From 392f16ca6a2556d8d7b4e8b1031f185b808d0224 Mon Sep 17 00:00:00 2001
From: Alexander Reifschneider <alexander.reifschneider@mgm-tp.com>
Date: Tue, 1 Apr 2025 14:34:14 +0200
Subject: [PATCH] OZG-7707 Add icons showcase to demo app

---
 alfa-client/apps/demo/project.json            | 29 ++++----
 .../apps/demo/src/app/app.component.html      | 14 +++-
 .../apps/demo/src/app/app.component.ts        |  2 +
 alfa-client/apps/demo/src/app/app.config.ts   | 11 +++-
 .../src/assets/accessibility.svg              |  9 +++
 .../src/assets/account-circle.svg             |  4 ++
 alfa-client/libs/design-system/src/index.ts   |  1 +
 .../src/lib/icon/icon.component.spec.ts       | 44 +++++++++++++
 .../src/lib/icon/icon.component.ts            | 66 +++++++++++++++++++
 .../src/lib/icon/icon.stories.ts              | 45 +++++++++++++
 alfa-client/package.json                      |  1 +
 alfa-client/pnpm-lock.yaml                    | 17 +++++
 12 files changed, 221 insertions(+), 22 deletions(-)
 create mode 100644 alfa-client/libs/design-system/src/assets/accessibility.svg
 create mode 100644 alfa-client/libs/design-system/src/assets/account-circle.svg
 create mode 100644 alfa-client/libs/design-system/src/lib/icon/icon.component.spec.ts
 create mode 100644 alfa-client/libs/design-system/src/lib/icon/icon.component.ts
 create mode 100644 alfa-client/libs/design-system/src/lib/icon/icon.stories.ts

