feature(ui-library): Added own library of UI components to replace digi-ng. Skeleton is first component moved (TV-850)

Squashed commit of the following:

commit d76e32cd99e2e823142f4410e66c66df5e096041
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Thu Oct 28 10:28:02 2021 +0200

    Move styles to own library

commit 85f0a5788ebdd7309499b1b623f4ac1046f45811
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Thu Oct 28 10:09:23 2021 +0200

    double quotes in html

commit eeb600cd631e3478c136795a8109e8927546b14b
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Oct 27 16:42:48 2021 +0200

    UI library with copy of digi-ng's skeleton

commit 11a24c0eef173e6b2f087eca5e96063036e6394b
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Oct 27 16:06:43 2021 +0200

    Update .eslintrc.json

commit 3c4b2e4823dbd8e9ca8dd332966bd10ac0fc098f
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Oct 27 15:08:32 2021 +0200

    add nx library
This commit is contained in:
Daniel Appelgren
2021-10-28 10:34:28 +02:00
parent a0f61c796d
commit d3c61a4c56
89 changed files with 2229 additions and 1574 deletions

21
libs/ui/.eslintrc.json Normal file
View File

@@ -0,0 +1,21 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts"],
"extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{ "type": "attribute", "prefix": "mina-sidor-fa-web", "style": "camelCase" }
],
"@angular-eslint/component-selector": [
"error",
{ "type": "element", "prefix": "mina-sidor-fa-web", "style": "kebab-case" }
]
}
},
{ "files": ["*.html"], "extends": ["plugin:@nrwl/nx/angular-template"], "rules": {} }
]
}

7
libs/ui/README.md Normal file
View File

