diff --git a/alfa-client/apps/demo/src/app/app.component.html b/alfa-client/apps/demo/src/app/app.component.html index 9612d07c43e6d89c238b6821fdf7d79d6852fd41..c7bf2af5512205e4c72ba04fd946836817cb133f 100644 --- a/alfa-client/apps/demo/src/app/app.component.html +++ b/alfa-client/apps/demo/src/app/app.component.html @@ -25,7 +25,12 @@ </div> </form> <app-bescheid-dialog-button></app-bescheid-dialog-button> - <ozgdesign-testbtn /> + <div class="my-4 flex gap-4"> + <ods-button size="small" text="Button 1" /> + <ods-button size="medium" [isLoading]="true" text="Button 2" /> + <ods-button size="small" type="secondary" text="Button 3" /> + <ods-button size="medium" /> + </div> <div class="text-warning">Achtung</div> <div class="text-primary">Achtung</div> <hr class="mt-24" /> @@ -46,17 +51,21 @@ <hr /> <div class="flex flex-col gap-4 bg-background-200 p-6"> <div class="mt-4"> - <ods-button class="w-72" [isLoading]="false"> + <ods-button-card class="w-72" [isLoading]="false"> <ods-icon icon name="file-generate" class="size-10 fill-primary" /> <ods-spinner-icon spinner class="size-10" /> - <p text class="text-center">Bescheid-Dokument<br />automatisch erstellen</p></ods-button + <p text class="text-center"> + Bescheid-Dokument<br />automatisch erstellen + </p></ods-button-card > </div> <div class="mt-4"> - <ods-button class="w-72" [isLoading]="true"> + <ods-button-card class="w-72" [isLoading]="true"> <ods-icon icon name="file-generate" class="size-10 fill-primary" /> <ods-spinner-icon spinner class="size-10" /> - <p text class="text-center">Bescheid-Dokument<br />automatisch erstellen</p></ods-button + <p text class="text-center"> + Bescheid-Dokument<br />automatisch erstellen + </p></ods-button-card > </div> diff --git a/alfa-client/apps/demo/src/app/app.component.ts b/alfa-client/apps/demo/src/app/app.component.ts index 592b72d0e4cf98c82c8ee23a793773a96d582901..8eec08adac82d7f830261a5994f10ea581b1dd59 100644 --- a/alfa-client/apps/demo/src/app/app.component.ts +++ b/alfa-client/apps/demo/src/app/app.component.ts @@ -5,12 +5,12 @@ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { AttachmentComponent, - ButtonComponent, + ButtonCardComponent, FileUploadButtonComponent, IconComponent, RadioButtonCardComponent, SpinnerIconComponent, - TestbtnComponent, + ButtonComponent, } from 'design-system'; import { BescheidDialogExampleComponent } from './components/bescheid-dialog/bescheid-dialog.component'; @@ -23,8 +23,8 @@ import { CustomStepperComponent } from './components/cdk-demo/custom-stepper.com imports: [ CommonModule, AttachmentComponent, - TestbtnComponent, ButtonComponent, + ButtonCardComponent, FileUploadButtonComponent, RouterModule, CdkStepperModule, diff --git a/alfa-client/libs/design-system/.storybook/main.ts b/alfa-client/libs/design-system/.storybook/main.ts index c88e5024b36aae7024b8cfc963eeb02a55113914..732c0f91ddc5686866530ce9fea4f9276fe7c35c 100644 --- a/alfa-client/libs/design-system/.storybook/main.ts +++ b/alfa-client/libs/design-system/.storybook/main.ts @@ -1,15 +1,15 @@ -import type { StorybookConfig } from '@storybook/angular' +import type { StorybookConfig } from '@storybook/angular'; const config: StorybookConfig = { - stories: ['../**/*.stories.@(js|jsx|ts|tsx|mdx)'], - addons: ['@storybook/addon-essentials'], - framework: { - name: '@storybook/angular', - options: {} - } -} + stories: ['../**/*.stories.@(js|jsx|ts|tsx|mdx)'], + addons: ['@storybook/addon-essentials', 'storybook-tailwind-dark-mode'], + framework: { + name: '@storybook/angular', + options: {}, + }, +}; -export default config +export default config; // To customize your webpack configuration you can use the webpackFinal field. // Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config diff --git a/alfa-client/libs/design-system/.storybook/preview.ts b/alfa-client/libs/design-system/.storybook/preview.ts index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9070b74931d65e95328186047c022e8b5783458c 100644 --- a/alfa-client/libs/design-system/.storybook/preview.ts +++ b/alfa-client/libs/design-system/.storybook/preview.ts @@ -0,0 +1,8 @@ +import { Preview } from '@storybook/angular'; + +const preview: Preview = { + globalTypes: { + darkMode: { defaultValue: false }, + }, +}; +export default preview; diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts index 57870264b3e8f2853e5fa24cd9da2962e0207902..1529e30fa3c0258fbc64ef3a7dbed7f6fe3a3b18 100644 --- a/alfa-client/libs/design-system/src/index.ts +++ b/alfa-client/libs/design-system/src/index.ts @@ -1,4 +1,5 @@ export * from './lib/attachment/attachment.component'; +export * from './lib/form/button-card/button-card.component'; export * from './lib/button/button.component'; export * from './lib/form/file-upload-button/file-upload-button.component'; export * from './lib/form/radio-button-card/radio-button-card.component'; diff --git a/alfa-client/libs/design-system/src/lib/button/button.component.html b/alfa-client/libs/design-system/src/lib/button/button.component.html index 623e97f8ca245b2b9db3d62a2544037348cb9659..52f3f2125385f52d1c2b8eb712ecaac9dd826708 100644 --- a/alfa-client/libs/design-system/src/lib/button/button.component.html +++ b/alfa-client/libs/design-system/src/lib/button/button.component.html @@ -1,11 +1,10 @@ <button type="button" - class="flex flex-grow items-center justify-center gap-4 whitespace-nowrap rounded-md bg-background-50 py-3 pl-6 pr-6 text-text hover:bg-background-100 focus:outline-none focus:ring-2 focus:ring-primary" + [ngClass]="buttonVariants({ size, type })" [disabled]="isLoading" + (click)="clickEmitter.emit()" > <ng-content *ngIf="!isLoading" select="[icon]"></ng-content> - <ng-content *ngIf="isLoading" select="[spinner]"></ng-content> - <div class="flex-grow"> - <ng-content select="[text]"></ng-content> - </div> + <ods-spinner-icon *ngIf="isLoading" class="h-full"></ods-spinner-icon> + <div class="flex-grow" [innerHTML]="text | safe: 'html'"></div> </button> diff --git a/alfa-client/libs/design-system/src/lib/button/button.component.ts b/alfa-client/libs/design-system/src/lib/button/button.component.ts index 665e7008eb856db8e59baa6509efd3485779d199..477e76f9af2e2b9de384b588fb16026d00a6739f 100644 --- a/alfa-client/libs/design-system/src/lib/button/button.component.ts +++ b/alfa-client/libs/design-system/src/lib/button/button.component.ts @@ -1,14 +1,45 @@ import { CommonModule } from '@angular/common'; -import { Component, Input } from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { VariantProps, cva } from 'class-variance-authority'; + +import { SpinnerIconComponent } from '../icons/spinner-icon/spinner-icon.component'; +import { SafePipe } from '../utils/safe.pipe'; + +const buttonVariants = cva( + 'flex cursor-pointer items-center gap-4 rounded-md font-medium disabled:cursor-wait text-sm min-w-32', + { + variants: { + type: { + primary: 'hover:enabled:bg-primary-hover bg-primary text-white shadow-sm', + secondary: + 'border border-primary bg-background-50 text-primary hover:enabled:bg-background-100', + }, + size: { + small: 'h-9 py-1 px-2', + medium: 'h-12 py-2 px-4', + }, + }, + defaultVariants: { + type: 'primary', + size: 'medium', + }, + }, +); +type ButtonVariants = VariantProps<typeof buttonVariants>; @Component({ selector: 'ods-button', standalone: true, - imports: [CommonModule], - styles: [':host {@apply inline-flex}'], + imports: [CommonModule, SpinnerIconComponent, SafePipe], templateUrl: './button.component.html', }) export class ButtonComponent { @Input() text: string = ''; @Input() isLoading: boolean = false; + @Input() type: ButtonVariants['type'] = 'primary'; + @Input() size: ButtonVariants['size'] = 'small'; + + @Output() public clickEmitter: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>(); + + buttonVariants = buttonVariants; } diff --git a/alfa-client/libs/design-system/src/lib/button/button.stories.ts b/alfa-client/libs/design-system/src/lib/button/button.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..bd6947bf414762ec445a1fdb0916af89e0f53614 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/button/button.stories.ts @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from '@storybook/angular'; + +import { ButtonComponent } from './button.component'; + +const meta: Meta<ButtonComponent> = { + title: 'Button', + component: ButtonComponent, + excludeStories: /.*Data$/, + tags: ['autodocs'], +}; + +export default meta; +type Story = StoryObj<ButtonComponent>; + +export const Default: Story = { + args: { text: 'Hello world!', isLoading: false, type: 'primary', size: 'small' }, + argTypes: { + type: { + options: ['primary', 'secondary'], + control: { type: 'radio' }, + }, + size: { + options: ['small', 'medium'], + control: { type: 'radio' }, + }, + }, +}; diff --git a/alfa-client/libs/design-system/src/lib/form/button-card/button-card.component.html b/alfa-client/libs/design-system/src/lib/form/button-card/button-card.component.html new file mode 100644 index 0000000000000000000000000000000000000000..623e97f8ca245b2b9db3d62a2544037348cb9659 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/form/button-card/button-card.component.html @@ -0,0 +1,11 @@ +<button + type="button" + class="flex flex-grow items-center justify-center gap-4 whitespace-nowrap rounded-md bg-background-50 py-3 pl-6 pr-6 text-text hover:bg-background-100 focus:outline-none focus:ring-2 focus:ring-primary" + [disabled]="isLoading" +> + <ng-content *ngIf="!isLoading" select="[icon]"></ng-content> + <ng-content *ngIf="isLoading" select="[spinner]"></ng-content> + <div class="flex-grow"> + <ng-content select="[text]"></ng-content> + </div> +</button> diff --git a/alfa-client/libs/design-system/src/lib/form/button-card/button-card.component.spec.ts b/alfa-client/libs/design-system/src/lib/form/button-card/button-card.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ef4d4a2deaf6da23aee78c685bb80b3b93708f1 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/form/button-card/button-card.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ButtonCardComponent } from './button-card.component'; + +describe('ButtonCardComponent', () => { + let component: ButtonCardComponent; + let fixture: ComponentFixture<ButtonCardComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ButtonCardComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(ButtonCardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/design-system/src/lib/form/button-card/button-card.component.ts b/alfa-client/libs/design-system/src/lib/form/button-card/button-card.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a3e40783947b21d050886008c2e165e7d321573 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/form/button-card/button-card.component.ts @@ -0,0 +1,14 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'ods-button-card', + standalone: true, + imports: [CommonModule], + styles: [':host {@apply inline-flex}'], + templateUrl: './button-card.component.html', +}) +export class ButtonCardComponent { + @Input() text: string = ''; + @Input() isLoading: boolean = false; +} diff --git a/alfa-client/libs/design-system/src/lib/icons/spinner-icon/spinner-icon.component.html b/alfa-client/libs/design-system/src/lib/icons/spinner-icon/spinner-icon.component.html index 07c3aaa36bbd86558c3bd789227ffa0162884471..4d2735bd1d4a4036077730bb7507586bea872c30 100644 --- a/alfa-client/libs/design-system/src/lib/icons/spinner-icon/spinner-icon.component.html +++ b/alfa-client/libs/design-system/src/lib/icons/spinner-icon/spinner-icon.component.html @@ -1,6 +1,6 @@ <svg aria-hidden="true" - class="inline size-full animate-spin text-gray-200 dark:text-gray-600" + class="size-full animate-spin text-gray-200 dark:text-gray-600" viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg" @@ -11,6 +11,6 @@ /> <path d="M93.968 39.04c2.425-.636 3.894-3.128 3.04-5.486A50 50 0 0 0 41.735 1.279c-2.474.414-3.922 2.919-3.285 5.344.637 2.426 3.12 3.849 5.6 3.484a40.916 40.916 0 0 1 44.131 25.769c.902 2.34 3.361 3.802 5.787 3.165Z" - fill="#1C64F2" + class="fill-primary" /> </svg> diff --git a/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css b/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css index 3954976c5bf8c792419d978d5a08ac789ad71e95..aa3bd10e0bc3c2ed98727fe26937b5d86a421e7c 100644 --- a/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css +++ b/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css @@ -13,6 +13,7 @@ --color-text-white: 0 0% 100%; --color-primary-600: 212 80% 42%; + --color-primary-600-hover: 212, 80%, 42%, 0.9; --color-background-50: 0 0% 100%; --color-background-100: 0 0% 98%; --color-background-200: 0 0% 90%; @@ -33,6 +34,7 @@ --color-text-white: 0 0% 0%; --color-primary-600: 43 96% 58%; + --color-primary-600-hover: 43, 96%, 58%, 0.9; --color-background-50: 0 0% 0%; --color-background-100: 0 0% 8%; --color-background-200: 0 0% 16%; diff --git a/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js b/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js index 12d6bbb46180572a187eed87845d44aacd166810..3ce809432151b56b1af1d4d2ae2f1a6b524cff29 100644 --- a/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js +++ b/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js @@ -79,6 +79,10 @@ module.exports = { 600: 'hsl(var(--color-primary-600) / <alpha-value>)', DEFAULT: 'hsl(var(--color-primary-600) / <alpha-value>)', }, + 'primary-hover': { + 600: 'hsla(var(--color-primary-600-hover))', + DEFAULT: 'hsla(var(--color-primary-600-hover))', + }, text: 'hsl(var(--text) / <alpha-value>)', whitetext: 'hsl(var(--color-text-white) / <alpha-value>)', warning: 'hsl(var(--warning))', diff --git a/alfa-client/libs/design-system/src/lib/testbtn/testbtn.stories.ts b/alfa-client/libs/design-system/src/lib/testbtn/testbtn.stories.ts index 3e9c2ebdeeab914bb1779a412702a11ccacdbdc1..effd01811bbb02c27ea569c992b0ea37aff8d51a 100644 --- a/alfa-client/libs/design-system/src/lib/testbtn/testbtn.stories.ts +++ b/alfa-client/libs/design-system/src/lib/testbtn/testbtn.stories.ts @@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/angular'; import { TestbtnComponent } from './testbtn.component'; const meta: Meta<TestbtnComponent> = { - title: 'Button', + title: 'Test button', component: TestbtnComponent, excludeStories: /.*Data$/, tags: ['autodocs'], diff --git a/alfa-client/libs/design-system/src/lib/utils/safe.pipe.ts b/alfa-client/libs/design-system/src/lib/utils/safe.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..d0d857f6925a22564c00e3442e34d2b042ef7a3e --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/utils/safe.pipe.ts @@ -0,0 +1,37 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { + DomSanitizer, + SafeHtml, + SafeResourceUrl, + SafeScript, + SafeStyle, + SafeUrl, +} from '@angular/platform-browser'; + +@Pipe({ + name: 'safe', + standalone: true, +}) +export class SafePipe implements PipeTransform { + constructor(protected sanitizer: DomSanitizer) {} + + public transform( + value: string, + type: string, + ): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl { + switch (type) { + case 'html': + return this.sanitizer.bypassSecurityTrustHtml(value); + case 'style': + return this.sanitizer.bypassSecurityTrustStyle(value); + case 'script': + return this.sanitizer.bypassSecurityTrustScript(value); + case 'url': + return this.sanitizer.bypassSecurityTrustUrl(value); + case 'resourceUrl': + return this.sanitizer.bypassSecurityTrustResourceUrl(value); + default: + throw new Error(`Invalid safe type specified: ${type}`); + } + } +} diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen.component.html index 0755d974036beed033db585e4fd65985ee013ce9..30c6c4eef92fc4a3de7e72253614ff141d8485a3 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen.component.html +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen.component.html @@ -1,6 +1,6 @@ <ng-container *ngIf="bescheidDraftStateResource.resource as bescheidDraft"> <div class="mt-4"> - <ods-button + <ods-button-card *ngIf="bescheidDraft | hasLink: bescheidLinkRel.CREATE_DOCUMENT" class="w-72" [isLoading]="(createBescheidDocumentInProgress$ | async).loading" @@ -9,7 +9,9 @@ > <ods-bescheid-generate-icon icon /> <ods-spinner-icon spinner class="size-10" /> - <div text class="text-center">Bescheid-Dokument<br />automatisch erstellen</div></ods-button + <div text class="text-center"> + Bescheid-Dokument<br />automatisch erstellen + </div></ods-button-card > </div> </ng-container> diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen.component.spec.ts index 79731c5661bc0d85b66cb78fd6eaabdfa2c6f839..a92b3b4315ec5c5bfd26bda915d2a41a8c1e7838 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen.component.spec.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen/vorgang-detail-bescheiden-bescheid-automatisch-erstellen.component.spec.ts @@ -11,7 +11,7 @@ import { OzgcloudButtonWithSpinnerComponent } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { BescheidGenerateIconComponent, - ButtonComponent, + ButtonCardComponent, IconComponent, SpinnerIconComponent, } from 'design-system'; @@ -34,7 +34,7 @@ describe('VorgangDetailBescheidenBescheidAutomatischErstellenComponent', () => { declarations: [ VorgangDetailBescheidenBescheidAutomatischErstellenComponent, MockComponent(OzgcloudButtonWithSpinnerComponent), - MockComponent(ButtonComponent), + MockComponent(ButtonCardComponent), MockComponent(IconComponent), MockComponent(SpinnerIconComponent), MockComponent(BescheidGenerateIconComponent), diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts index e766aa38002e0187f7f03fda8841d6fc603dda4e..79542b25a49906c7b53a490262d0ab19082c0902 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts @@ -44,7 +44,7 @@ import { AttachmentComponent, BescheidGenerateIconComponent, BescheidUploadIconComponent, - ButtonComponent, + ButtonCardComponent, IconComponent, RadioButtonCardComponent, SpinnerIconComponent, @@ -129,7 +129,7 @@ const routes: Routes = [ LoeschAnforderungSharedModule, BescheidModule, RadioButtonCardComponent, - ButtonComponent, + ButtonCardComponent, IconComponent, SpinnerIconComponent, BescheidUploadIconComponent, diff --git a/alfa-client/package-lock.json b/alfa-client/package-lock.json index 5c059d655653f1a592af5be0ed5b1e3e30ba6254..5953f296825187f4124aae284daae382da6c24eb 100644 --- a/alfa-client/package-lock.json +++ b/alfa-client/package-lock.json @@ -31,6 +31,7 @@ "@nx/angular": "17.0.2", "angular-oauth2-oidc": "15.0.1", "angular-oauth2-oidc-jwks": "15.0.1", + "class-variance-authority": "^0.7.0", "date-fns": "^2.29.3", "file-saver": "2.0.5", "include-media": "^1.4.10", @@ -115,6 +116,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "sonarqube-scanner": "3.1.0", + "storybook-tailwind-dark-mode": "^1.0.22", "tailwindcss": "^3.4.1", "ts-jest": "^29.1.0", "ts-node": "10.9.1", @@ -13939,6 +13941,186 @@ "url": "https://opencollective.com/storybook" } }, + "node_modules/@storybook/addons": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/addons/-/addons-7.6.17.tgz", + "integrity": "sha512-Ok18Y698Ccyg++MoUNJNHY0cXUvo8ETFIRLJk1g9ElJ70j6kPgNnzW2pAtZkBNmswHtofZ7pT156cj96k/LgfA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/manager-api": "7.6.17", + "@storybook/preview-api": "7.6.17", + "@storybook/types": "7.6.17" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addons/node_modules/@storybook/channels": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/channels/-/channels-7.6.17.tgz", + "integrity": "sha512-GFG40pzaSxk1hUr/J/TMqW5AFDDPUSu+HkeE/oqSWJbOodBOLJzHN6CReJS6y1DjYSZLNFt1jftPWZZInG/XUA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/client-logger": "7.6.17", + "@storybook/core-events": "7.6.17", + "@storybook/global": "^5.0.0", + "qs": "^6.10.0", + "telejson": "^7.2.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addons/node_modules/@storybook/client-logger": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/client-logger/-/client-logger-7.6.17.tgz", + "integrity": "sha512-6WBYqixAXNAXlSaBWwgljWpAu10tPRBJrcFvx2gPUne58EeMM20Gi/iHYBz2kMCY+JLAgeIH7ZxInqwO8vDwiQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addons/node_modules/@storybook/core-events": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/core-events/-/core-events-7.6.17.tgz", + "integrity": "sha512-AriWMCm/k1cxlv10f+jZ1wavThTRpLaN3kY019kHWbYT9XgaSuLU67G7GPr3cGnJ6HuA6uhbzu8qtqVCd6OfXA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addons/node_modules/@storybook/manager-api": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/manager-api/-/manager-api-7.6.17.tgz", + "integrity": "sha512-IJIV1Yc6yw1dhCY4tReHCfBnUKDqEBnMyHp3mbXpsaHxnxJZrXO45WjRAZIKlQKhl/Ge1CrnznmHRCmYgqmrWg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/channels": "7.6.17", + "@storybook/client-logger": "7.6.17", + "@storybook/core-events": "7.6.17", + "@storybook/csf": "^0.1.2", + "@storybook/global": "^5.0.0", + "@storybook/router": "7.6.17", + "@storybook/theming": "7.6.17", + "@storybook/types": "7.6.17", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "store2": "^2.14.2", + "telejson": "^7.2.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addons/node_modules/@storybook/preview-api": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/preview-api/-/preview-api-7.6.17.tgz", + "integrity": "sha512-wLfDdI9RWo1f2zzFe54yRhg+2YWyxLZvqdZnSQ45mTs4/7xXV5Wfbv3QNTtcdw8tT3U5KRTrN1mTfTCiRJc0Kw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/channels": "7.6.17", + "@storybook/client-logger": "7.6.17", + "@storybook/core-events": "7.6.17", + "@storybook/csf": "^0.1.2", + "@storybook/global": "^5.0.0", + "@storybook/types": "7.6.17", + "@types/qs": "^6.9.5", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "synchronous-promise": "^2.0.15", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addons/node_modules/@storybook/router": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/router/-/router-7.6.17.tgz", + "integrity": "sha512-GnyC0j6Wi5hT4qRhSyT8NPtJfGmf82uZw97LQRWeyYu5gWEshUdM7aj40XlNiScd5cZDp0owO1idduVF2k2l2A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/client-logger": "7.6.17", + "memoizerific": "^1.11.3", + "qs": "^6.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addons/node_modules/@storybook/theming": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/theming/-/theming-7.6.17.tgz", + "integrity": "sha512-ZbaBt3KAbmBtfjNqgMY7wPMBshhSJlhodyMNQypv+95xLD/R+Az6aBYbpVAOygLaUQaQk4ar7H/Ww6lFIoiFbA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@storybook/client-logger": "7.6.17", + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/addons/node_modules/@storybook/types": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/types/-/types-7.6.17.tgz", + "integrity": "sha512-GRY0xEJQ0PrL7DY2qCNUdIfUOE0Gsue6N+GBJw9ku1IUDFLJRDOF+4Dx2BvYcVCPI5XPqdWKlEyZdMdKjiQN7Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/channels": "7.6.17", + "@types/babel__core": "^7.0.0", + "@types/express": "^4.7.0", + "file-system-cache": "2.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, "node_modules/@storybook/angular": { "version": "7.6.14", "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/angular/-/angular-7.6.14.tgz", @@ -14169,6 +14351,157 @@ "node": ">=10.13.0" } }, + "node_modules/@storybook/api": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/api/-/api-7.6.17.tgz", + "integrity": "sha512-l92PI+5XL4zB/o4IBWFCKQWTXvPg9hR45DCJqlPHrLZStiR6Xj1mbrtOjUlgIOH+nYb/SZFZqO53hhrs7X4Nvg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/client-logger": "7.6.17", + "@storybook/manager-api": "7.6.17" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/api/node_modules/@storybook/channels": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/channels/-/channels-7.6.17.tgz", + "integrity": "sha512-GFG40pzaSxk1hUr/J/TMqW5AFDDPUSu+HkeE/oqSWJbOodBOLJzHN6CReJS6y1DjYSZLNFt1jftPWZZInG/XUA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/client-logger": "7.6.17", + "@storybook/core-events": "7.6.17", + "@storybook/global": "^5.0.0", + "qs": "^6.10.0", + "telejson": "^7.2.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/api/node_modules/@storybook/client-logger": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/client-logger/-/client-logger-7.6.17.tgz", + "integrity": "sha512-6WBYqixAXNAXlSaBWwgljWpAu10tPRBJrcFvx2gPUne58EeMM20Gi/iHYBz2kMCY+JLAgeIH7ZxInqwO8vDwiQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/api/node_modules/@storybook/core-events": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/core-events/-/core-events-7.6.17.tgz", + "integrity": "sha512-AriWMCm/k1cxlv10f+jZ1wavThTRpLaN3kY019kHWbYT9XgaSuLU67G7GPr3cGnJ6HuA6uhbzu8qtqVCd6OfXA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/api/node_modules/@storybook/manager-api": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/manager-api/-/manager-api-7.6.17.tgz", + "integrity": "sha512-IJIV1Yc6yw1dhCY4tReHCfBnUKDqEBnMyHp3mbXpsaHxnxJZrXO45WjRAZIKlQKhl/Ge1CrnznmHRCmYgqmrWg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/channels": "7.6.17", + "@storybook/client-logger": "7.6.17", + "@storybook/core-events": "7.6.17", + "@storybook/csf": "^0.1.2", + "@storybook/global": "^5.0.0", + "@storybook/router": "7.6.17", + "@storybook/theming": "7.6.17", + "@storybook/types": "7.6.17", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "store2": "^2.14.2", + "telejson": "^7.2.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/api/node_modules/@storybook/router": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/router/-/router-7.6.17.tgz", + "integrity": "sha512-GnyC0j6Wi5hT4qRhSyT8NPtJfGmf82uZw97LQRWeyYu5gWEshUdM7aj40XlNiScd5cZDp0owO1idduVF2k2l2A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/client-logger": "7.6.17", + "memoizerific": "^1.11.3", + "qs": "^6.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/api/node_modules/@storybook/theming": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/theming/-/theming-7.6.17.tgz", + "integrity": "sha512-ZbaBt3KAbmBtfjNqgMY7wPMBshhSJlhodyMNQypv+95xLD/R+Az6aBYbpVAOygLaUQaQk4ar7H/Ww6lFIoiFbA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@storybook/client-logger": "7.6.17", + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/api/node_modules/@storybook/types": { + "version": "7.6.17", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/types/-/types-7.6.17.tgz", + "integrity": "sha512-GRY0xEJQ0PrL7DY2qCNUdIfUOE0Gsue6N+GBJw9ku1IUDFLJRDOF+4Dx2BvYcVCPI5XPqdWKlEyZdMdKjiQN7Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/channels": "7.6.17", + "@types/babel__core": "^7.0.0", + "@types/express": "^4.7.0", + "file-system-cache": "2.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, "node_modules/@storybook/blocks": { "version": "7.6.14", "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/blocks/-/blocks-7.6.14.tgz", @@ -20029,6 +20362,18 @@ "node": ">=0.10.0" } }, + "node_modules/class-variance-authority": { + "version": "0.7.0", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/class-variance-authority/-/class-variance-authority-0.7.0.tgz", + "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "2.0.0" + }, + "funding": { + "url": "https://joebell.co.uk" + } + }, "node_modules/clean-css": { "version": "5.3.3", "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/clean-css/-/clean-css-5.3.3.tgz", @@ -20165,6 +20510,15 @@ "node": ">=6" } }, + "node_modules/clsx": { + "version": "2.0.0", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/co/-/co-4.6.0.tgz", @@ -38732,6 +39086,30 @@ "dev": true, "license": "(MIT OR GPL-3.0)" }, + "node_modules/storybook-tailwind-dark-mode": { + "version": "1.0.22", + "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/storybook-tailwind-dark-mode/-/storybook-tailwind-dark-mode-1.0.22.tgz", + "integrity": "sha512-I0HSVCuvo3OkaGDnCjLM7V1OYmQccrUCAGZ5ZaJfl9s3e93WA6DKFpQRbuoSidci+PTy+KvgrINgE08rA16bWA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@storybook/addons": "^7.0.0", + "@storybook/api": "^7.0.0", + "@storybook/components": "^7.0.0", + "@storybook/core-events": "^7.0.0", + "@storybook/theming": "^7.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/stream-browserify": { "version": "2.0.2", "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/stream-browserify/-/stream-browserify-2.0.2.tgz", diff --git a/alfa-client/package.json b/alfa-client/package.json index 52bb29c797684d3a4ee71c931e3b0fe82626761b..fd31984dcca52afbf4eec772d193bfda2b1a2d74 100644 --- a/alfa-client/package.json +++ b/alfa-client/package.json @@ -68,6 +68,7 @@ "@nx/angular": "17.0.2", "angular-oauth2-oidc": "15.0.1", "angular-oauth2-oidc-jwks": "15.0.1", + "class-variance-authority": "^0.7.0", "date-fns": "^2.29.3", "file-saver": "2.0.5", "include-media": "^1.4.10", @@ -152,6 +153,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "sonarqube-scanner": "3.1.0", + "storybook-tailwind-dark-mode": "^1.0.22", "tailwindcss": "^3.4.1", "ts-jest": "^29.1.0", "ts-node": "10.9.1",