diff --git a/alfa-client/apps/demo/project.json b/alfa-client/apps/demo/project.json
index e0876536a2..33b6d437bf 100644
--- a/alfa-client/apps/demo/project.json
+++ b/alfa-client/apps/demo/project.json
@@ -8,24 +8,23 @@
   "targets": {
     "build": {
       "executor": "@angular-devkit/build-angular:browser",
-      "outputs": [
-        "{options.outputPath}"
-      ],
+      "outputs": ["{options.outputPath}"],
       "options": {
         "outputPath": "dist/apps/demo",
         "index": "apps/demo/src/index.html",
         "main": "apps/demo/src/main.ts",
-        "polyfills": [
-          "zone.js"
-        ],
+        "polyfills": ["zone.js"],
         "tsConfig": "apps/demo/tsconfig.app.json",
         "assets": [
           "apps/demo/src/favicon.ico",
-          "apps/demo/src/assets"
-        ],
-        "styles": [
-          "apps/demo/src/styles.scss"
+          "apps/demo/src/assets",
+          {
+            "input": "libs/design-system/src/assets",
+            "glob": "**/*",
+            "output": "assets/icons"
+          }
         ],
+        "styles": ["apps/demo/src/styles.scss"],
         "scripts": []
       },
       "configurations": {
@@ -75,15 +74,11 @@
     },
     "lint": {
       "executor": "@nx/eslint:lint",
-      "outputs": [
-        "{options.outputFile}"
-      ]
+      "outputs": ["{options.outputFile}"]
     },
     "test": {
       "executor": "@nx/jest:jest",
-      "outputs": [
-        "{workspaceRoot}/coverage/{projectRoot}"
-      ],
+      "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
       "options": {
         "jestConfig": "apps/demo/jest.config.ts"
       }
@@ -95,4 +90,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/alfa-client/apps/demo/src/app/app.component.html b/alfa-client/apps/demo/src/app/app.component.html
index 22a2f09c8b..9dce1e1daf 100644
--- a/alfa-client/apps/demo/src/app/app.component.html
+++ b/alfa-client/apps/demo/src/app/app.component.html
@@ -57,6 +57,14 @@
       </div>
 
       <div class="my-12">
+        <h2 class="heading-2">Icons</h2>
+        <div class="mb-6 flex">
+          <ods-icon name="account-circle" size="xxl" />
+          <ods-icon name="accessibility" size="extra-large" color="text" />
+          <ods-icon name="accessibility" size="large" color="error" />
+          <ods-icon name="accessibility" class="fill-red-500" />
+          <ods-icon name="accessibility" size="small" />
+        </div>
         <h1 class="mb-6 text-2xl font-semibold text-text">Auswertungen</h1>
         <ods-button text="Auswertung hinzufügen" />
         <ul class="mt-6 divide-y divide-gray-300 rounded-md bg-background-50 text-text shadow-sm ring-1 ring-gray-300">
@@ -582,21 +590,21 @@
         </div>
 
         <div class="mt-4">
-          <ods-file-upload-button class="w-72" [isLoading]="false" id="upload117">
+          <ods-file-upload-button class="w-72" [isLoading]="false" id="upload117" dataTestId="demo-upload-1">
             <ods-bescheid-upload-icon icon />
             <ods-spinner-icon spinner size="extra-large" />
             <p text class="text-center">Bescheiddokument<br />hochladen</p></ods-file-upload-button
           >
         </div>
         <div class="mt-4">
-          <ods-file-upload-button class="w-72" [isLoading]="true" id="upload117">
+          <ods-file-upload-button class="w-72" [isLoading]="true" id="upload117" dataTestId="demo-upload-2">
             <ods-bescheid-upload-icon icon />
             <ods-spinner-icon spinner size="extra-large" />
             <p text class="text-center">Bescheiddokument<br />hochladen</p></ods-file-upload-button
           >
         </div>
         <div class="mt-4">
-          <ods-file-upload-button class="w-72" [isLoading]="true" id="upload130">
+          <ods-file-upload-button class="w-72" [isLoading]="true" id="upload130" dataTestId="demo-upload-3">
             <ods-attachment-icon icon />
             <ods-spinner-icon spinner size="medium" />
             <div text class="text-center">Anhang hochladen</div></ods-file-upload-button
diff --git a/alfa-client/apps/demo/src/app/app.component.ts b/alfa-client/apps/demo/src/app/app.component.ts
index 044bdfb401..1e18d64a6b 100644
--- a/alfa-client/apps/demo/src/app/app.component.ts
+++ b/alfa-client/apps/demo/src/app/app.component.ts
@@ -39,6 +39,7 @@ import {
   ErrorMessageComponent,
   FieldsetComponent,
   FileUploadButtonComponent,
+  IconComponent,
   InstantSearchComponent,
   RadioButtonCardComponent,
   SaveIconComponent,
@@ -90,6 +91,7 @@ import { CustomStepperComponent } from './components/cdk-demo/custom-stepper.com
     TextareaComponent,
     ErrorMessageComponent,
     TooltipDirective,
+    IconComponent,
   ],
   selector: 'app-root',
   templateUrl: './app.component.html',
diff --git a/alfa-client/apps/demo/src/app/app.config.ts b/alfa-client/apps/demo/src/app/app.config.ts
index 9c33c34037..a0ecda43e8 100644
--- a/alfa-client/apps/demo/src/app/app.config.ts
+++ b/alfa-client/apps/demo/src/app/app.config.ts
@@ -21,10 +21,17 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { ApplicationConfig } from '@angular/core';
+import { provideHttpClient } from '@angular/common/http';
+import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
 import { provideRouter, withEnabledBlockingInitialNavigation } from '@angular/router';
+import { provideAngularSvgIcon } from 'angular-svg-icon';
 import { appRoutes } from './app.routes';
 
 export const appConfig: ApplicationConfig = {
-  providers: [provideRouter(appRoutes, withEnabledBlockingInitialNavigation())],
+  providers: [
+    provideRouter(appRoutes, withEnabledBlockingInitialNavigation()),
+    provideZoneChangeDetection({ eventCoalescing: true }),
+    provideHttpClient(),
+    provideAngularSvgIcon(),
+  ],
 };
diff --git a/alfa-client/libs/design-system/src/assets/accessibility.svg b/alfa-client/libs/design-system/src/assets/accessibility.svg
new file mode 100644
index 0000000000..5f0c8a9197
--- /dev/null
+++ b/alfa-client/libs/design-system/src/assets/accessibility.svg
@@ -0,0 +1,9 @@
+<svg viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
+  <rect x="2" y="2" width="22" height="22" rx="11" />
+  <path
+    d="M13 8.87508C12.6828 8.87508 12.3726 8.781 12.1088 8.60473C11.845 8.42846 11.6394 8.17793 11.518 7.8848C11.3966 7.59168 11.3648 7.26914 11.4267 6.95796C11.4886 6.64678 11.6414 6.36095 11.8657 6.1366C12.0901 5.91225 12.3759 5.75947 12.6871 5.69757C12.9983 5.63568 13.3208 5.66744 13.6139 5.78886C13.907 5.91027 14.1576 6.11588 14.3339 6.37969C14.5101 6.64349 14.6042 6.95364 14.6042 7.27092C14.6038 7.69623 14.4346 8.10399 14.1339 8.40473C13.8331 8.70547 13.4253 8.87463 13 8.87508Z"
+    class="fill-whitetext" />
+  <path
+    d="M18.0417 8.898L18.0288 8.90144L18.0168 8.90516C17.9881 8.91318 17.9595 8.92178 17.9308 8.93066C17.3977 9.08706 14.8105 9.81638 12.9877 9.81638C11.2939 9.81638 8.94064 9.18618 8.18783 8.97219C8.1129 8.94322 8.03639 8.91855 7.95866 8.89829C7.41439 8.75506 7.04199 9.30792 7.04199 9.81323C7.04199 10.3137 7.49173 10.552 7.94577 10.723V10.731L10.6734 11.583C10.9521 11.6898 11.0266 11.799 11.063 11.8935C11.1813 12.1969 11.0868 12.7976 11.0533 13.0072L10.8871 14.2963L9.96501 19.3434C9.96215 19.3572 9.95957 19.3712 9.95728 19.3855L9.95069 19.4219C9.88423 19.8845 10.224 20.3334 10.8674 20.3334C11.4288 20.3334 11.6766 19.9458 11.784 19.4185C11.784 19.4185 12.5861 14.9047 12.9871 14.9047C13.3882 14.9047 14.2143 19.4185 14.2143 19.4185C14.3218 19.9458 14.5695 20.3334 15.131 20.3334C15.7761 20.3334 16.1158 19.8825 16.0477 19.4185C16.0417 19.3789 16.0345 19.34 16.0259 19.3022L15.0912 14.2969L14.9253 13.0078C14.8053 12.257 14.9018 12.0089 14.9345 11.9508L14.9368 11.9465C14.9677 11.8892 15.1087 11.7609 15.4375 11.6374L17.995 10.7434C18.0107 10.7392 18.0262 10.7342 18.0414 10.7285C18.4998 10.5566 18.9581 10.3188 18.9581 9.81381C18.9581 9.30878 18.586 8.75506 18.0417 8.898Z"
+    class="fill-whitetext" />
+</svg>
\ No newline at end of file
diff --git a/alfa-client/libs/design-system/src/assets/account-circle.svg b/alfa-client/libs/design-system/src/assets/account-circle.svg
new file mode 100644
index 0000000000..e6e1d1517a
--- /dev/null
+++ b/alfa-client/libs/design-system/src/assets/account-circle.svg
@@ -0,0 +1,4 @@
+<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
+  <path
+    d="M12.75 2C7.23 2 2.75 6.48 2.75 12C2.75 17.52 7.23 22 12.75 22C18.27 22 22.75 17.52 22.75 12C22.75 6.48 18.27 2 12.75 2ZM7.82 18.28C8.25 17.38 10.87 16.5 12.75 16.5C14.63 16.5 17.26 17.38 17.68 18.28C16.32 19.36 14.61 20 12.75 20C10.89 20 9.18 19.36 7.82 18.28ZM19.11 16.83C17.68 15.09 14.21 14.5 12.75 14.5C11.29 14.5 7.82 15.09 6.39 16.83C5.37 15.49 4.75 13.82 4.75 12C4.75 7.59 8.34 4 12.75 4C17.16 4 20.75 7.59 20.75 12C20.75 13.82 20.13 15.49 19.11 16.83ZM12.75 6C10.81 6 9.25 7.56 9.25 9.5C9.25 11.44 10.81 13 12.75 13C14.69 13 16.25 11.44 16.25 9.5C16.25 7.56 14.69 6 12.75 6ZM12.75 11C11.92 11 11.25 10.33 11.25 9.5C11.25 8.67 11.92 8 12.75 8C13.58 8 14.25 8.67 14.25 9.5C14.25 10.33 13.58 11 12.75 11Z" />
+</svg>
\ No newline at end of file
diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts
index c17fdb29f5..0c5d7568d8 100644
--- a/alfa-client/libs/design-system/src/index.ts
+++ b/alfa-client/libs/design-system/src/index.ts
@@ -44,6 +44,7 @@ export * from './lib/form/text-input/text-input.component';
 export * from './lib/form/textarea/textarea.component';
 export * from './lib/forwarding-item/forwarding-item-info/forwarding-item-info.component';
 export * from './lib/forwarding-item/forwarding-item.component';
+export * from './lib/icon/icon.component';
 export * from './lib/icons/accessibility-icon/accessibility-icon.component';
 export * from './lib/icons/account-circle-icon/account-circle-icon.component';
 export * from './lib/icons/admin-logo-icon/admin-logo-icon.component';
diff --git a/alfa-client/libs/design-system/src/lib/icon/icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icon/icon.component.spec.ts
new file mode 100644
index 0000000000..90024846fc
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icon/icon.component.spec.ts
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { IconComponent } from './icon.component';
+
+describe('IconComponent', () => {
+  let component: IconComponent;
+  let fixture: ComponentFixture<IconComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [IconComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(IconComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/icon/icon.component.ts b/alfa-client/libs/design-system/src/lib/icon/icon.component.ts
new file mode 100644
index 0000000000..1681095e65
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icon/icon.component.ts
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import { CommonModule } from '@angular/common';
+import { Component, Input } from '@angular/core';
+import { SvgIconComponent } from 'angular-svg-icon';
+import { VariantProps, cva } from 'class-variance-authority';
+import { twMerge } from 'tailwind-merge';
+
+const iconVariants = cva('', {
+  variants: {
+    size: {
+      full: 'size-full',
+      small: 'size-4',
+      medium: 'size-6',
+      large: 'size-8',
+      'extra-large': 'size-10',
+      xxl: 'size-12',
+    },
+    color: {
+      primary: 'fill-primary',
+      text: 'fill-text',
+      whitetext: 'fill-whitetext',
+      error: 'fill-error',
+    },
+  },
+});
+
+type IconVariants = VariantProps<typeof iconVariants>;
+
+@Component({
+  selector: 'ods-icon',
+  standalone: true,
+  imports: [CommonModule, SvgIconComponent],
+  template: `<svg-icon [src]="'assets/icons/' + name + '.svg'" [svgClass]="twMerge(iconVariants({ size, color }), class)" />`,
+  styles: [':host {@apply block w-fit}'],
+})
+export class IconComponent {
+  @Input({ required: true }) name!: string;
+  @Input() class: string;
+  @Input() size: IconVariants['size'] = 'medium';
+  @Input() color: IconVariants['color'] = 'primary';
+
+  readonly iconVariants = iconVariants;
+  readonly twMerge = twMerge;
+}
diff --git a/alfa-client/libs/design-system/src/lib/icon/icon.stories.ts b/alfa-client/libs/design-system/src/lib/icon/icon.stories.ts
new file mode 100644
index 0000000000..6f92ea55f2
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icon/icon.stories.ts
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
+
+import { IconComponent } from './icon.component';
+
+const meta: Meta<IconComponent> = {
+  title: 'Icon',
+  component: IconComponent,
+  decorators: [
+    moduleMetadata({
+      imports: [IconComponent],
+    }),
+  ],
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<IconComponent>;
+
+export const Default: Story = {
+  args: {},
+};
diff --git a/alfa-client/package.json b/alfa-client/package.json
index d4e51a736a..94a5710a8b 100644
--- a/alfa-client/package.json
+++ b/alfa-client/package.json
@@ -73,6 +73,7 @@
     "@nx/angular": "19.8.8",
     "angular-oauth2-oidc": "17.0.2",
     "angular-oauth2-oidc-jwks": "17.0.2",
+    "angular-svg-icon": "^19.1.1",
     "class-variance-authority": "^0.7.0",
     "date-fns": "^2.30.0",
     "file-saver": "2.0.5",
diff --git a/alfa-client/pnpm-lock.yaml b/alfa-client/pnpm-lock.yaml
index c447ee766c..c01bfa47f1 100644
--- a/alfa-client/pnpm-lock.yaml
+++ b/alfa-client/pnpm-lock.yaml
@@ -71,6 +71,9 @@ importers:
       angular-oauth2-oidc-jwks:
         specifier: 17.0.2
         version: 17.0.2
+      angular-svg-icon:
+        specifier: ^19.1.1
+        version: 19.1.1(@angular/common@18.2.8(@angular/core@18.2.8(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.8(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1)
       class-variance-authority:
         specifier: ^0.7.0
         version: 0.7.0
@@ -4362,6 +4365,13 @@ packages:
       '@angular/common': '>=14.0.0'
       '@angular/core': '>=14.0.0'
 
+  angular-svg-icon@19.1.1:
+    resolution: {integrity: sha512-4uKVdkc68ii2nadJAqJDbRfMFaD3JZ4AK2S28PjGDvXfvtE5T28lm/CFZA3MKqUesUZlneJAaOX4cpC3pvoCZQ==}
+    peerDependencies:
+      '@angular/common': '>=19.0.0'
+      '@angular/core': '>=19.0.0'
+      rxjs: '>=6.6.3'
+
   ansi-colors@4.1.3:
     resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
     engines: {node: '>=6'}
@@ -16432,6 +16442,13 @@ snapshots:
       '@angular/core': 18.2.8(rxjs@7.8.1)(zone.js@0.14.10)
       tslib: 2.8.1
 
+  angular-svg-icon@19.1.1(@angular/common@18.2.8(@angular/core@18.2.8(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.8(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1):
+    dependencies:
+      '@angular/common': 18.2.8(@angular/core@18.2.8(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1)
+      '@angular/core': 18.2.8(rxjs@7.8.1)(zone.js@0.14.10)
+      rxjs: 7.8.1
+      tslib: 2.8.1
+
   ansi-colors@4.1.3: {}
 
   ansi-escapes@4.3.2:
-- 
GitLab