@@ -0,0 +1,7 @@
# ui
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test ui` to execute the unit tests.

23
libs/ui/jest.config.js Normal file
View File

@@ -0,0 +1,23 @@
module.exports = {
displayName: 'ui',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {
'ts-jest': {
tsConfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
astTransformers: {
before: [
'jest-preset-angular/build/InlineFilesTransformer',
'jest-preset-angular/build/StripStylesTransformer',
],
},
},
},
coverageDirectory: '../../coverage/libs/ui',
snapshotSerializers: [
'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js',
'jest-preset-angular/build/AngularSnapshotSerializer.js',
'jest-preset-angular/build/HTMLCommentSerializer.js',
],
};

View File

@@ -0,0 +1,6 @@
export enum UiLoaderType {
FULL_SCREEN = 'fullscreen',
FULL_BLANK_SCREEN = 'full-blank-screen',
ABSOLUTE = 'absolute',
PADDED = 'padded',
}

View File

@@ -0,0 +1,4 @@
<div [ngClass]="loaderClass">
asdf
<digi-icon-spinner [ngClass]="spinnerClass"></digi-icon-spinner>
</div>

View File

@@ -0,0 +1,40 @@
@import 'mixins/backdrop';
@import 'variables/gutters';
@import 'variables/z-index';
@keyframes spinning {
to {
transform: rotate(360deg);
}
}
.ui-loader {
display: flex;
align-items: center;
justify-content: center;
&--padded {
padding: $digi--layout--gutter--l;
}
&--absolute {
@include msfa__backdrop($msfa__z-index-backdrop, false);
}
&--full-screen {
@include msfa__backdrop($msfa__z-index-backdrop);
}
&--full-blank-screen {
@include msfa__backdrop($msfa__z-index-backdrop, true, true);
}
&__spinner {
display: inline-flex;
animation: spinning 1s linear infinite;
&--s {
width: 2.5rem;
}
}
}

View File

@@ -0,0 +1,26 @@
/* tslint:disable:no-unused-variable */
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LoaderComponent } from './loader.component';
describe('LoaderComponent', () => {
let component: LoaderComponent;
let fixture: ComponentFixture<LoaderComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [LoaderComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LoaderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,15 @@
import { LoaderComponent } from './loader.component';
import { UiLoaderModule } from './loader.module';
export default { title: 'Loader', component: LoaderComponent };
const componentModule = {
moduleMetadata: {
imports: [UiLoaderModule],
},
};
export const standard = () => ({
...componentModule,
template: '<ui-loader></ui-loader>',
});

View File

@@ -0,0 +1,25 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { UiLoaderType } from './loader-type.enum';
@Component({
selector: 'ui-loader',
templateUrl: './loader.component.html',
styleUrls: ['./loader.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LoaderComponent {
private readonly _defaultClass = 'ui-loader';
@Input() uiType: UiLoaderType = UiLoaderType.PADDED;
@Input() uiSize: 's' | 'm' = 'm';
get loaderClass(): string {
if (this.uiType) {
return `${this._defaultClass} ${this._defaultClass}--${this.uiType as string}`;
}
return this._defaultClass;
}
get spinnerClass(): string {
return `${this._defaultClass}__spinner ${this._defaultClass}__spinner--${this.uiSize}`;
}
}

View File

@@ -0,0 +1,11 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { LoaderComponent } from './loader.component';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [LoaderComponent],
imports: [CommonModule],
exports: [LoaderComponent],
})
export class UiLoaderModule {}

View File

@@ -0,0 +1,11 @@
<div class="ui-skeleton" data-digi-ng-component>
<div *ngIf="uiText" class="ui-skeleton__top"></div>
<p *ngIf="uiText" class="ui-skeleton__text">{{ uiText }}</p>
<div class="ui-skeleton__header"></div>
<div *ngFor="let stub of stubs" class="ui-skeleton__lines">
<div class="ui-skeleton__line"></div>
<div class="ui-skeleton__line"></div>
<div class="ui-skeleton__line"></div>
<div class="ui-skeleton__line ui-skeleton__line--last"></div>
</div>
</div>

View File

@@ -0,0 +1,91 @@
@import 'variables/gutters';
@import 'variables/breakpoints';
$typography__margin--text: u(6);
$animation__duration--sweep: 4s;
$ui__color--gray-10: #f5f5f5;
$ui__color--gray-20: #efefef;
$ui__color--gray-30: #d1d1d1;
$ui__color--skeleton-text: linear-gradient(
to left,
$ui__color--gray-20,
$ui__color--gray-20 40%,
$ui__color--gray-10 50%,
$ui__color--gray-20 60%,
$ui__color--gray-20
);
$ui__color--skeleton-head: linear-gradient(
to left,
$ui__color--gray-30,
$ui__color--gray-30 40%,
$ui__color--gray-20 50%,
$ui__color--gray-30 60%,
$ui__color--gray-30
);
$skeleton__top--height: 2.5rem;
$skeleton__top--height-desktop: 4.5rem;
$skeleton__header--height: 1rem + 0.46875rem;
$skeleton__header--height-desktop: 2rem + 0.3125rem;
:host {
.ui-skeleton__top {
animation: ui-skeleton__animation $animation__duration--sweep infinite;
height: $skeleton__top--height;
background: $ui__color--skeleton-text;
background-size: 400%;
width: 25%;
margin-bottom: var(--digi--layout--gutter--m);
@media (min-width: $digi--layout--breakpoint--l) {
height: $skeleton__top--height-desktop;
width: 20%;
margin-bottom: $digi--layout--gutter--l;
}
}
.ui-skeleton__header {
animation: ui-skeleton__animation $animation__duration--sweep infinite;
background: $ui__color--skeleton-head;
background-size: 400%;
width: 33%;
height: $skeleton__header--height;
margin-bottom: var(----digi--layout--gutter--s);
@media (min-width: $digi--layout--breakpoint--l) {
height: $skeleton__header--height-desktop;
margin-bottom: $digi--layout--gutter--l;
width: 90%;
}
}
.ui-skeleton__line {
animation: ui-skeleton__animation $animation__duration--sweep 0.5s infinite;
background: $ui__color--skeleton-text;
background-size: 400%;
margin-bottom: var(--digi--layout--gutter--xs);
height: var(--digi--typography--font-size);
}
.ui-skeleton__line--last {
width: 75%;
margin-bottom: var(--digi--layout--gutter);
}
.ui-skeleton__text {
font-weight: var(--digi--typography--font-weight--semibold);
margin-bottom: $typography__margin--text / 2;
}
}
@keyframes ui-skeleton__animation {
0% {
background-position-x: 100%;
}
100% {
background-position-x: 0%;
}
}

View File

@@ -0,0 +1,40 @@
import { SkeletonComponent } from './skeleton.component';
import { UiSkeletonModule } from './skeleton.module';
export default { title: 'Skeleton', component: SkeletonComponent };
const componentModule = {
moduleMetadata: {
imports: [UiSkeletonModule],
},
};
export const standard = () => ({
...componentModule,
template: '<ui-skeleton></ui-skeleton>',
});
export const limitedMultiLine = () => ({
...componentModule,
template: '<ui-skeleton [uiCount]="2"></ui-skeleton>',
});
export const extensiveMultiLine = () => ({
...componentModule,
template: '<ui-skeleton [uiCount]="5"></ui-skeleton>',
});
export const paragraphless = () => ({
...componentModule,
template: '<ui-skeleton [uiCount]="0"></ui-skeleton>',
});
export const customText = () => ({
...componentModule,
template: '<ui-skeleton uiText="I am a custom text..."></ui-skeleton>',
});
export const noText = () => ({
...componentModule,
template: '<ui-skeleton uiText=""></ui-skeleton>',
});

View File

@@ -0,0 +1,25 @@
import { Component, Input } from '@angular/core';
/**
* Placeholder for content being loaded
*
* ##Usage
* ``import {SkeletonModule} from '@ui/skeleton';``
*/
@Component({
selector: 'ui-skeleton',
templateUrl: './skeleton.component.html',
styleUrls: ['./skeleton.component.scss'],
})
export class SkeletonComponent {
/**
* The amount of skeleton sections
*/
@Input() uiCount: number | undefined;
@Input() uiText = 'Laddar sidan';
get stubs(): string[] {
return Array(this.uiCount);
}
}

View File

@@ -0,0 +1,10 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { SkeletonComponent } from './skeleton.component';
@NgModule({
imports: [CommonModule],
declarations: [SkeletonComponent],
exports: [SkeletonComponent],
})
export class UiSkeletonModule {}

13
libs/ui/tsconfig.json Normal file
View File

@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

19
libs/ui/tsconfig.lib.json Normal file
View File

@@ -0,0 +1,19 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"target": "es2015",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": [],
"lib": ["dom", "es2018"]
},
"angularCompilerOptions": {
"skipTemplateCodegen": true,
"strictMetadataEmit": true,
"enableResourceInlining": true
},
"exclude": ["src/test-setup.ts", "**/*.spec.ts"],
"include": ["**/*.ts"]
}

View File

@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"files": ["src/test-setup.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts"]
}