This commit is contained in:
Tizian.Breuch
2025-09-17 13:02:27 +02:00
parent 7e5939868b
commit a7d0f44d20
18 changed files with 929 additions and 149 deletions

666
package-lock.json generated
View File

@@ -20,6 +20,7 @@
"@angular/platform-server": "^19.1.0", "@angular/platform-server": "^19.1.0",
"@angular/router": "^19.1.0", "@angular/router": "^19.1.0",
"@angular/ssr": "^19.1.3", "@angular/ssr": "^19.1.3",
"@swimlane/ngx-charts": "^23.0.1",
"@tailwindcss/postcss": "^4.1.11", "@tailwindcss/postcss": "^4.1.11",
"express": "^4.18.2", "express": "^4.18.2",
"postcss": "^8.5.6", "postcss": "^8.5.6",
@@ -96,17 +97,17 @@
} }
}, },
"node_modules/@angular-devkit/build-angular": { "node_modules/@angular-devkit/build-angular": {
"version": "19.2.15", "version": "19.2.16",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-19.2.15.tgz", "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-19.2.16.tgz",
"integrity": "sha512-mqudAcyrSp/E7ZQdQoHfys0/nvQuwyJDaAzj3qL3HUStuUzb5ULNOj2f6sFBo+xYo+/WT8IzmzDN9DCqDgvFaA==", "integrity": "sha512-06Ry1GJ77wwy/yCSjzTcPn7mE61CRUDN1npQKwRZOQd63hrPvxFp/ueyZUODXxbqkAyieCgBwQ7qAKP6lFiZNg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "2.3.0", "@ampproject/remapping": "2.3.0",
"@angular-devkit/architect": "0.1902.15", "@angular-devkit/architect": "0.1902.16",
"@angular-devkit/build-webpack": "0.1902.15", "@angular-devkit/build-webpack": "0.1902.16",
"@angular-devkit/core": "19.2.15", "@angular-devkit/core": "19.2.16",
"@angular/build": "19.2.15", "@angular/build": "19.2.16",
"@babel/core": "7.26.10", "@babel/core": "7.26.10",
"@babel/generator": "7.26.10", "@babel/generator": "7.26.10",
"@babel/helper-annotate-as-pure": "7.25.9", "@babel/helper-annotate-as-pure": "7.25.9",
@@ -117,7 +118,7 @@
"@babel/preset-env": "7.26.9", "@babel/preset-env": "7.26.9",
"@babel/runtime": "7.26.10", "@babel/runtime": "7.26.10",
"@discoveryjs/json-ext": "0.6.3", "@discoveryjs/json-ext": "0.6.3",
"@ngtools/webpack": "19.2.15", "@ngtools/webpack": "19.2.16",
"@vitejs/plugin-basic-ssl": "1.2.0", "@vitejs/plugin-basic-ssl": "1.2.0",
"ansi-colors": "4.1.3", "ansi-colors": "4.1.3",
"autoprefixer": "10.4.20", "autoprefixer": "10.4.20",
@@ -171,7 +172,7 @@
"@angular/localize": "^19.0.0 || ^19.2.0-next.0", "@angular/localize": "^19.0.0 || ^19.2.0-next.0",
"@angular/platform-server": "^19.0.0 || ^19.2.0-next.0", "@angular/platform-server": "^19.0.0 || ^19.2.0-next.0",
"@angular/service-worker": "^19.0.0 || ^19.2.0-next.0", "@angular/service-worker": "^19.0.0 || ^19.2.0-next.0",
"@angular/ssr": "^19.2.15", "@angular/ssr": "^19.2.16",
"@web/test-runner": "^0.20.0", "@web/test-runner": "^0.20.0",
"browser-sync": "^3.0.2", "browser-sync": "^3.0.2",
"jest": "^29.5.0", "jest": "^29.5.0",
@@ -221,6 +222,50 @@
} }
} }
}, },
"node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": {
"version": "0.1902.16",
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.16.tgz",
"integrity": "sha512-E5cM4D5nHmCpuQkvyYJjJ/GEfygfU5NoN1YAWRnIMLwTyC9s6ms13L/FuCfr7HqGPY8NjkOWG2517Xda03+jAw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@angular-devkit/core": "19.2.16",
"rxjs": "7.8.1"
},
"engines": {
"node": "^18.19.1 || ^20.11.1 || >=22.0.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
}
},
"node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": {
"version": "19.2.16",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.16.tgz",
"integrity": "sha512-3MHfTTUMT/nSXLdhoilQATCY38XcnoJd7u7K0tLajTT7C+iNknvkzaV4g5qMA+E3yNzefcAkY7MZpgreNJuKEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
"jsonc-parser": "3.3.1",
"picomatch": "4.0.2",
"rxjs": "7.8.1",
"source-map": "0.7.4"
},
"engines": {
"node": "^18.19.1 || ^20.11.1 || >=22.0.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
},
"peerDependencies": {
"chokidar": "^4.0.0"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/@angular-devkit/build-angular/node_modules/postcss": { "node_modules/@angular-devkit/build-angular/node_modules/postcss": {
"version": "8.5.2", "version": "8.5.2",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.2.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.2.tgz",
@@ -261,13 +306,13 @@
} }
}, },
"node_modules/@angular-devkit/build-webpack": { "node_modules/@angular-devkit/build-webpack": {
"version": "0.1902.15", "version": "0.1902.16",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1902.15.tgz", "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1902.16.tgz",
"integrity": "sha512-pIfZeizWsViXx8bsMoBLZw7Tl7uFf7bM7hAfmNwk0bb0QGzx5k1BiW6IKWyaG+Dg6U4UCrlNpIiut2b78HwQZw==", "integrity": "sha512-KtTz1z/beiQqyB/gaw4k9xnYhymPHDeX5AOMp4f5xfn/iiUd+CKsRO/P7wyVADI9IUxEPjy7BCJFhmOYHM9anQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@angular-devkit/architect": "0.1902.15", "@angular-devkit/architect": "0.1902.16",
"rxjs": "7.8.1" "rxjs": "7.8.1"
}, },
"engines": { "engines": {
@@ -280,6 +325,50 @@
"webpack-dev-server": "^5.0.2" "webpack-dev-server": "^5.0.2"
} }
}, },
"node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": {
"version": "0.1902.16",
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.16.tgz",
"integrity": "sha512-E5cM4D5nHmCpuQkvyYJjJ/GEfygfU5NoN1YAWRnIMLwTyC9s6ms13L/FuCfr7HqGPY8NjkOWG2517Xda03+jAw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@angular-devkit/core": "19.2.16",
"rxjs": "7.8.1"
},
"engines": {
"node": "^18.19.1 || ^20.11.1 || >=22.0.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
}
},
"node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": {
"version": "19.2.16",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.16.tgz",
"integrity": "sha512-3MHfTTUMT/nSXLdhoilQATCY38XcnoJd7u7K0tLajTT7C+iNknvkzaV4g5qMA+E3yNzefcAkY7MZpgreNJuKEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
"jsonc-parser": "3.3.1",
"picomatch": "4.0.2",
"rxjs": "7.8.1",
"source-map": "0.7.4"
},
"engines": {
"node": "^18.19.1 || ^20.11.1 || >=22.0.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
},
"peerDependencies": {
"chokidar": "^4.0.0"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": {
"version": "7.8.1", "version": "7.8.1",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
@@ -374,14 +463,14 @@
} }
}, },
"node_modules/@angular/build": { "node_modules/@angular/build": {
"version": "19.2.15", "version": "19.2.16",
"resolved": "https://registry.npmjs.org/@angular/build/-/build-19.2.15.tgz", "resolved": "https://registry.npmjs.org/@angular/build/-/build-19.2.16.tgz",
"integrity": "sha512-iE4fp4d5ALu702uoL6/YkjM2JlGEXZ5G+RVzq3W2jg/Ft6ISAQnRKB6mymtetDD6oD7i87e8uSu9kFVNBauX2w==", "integrity": "sha512-sgxyrzWs2b4O19pOtWUoeDHkZ53pDoGK8GQYEdqHLNgM1JQRrHBTQts8pteopS+oPsG7WJinfXZww/c9P7BuSQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "2.3.0", "@ampproject/remapping": "2.3.0",
"@angular-devkit/architect": "0.1902.15", "@angular-devkit/architect": "0.1902.16",
"@babel/core": "7.26.10", "@babel/core": "7.26.10",
"@babel/helper-annotate-as-pure": "7.25.9", "@babel/helper-annotate-as-pure": "7.25.9",
"@babel/helper-split-export-declaration": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7",
@@ -421,7 +510,7 @@
"@angular/localize": "^19.0.0 || ^19.2.0-next.0", "@angular/localize": "^19.0.0 || ^19.2.0-next.0",
"@angular/platform-server": "^19.0.0 || ^19.2.0-next.0", "@angular/platform-server": "^19.0.0 || ^19.2.0-next.0",
"@angular/service-worker": "^19.0.0 || ^19.2.0-next.0", "@angular/service-worker": "^19.0.0 || ^19.2.0-next.0",
"@angular/ssr": "^19.2.15", "@angular/ssr": "^19.2.16",
"karma": "^6.4.0", "karma": "^6.4.0",
"less": "^4.2.0", "less": "^4.2.0",
"ng-packagr": "^19.0.0 || ^19.2.0-next.0", "ng-packagr": "^19.0.0 || ^19.2.0-next.0",
@@ -459,6 +548,60 @@
} }
} }
}, },
"node_modules/@angular/build/node_modules/@angular-devkit/architect": {
"version": "0.1902.16",
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.16.tgz",
"integrity": "sha512-E5cM4D5nHmCpuQkvyYJjJ/GEfygfU5NoN1YAWRnIMLwTyC9s6ms13L/FuCfr7HqGPY8NjkOWG2517Xda03+jAw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@angular-devkit/core": "19.2.16",
"rxjs": "7.8.1"
},
"engines": {
"node": "^18.19.1 || ^20.11.1 || >=22.0.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
}
},
"node_modules/@angular/build/node_modules/@angular-devkit/core": {
"version": "19.2.16",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.16.tgz",
"integrity": "sha512-3MHfTTUMT/nSXLdhoilQATCY38XcnoJd7u7K0tLajTT7C+iNknvkzaV4g5qMA+E3yNzefcAkY7MZpgreNJuKEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
"jsonc-parser": "3.3.1",
"picomatch": "4.0.2",
"rxjs": "7.8.1",
"source-map": "0.7.4"
},
"engines": {
"node": "^18.19.1 || ^20.11.1 || >=22.0.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
},
"peerDependencies": {
"chokidar": "^4.0.0"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/@angular/build/node_modules/rxjs": {
"version": "7.8.1",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/@angular/cdk": { "node_modules/@angular/cdk": {
"version": "19.2.19", "version": "19.2.19",
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-19.2.19.tgz", "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-19.2.19.tgz",
@@ -705,9 +848,9 @@
} }
}, },
"node_modules/@angular/platform-server": { "node_modules/@angular/platform-server": {
"version": "19.2.14", "version": "19.2.15",
"resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-19.2.14.tgz", "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-19.2.15.tgz",
"integrity": "sha512-vmnRTDhlhahna6HbmzJh+qelXkyy1wBiJrOhnLR3UVeoBMBOTTjnTKtInfVrgZTMYcV9H8us480cvtSWzYsddA==", "integrity": "sha512-VKuEmzFylYLnFjjFTctnbckgYdXEyt3wU0AwT3uuLrSU/3EgfHlqd33ONuYaIxSRES81GaLcV9cc9uiZYT2QMg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"tslib": "^2.3.0", "tslib": "^2.3.0",
@@ -717,10 +860,10 @@
"node": "^18.19.1 || ^20.11.1 || >=22.0.0" "node": "^18.19.1 || ^20.11.1 || >=22.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/common": "19.2.14", "@angular/common": "19.2.15",
"@angular/compiler": "19.2.14", "@angular/compiler": "19.2.15",
"@angular/core": "19.2.14", "@angular/core": "19.2.15",
"@angular/platform-browser": "19.2.14", "@angular/platform-browser": "19.2.15",
"rxjs": "^6.5.3 || ^7.4.0" "rxjs": "^6.5.3 || ^7.4.0"
} }
}, },
@@ -743,9 +886,9 @@
} }
}, },
"node_modules/@angular/ssr": { "node_modules/@angular/ssr": {
"version": "19.2.15", "version": "19.2.16",
"resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-19.2.15.tgz", "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-19.2.16.tgz",
"integrity": "sha512-a3yKN0RDbXgcE+izNmfuTfyN/tpwh2j0VQblA75re+TDgoovzFE74wqRPe8aGuVS90Uxya/DTkHBm3ajnOMfig==", "integrity": "sha512-6nUBQxz6vi1epIAKTGptEbQGTe4wr0vqLwwszBpXiw8DwAX0hYbAubUnnYz3rgCVIy8ekcOZlf13SO5/Gb0o7A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"tslib": "^2.3.0" "tslib": "^2.3.0"
@@ -3709,9 +3852,9 @@
] ]
}, },
"node_modules/@napi-rs/nice": { "node_modules/@napi-rs/nice": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz",
"integrity": "sha512-Sqih1YARrmMoHlXGgI9JrrgkzxcaaEso0AH+Y7j8NHonUs+xe4iDsgC3IBIDNdzEewbNpccNN6hip+b5vmyRLw==", "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
@@ -3723,28 +3866,29 @@
"url": "https://github.com/sponsors/Brooooooklyn" "url": "https://github.com/sponsors/Brooooooklyn"
}, },
"optionalDependencies": { "optionalDependencies": {
"@napi-rs/nice-android-arm-eabi": "1.0.4", "@napi-rs/nice-android-arm-eabi": "1.1.1",
"@napi-rs/nice-android-arm64": "1.0.4", "@napi-rs/nice-android-arm64": "1.1.1",
"@napi-rs/nice-darwin-arm64": "1.0.4", "@napi-rs/nice-darwin-arm64": "1.1.1",
"@napi-rs/nice-darwin-x64": "1.0.4", "@napi-rs/nice-darwin-x64": "1.1.1",
"@napi-rs/nice-freebsd-x64": "1.0.4", "@napi-rs/nice-freebsd-x64": "1.1.1",
"@napi-rs/nice-linux-arm-gnueabihf": "1.0.4", "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1",
"@napi-rs/nice-linux-arm64-gnu": "1.0.4", "@napi-rs/nice-linux-arm64-gnu": "1.1.1",
"@napi-rs/nice-linux-arm64-musl": "1.0.4", "@napi-rs/nice-linux-arm64-musl": "1.1.1",
"@napi-rs/nice-linux-ppc64-gnu": "1.0.4", "@napi-rs/nice-linux-ppc64-gnu": "1.1.1",
"@napi-rs/nice-linux-riscv64-gnu": "1.0.4", "@napi-rs/nice-linux-riscv64-gnu": "1.1.1",
"@napi-rs/nice-linux-s390x-gnu": "1.0.4", "@napi-rs/nice-linux-s390x-gnu": "1.1.1",
"@napi-rs/nice-linux-x64-gnu": "1.0.4", "@napi-rs/nice-linux-x64-gnu": "1.1.1",
"@napi-rs/nice-linux-x64-musl": "1.0.4", "@napi-rs/nice-linux-x64-musl": "1.1.1",
"@napi-rs/nice-win32-arm64-msvc": "1.0.4", "@napi-rs/nice-openharmony-arm64": "1.1.1",
"@napi-rs/nice-win32-ia32-msvc": "1.0.4", "@napi-rs/nice-win32-arm64-msvc": "1.1.1",
"@napi-rs/nice-win32-x64-msvc": "1.0.4" "@napi-rs/nice-win32-ia32-msvc": "1.1.1",
"@napi-rs/nice-win32-x64-msvc": "1.1.1"
} }
}, },
"node_modules/@napi-rs/nice-android-arm-eabi": { "node_modules/@napi-rs/nice-android-arm-eabi": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz",
"integrity": "sha512-OZFMYUkih4g6HCKTjqJHhMUlgvPiDuSLZPbPBWHLjKmFTv74COzRlq/gwHtmEVaR39mJQ6ZyttDl2HNMUbLVoA==", "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -3759,9 +3903,9 @@
} }
}, },
"node_modules/@napi-rs/nice-android-arm64": { "node_modules/@napi-rs/nice-android-arm64": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz",
"integrity": "sha512-k8u7cjeA64vQWXZcRrPbmwjH8K09CBnNaPnI9L1D5N6iMPL3XYQzLcN6WwQonfcqCDv5OCY3IqX89goPTV4KMw==", "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3776,9 +3920,9 @@
} }
}, },
"node_modules/@napi-rs/nice-darwin-arm64": { "node_modules/@napi-rs/nice-darwin-arm64": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz",
"integrity": "sha512-GsLdQvUcuVzoyzmtjsThnpaVEizAqH5yPHgnsBmq3JdVoVZHELFo7PuJEdfOH1DOHi2mPwB9sCJEstAYf3XCJA==", "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3793,9 +3937,9 @@
} }
}, },
"node_modules/@napi-rs/nice-darwin-x64": { "node_modules/@napi-rs/nice-darwin-x64": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz",
"integrity": "sha512-1y3gyT3e5zUY5SxRl3QDtJiWVsbkmhtUHIYwdWWIQ3Ia+byd/IHIEpqAxOGW1nhhnIKfTCuxBadHQb+yZASVoA==", "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3810,9 +3954,9 @@
} }
}, },
"node_modules/@napi-rs/nice-freebsd-x64": { "node_modules/@napi-rs/nice-freebsd-x64": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz",
"integrity": "sha512-06oXzESPRdXUuzS8n2hGwhM2HACnDfl3bfUaSqLGImM8TA33pzDXgGL0e3If8CcFWT98aHows5Lk7xnqYNGFeA==", "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3827,9 +3971,9 @@
} }
}, },
"node_modules/@napi-rs/nice-linux-arm-gnueabihf": { "node_modules/@napi-rs/nice-linux-arm-gnueabihf": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz",
"integrity": "sha512-CgklZ6g8WL4+EgVVkxkEvvsi2DSLf9QIloxWO0fvQyQBp6VguUSX3eHLeRpqwW8cRm2Hv/Q1+PduNk7VK37VZw==", "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -3844,9 +3988,9 @@
} }
}, },
"node_modules/@napi-rs/nice-linux-arm64-gnu": { "node_modules/@napi-rs/nice-linux-arm64-gnu": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz",
"integrity": "sha512-wdAJ7lgjhAlsANUCv0zi6msRwq+D4KDgU+GCCHssSxWmAERZa2KZXO0H2xdmoJ/0i03i6YfK/sWaZgUAyuW2oQ==", "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3861,9 +4005,9 @@
} }
}, },
"node_modules/@napi-rs/nice-linux-arm64-musl": { "node_modules/@napi-rs/nice-linux-arm64-musl": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz",
"integrity": "sha512-4b1KYG+sriufhFrpUS9uNOEYYJqSfcbnwGx6uGX7JjrH8tELG90cOpCawz5THNIwlS3DhLgnCOcn0+4p6z26QA==", "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3878,9 +4022,9 @@
} }
}, },
"node_modules/@napi-rs/nice-linux-ppc64-gnu": { "node_modules/@napi-rs/nice-linux-ppc64-gnu": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz",
"integrity": "sha512-iaf3vMRgr23oe1PUaKpxaH3DS0IMN0+N9iEiWVwYPm/U15vZFYdqVegGfN2PzrZLUl5lc8ZxbmEKDfuqslhAMA==", "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -3895,9 +4039,9 @@
} }
}, },
"node_modules/@napi-rs/nice-linux-riscv64-gnu": { "node_modules/@napi-rs/nice-linux-riscv64-gnu": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz",
"integrity": "sha512-UXoREY6Yw6rHrGuTwQgBxpfjK34t6mTjibE9/cXbefL9AuUCJ9gEgwNKZiONuR5QGswChqo9cnthjdKkYyAdDg==", "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -3912,9 +4056,9 @@
} }
}, },
"node_modules/@napi-rs/nice-linux-s390x-gnu": { "node_modules/@napi-rs/nice-linux-s390x-gnu": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz",
"integrity": "sha512-eFbgYCRPmsqbYPAlLYU5hYTNbogmIDUvknilehHsFhCH1+0/kN87lP+XaLT0Yeq4V/rpwChSd9vlz4muzFArtw==", "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -3929,9 +4073,9 @@
} }
}, },
"node_modules/@napi-rs/nice-linux-x64-gnu": { "node_modules/@napi-rs/nice-linux-x64-gnu": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz",
"integrity": "sha512-4T3E6uTCwWT6IPnwuPcWVz3oHxvEp/qbrCxZhsgzwTUBEwu78EGNXGdHfKJQt3soth89MLqZJw+Zzvnhrsg1mQ==", "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3946,9 +4090,9 @@
} }
}, },
"node_modules/@napi-rs/nice-linux-x64-musl": { "node_modules/@napi-rs/nice-linux-x64-musl": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz",
"integrity": "sha512-NtbBkAeyBPLvCBkWtwkKXkNSn677eaT0cX3tygq+2qVv71TmHgX4gkX6o9BXjlPzdgPGwrUudavCYPT9tzkEqQ==", "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3962,10 +4106,27 @@
"node": ">= 10" "node": ">= 10"
} }
}, },
"node_modules/@napi-rs/nice-openharmony-arm64": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz",
"integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-win32-arm64-msvc": { "node_modules/@napi-rs/nice-win32-arm64-msvc": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz",
"integrity": "sha512-vubOe3i+YtSJGEk/++73y+TIxbuVHi+W8ZzrRm2eETCjCRwNlgbfToQZ85dSA+4iBB/NJRGNp+O4hfdbbttZWA==", "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3980,9 +4141,9 @@
} }
}, },
"node_modules/@napi-rs/nice-win32-ia32-msvc": { "node_modules/@napi-rs/nice-win32-ia32-msvc": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz",
"integrity": "sha512-BMOVrUDZeg1RNRKVlh4eyLv5djAAVLiSddfpuuQ47EFjBcklg0NUeKMFKNrKQR4UnSn4HAiACLD7YK7koskwmg==", "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -3997,9 +4158,9 @@
} }
}, },
"node_modules/@napi-rs/nice-win32-x64-msvc": { "node_modules/@napi-rs/nice-win32-x64-msvc": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz",
"integrity": "sha512-kCNk6HcRZquhw/whwh4rHsdPyOSCQCgnVDVik+Y9cuSVTDy3frpiCJTScJqPPS872h4JgZKkr/+CwcwttNEo9Q==", "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -4014,9 +4175,9 @@
} }
}, },
"node_modules/@ngtools/webpack": { "node_modules/@ngtools/webpack": {
"version": "19.2.15", "version": "19.2.16",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-19.2.15.tgz", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-19.2.16.tgz",
"integrity": "sha512-H37nop/wWMkSgoU2VvrMzanHePdLRRrX52nC5tT2ZhH3qP25+PrnMyw11PoLDLv3iWXC68uB1AiKNIT+jiQbuQ==", "integrity": "sha512-KJf/pmpQl8SGhTof91EUuSFfR34kSTjcCQp3JQWDvG08+Lnx3wKbnKrZjC9vz0fhRrB+ZFVxeAyDAh1zZk07wg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -5070,6 +5231,39 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@swimlane/ngx-charts": {
"version": "23.0.1",
"resolved": "https://registry.npmjs.org/@swimlane/ngx-charts/-/ngx-charts-23.0.1.tgz",
"integrity": "sha512-mvdJTjBjUNoDj/R3AopYyVkVNrv0Zsrlh71CIQLVhBOs6PSV1mT3o7ukBFu8ct4w38wTfiGr8G+twHiYM1TEKA==",
"license": "MIT",
"dependencies": {
"d3-array": "^3.2.0",
"d3-brush": "^3.0.0",
"d3-color": "^3.1.0",
"d3-ease": "^3.0.1",
"d3-format": "^3.1.0",
"d3-hierarchy": "^3.1.2",
"d3-interpolate": "^3.0.1",
"d3-sankey": "^0.12.3",
"d3-scale": "^4.0.2",
"d3-selection": "^3.0.0",
"d3-shape": "^3.2.0",
"d3-time-format": "^4.1.0",
"d3-transition": "^3.0.1",
"gradient-path": "^2.3.0",
"tslib": "^2.3.1"
},
"peerDependencies": {
"@angular/animations": "18.x || 19.x || 20.x",
"@angular/cdk": "18.x || 19.x || 20.x",
"@angular/common": "18.x || 19.x || 20.x",
"@angular/core": "18.x || 19.x || 20.x",
"@angular/forms": "18.x || 19.x || 20.x",
"@angular/platform-browser": "18.x || 19.x || 20.x",
"@angular/platform-browser-dynamic": "18.x || 19.x || 20.x",
"rxjs": "7.x"
}
},
"node_modules/@tailwindcss/node": { "node_modules/@tailwindcss/node": {
"version": "4.1.11", "version": "4.1.11",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz",
@@ -5669,6 +5863,12 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/tinycolor2": {
"version": "1.4.6",
"resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.6.tgz",
"integrity": "sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==",
"license": "MIT"
},
"node_modules/@types/ws": { "node_modules/@types/ws": {
"version": "8.18.1", "version": "8.18.1",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
@@ -7392,6 +7592,242 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/d3-array": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
"integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
"license": "ISC",
"dependencies": {
"internmap": "1 - 2"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-brush": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
"integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
"license": "ISC",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
"d3-interpolate": "1 - 3",
"d3-selection": "3",
"d3-transition": "3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-dispatch": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-drag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
"license": "ISC",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-selection": "3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-ease": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-format": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
"integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-hierarchy": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
"integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
"license": "ISC",
"dependencies": {
"d3-color": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-path": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
"integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-sankey": {
"version": "0.12.3",
"resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz",
"integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==",
"license": "BSD-3-Clause",
"dependencies": {
"d3-array": "1 - 2",
"d3-shape": "^1.2.0"
}
},
"node_modules/d3-sankey/node_modules/d3-array": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
"integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
"license": "BSD-3-Clause",
"dependencies": {
"internmap": "^1.0.0"
}
},
"node_modules/d3-sankey/node_modules/d3-path": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
"integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==",
"license": "BSD-3-Clause"
},
"node_modules/d3-sankey/node_modules/d3-shape": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
"integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
"license": "BSD-3-Clause",
"dependencies": {
"d3-path": "1"
}
},
"node_modules/d3-sankey/node_modules/internmap": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==",
"license": "ISC"
},
"node_modules/d3-scale": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
"integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
"license": "ISC",
"dependencies": {
"d3-array": "2.10.0 - 3",
"d3-format": "1 - 3",
"d3-interpolate": "1.2.0 - 3",
"d3-time": "2.1.1 - 3",
"d3-time-format": "2 - 4"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-selection": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-shape": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
"integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
"license": "ISC",
"dependencies": {
"d3-path": "^3.1.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-time": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
"integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
"license": "ISC",
"dependencies": {
"d3-array": "2 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-time-format": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
"integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
"license": "ISC",
"dependencies": {
"d3-time": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-timer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-transition": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
"license": "ISC",
"dependencies": {
"d3-color": "1 - 3",
"d3-dispatch": "1 - 3",
"d3-ease": "1 - 3",
"d3-interpolate": "1 - 3",
"d3-timer": "1 - 3"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"d3-selection": "2 - 3"
}
},
"node_modules/date-format": { "node_modules/date-format": {
"version": "4.0.14", "version": "4.0.14",
"resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz",
@@ -8563,6 +8999,15 @@
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/gradient-path": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/gradient-path/-/gradient-path-2.3.0.tgz",
"integrity": "sha512-vZdF/Z0EpqUztzWXFjFC16lqcialHacYoRonslk/bC6CuujkuIrqx7etlzdYHY4SnUU94LRWESamZKfkGh7yYQ==",
"license": "MIT",
"dependencies": {
"tinygradient": "^1.0.0"
}
},
"node_modules/handle-thing": { "node_modules/handle-thing": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
@@ -9006,6 +9451,15 @@
"node": "^18.17.0 || >=20.5.0" "node": "^18.17.0 || >=20.5.0"
} }
}, },
"node_modules/internmap": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
"integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/ip-address": { "node_modules/ip-address": {
"version": "10.0.1", "version": "10.0.1",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz",
@@ -13808,6 +14262,12 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/tinycolor2": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
"integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
"license": "MIT"
},
"node_modules/tinyglobby": { "node_modules/tinyglobby": {
"version": "0.2.14", "version": "0.2.14",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
@@ -13825,6 +14285,16 @@
"url": "https://github.com/sponsors/SuperchupuDev" "url": "https://github.com/sponsors/SuperchupuDev"
} }
}, },
"node_modules/tinygradient": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/tinygradient/-/tinygradient-1.1.5.tgz",
"integrity": "sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw==",
"license": "MIT",
"dependencies": {
"@types/tinycolor2": "^1.4.0",
"tinycolor2": "^1.0.0"
}
},
"node_modules/tmp": { "node_modules/tmp": {
"version": "0.2.5", "version": "0.2.5",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",

View File

@@ -23,6 +23,7 @@
"@angular/platform-server": "^19.1.0", "@angular/platform-server": "^19.1.0",
"@angular/router": "^19.1.0", "@angular/router": "^19.1.0",
"@angular/ssr": "^19.1.3", "@angular/ssr": "^19.1.3",
"@swimlane/ngx-charts": "^23.0.1",
"@tailwindcss/postcss": "^4.1.11", "@tailwindcss/postcss": "^4.1.11",
"express": "^4.18.2", "express": "^4.18.2",
"postcss": "^8.5.6", "postcss": "^8.5.6",

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#666666"><path d="m242-200 200-280-200-280h98l200 280-200 280h-98Zm238 0 200-280-200-280h98l200 280-200 280h-98Z"/></svg>

After

Width:  |  Height:  |  Size: 219 B

View File

@@ -3,15 +3,30 @@ import { Routes } from '@angular/router';
import { AccessDeniedComponent } from './core/components/access-denied/access-denied.component'; import { AccessDeniedComponent } from './core/components/access-denied/access-denied.component';
import { NotFoundComponent } from './core/components/not-found/not-found.component'; import { NotFoundComponent } from './core/components/not-found/not-found.component';
import { DefaultLayoutComponent } from './core/components/default-layout/default-layout.component';
import { DashboardPageComponent } from './features/dashboard/pages/dashboard-page/dashboard-page.component';
export const routes: Routes = [ export const routes: Routes = [
// Regel 1: Leerer Pfad (Startseite der Anwendung)
// Ein Benutzer, der die Haupt-URL Ihrer Seite aufruft (z.B. "http://localhost:4200/"),
// wird sofort und ohne Umwege zur Login-Seite weitergeleitet.
{ {
path: '', path: '',
redirectTo: 'auth', redirectTo: 'auth',
pathMatch: 'full', pathMatch: 'full',
}, },
{
path: 'dashboard',
component: DefaultLayoutComponent,
children: [
{
path: '',
loadChildren: () =>
import('./features/dashboard/dashboard.routes').then(
(r) => r.DASHBOARD_ROUTES
),
},
],
},
{ {
path: 'auth', path: 'auth',
loadChildren: () => loadChildren: () =>
@@ -28,8 +43,13 @@ export const routes: Routes = [
title: 'Zugriff verweigert', title: 'Zugriff verweigert',
}, },
{ {
path: '**', path: '404',
component: NotFoundComponent, component: NotFoundComponent,
title: '404 - Seite nicht gefunden', title: '404 - Seite nicht gefunden',
}, },
{
path: '**',
redirectTo: '404',
},
]; ];

View File

@@ -0,0 +1,13 @@
:host {
display: block;
}
.main-layout-container {
display: flex;
background-color: var(--color-body-bg);
}
.main-content {
flex-grow: 1;
overflow-y: auto;
padding: 2rem;
}

View File

@@ -0,0 +1,6 @@
<div class="main-layout-container">
<app-sidebar></app-sidebar>
<div class="main-content">
<router-outlet></router-outlet>
</div>
</div>

View File

@@ -0,0 +1,13 @@
import { Component } from '@angular/core';
import { SidebarComponent } from '../../../shared/components/layout/sidebar/sidebar.component';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-default-layout',
imports: [SidebarComponent,RouterOutlet],
templateUrl: './default-layout.component.html',
styleUrl: './default-layout.component.css'
})
export class DefaultLayoutComponent {
}

View File

@@ -0,0 +1,9 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [],
imports: [CommonModule],
})
export class DashboardModule {}

View File

@@ -0,0 +1,12 @@
import { Routes } from '@angular/router';
import { DashboardPageComponent } from './pages/dashboard-page/dashboard-page.component';
// Importiere dein spezielles Layout für Auth-Seiten und alle Komponenten
export const DASHBOARD_ROUTES: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{
path: 'home',
component: DashboardPageComponent,
title: 'Dashboard Übersicht',
},
];

View File

@@ -0,0 +1,56 @@
<p>dashboard-page works!</p>
<p>
Key Performance Indicators (KPIs) Das "Big Picture" Dies sind die
wichtigsten Kennzahlen, die den Geschäftserfolg auf einen Blick zeigen. Sie
sollten prominent ganz oben platziert werden. Alle diese Daten stammen direkt
aus dem KpiSummaryDto, das Sie vom /api/v1/admin/AdminAnalytics-Endpunkt
bekommen. Gesamtumsatz (totalRevenue): Die wichtigste Kennzahl. Zeigt, wie
viel Geld der Shop einnimmt. Anzahl der Bestellungen (totalOrders): Zeigt die
Aktivität im Shop. Durchschnittlicher Bestellwert (averageOrderValue): Hilft
zu beurteilen, ob Kunden tendenziell mehr oder weniger pro Einkauf ausgeben.
Anzahl der Neukunden (newCustomersThisPeriod): Wichtig für das Wachstum.
Zeigt, wie viele neue Kunden im gewählten Zeitraum registriert wurden.
Darstellung: Am besten als einzelne, große "KPI-Karten", wie wir es im
vorherigen Beispiel hatten.
</p>
<br />
<p>
Handlungsrelevante Aufgaben "Was muss ich jetzt tun?" Das ist der vielleicht
wichtigste Teil des Dashboards. Er sollte dem Admin direkt zeigen, wo seine
Aufmerksamkeit benötigt wird. Bestellungen zur Bearbeitung: Eine Zählung und
eine Liste der letzten Bestellungen mit dem Status Pending oder Processing.
Dies signalisiert "Hier muss etwas verpackt und versendet werden!".
API-Endpunkt: GET /api/v1/admin/AdminOrders Sie müssten die zurückgegebene
Liste clientseitig nach dem Status filtern. Produkte mit niedrigem
Lagerbestand: Eine Warnung oder eine Liste von Produkten, deren stockQuantity
unter einen bestimmten Schwellenwert fällt. API-Endpunkt: Das
InventoryStatusDto aus dem AdminAnalytics-Endpunkt liefert Ihnen direkt die
Anzahl (productsWithLowStock). Zu genehmigende Bewertungen (Reviews): Falls
Sie ein Freigabeverfahren für Kundenbewertungen haben, ist eine Anzeige wie "3
neue Bewertungen warten auf Freigabe" extrem hilfreich. API-Endpunkt: GET
/api/v1/admin/AdminReviews Sie müssten hier eine Zählung der noch nicht
genehmigten Reviews durchführen. Darstellung: Als auffällige
Benachrichtigungs-Boxen oder "To-Do"-Listen.
</p>
<br />
<p>
Jüngste Aktivitäten "Was passiert gerade im Shop?" Diese Sektion gibt dem
Admin ein Gefühl für die aktuelle Dynamik im Shop. Letzte Bestellungen: Eine
kurze Liste der 5-10 neuesten Bestellungen, unabhängig vom Status. Zeigt den
Namen des Kunden, den Bestellwert und das Datum. API-Endpunkt: GET
/api/v1/admin/AdminOrders. Umsatzverlauf der letzten 30 Tage: Ein einfaches
Linien- oder Balkendiagramm, das den täglichen Umsatz anzeigt. API-Endpunkt:
Die salesOverTime-Daten aus dem AdminAnalytics-Endpunkt sind perfekt dafür
gemacht.
</p>
<br />
<p>
Top-Listen "Was läuft am besten?" Diese Informationen sind strategisch
wertvoll, um zu wissen, welche Produkte populär sind. Top 5 meistverkaufte
Produkte: Eine einfache Tabelle mit den Produkten, die den meisten Umsatz
generieren oder am häufigsten verkauft wurden. API-Endpunkt: Die Liste
topPerformingProducts aus dem AdminAnalytics-Endpunkt liefert Ihnen genau
diese Daten.
</p>
<br />

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-dashboard-page',
imports: [],
templateUrl: './dashboard-page.component.html',
styleUrl: './dashboard-page.component.css'
})
export class DashboardPageComponent {
}

View File

@@ -105,6 +105,37 @@
</app-form-group> </app-form-group>
</div> </div>
<div class="grid-col-span-2">
<app-form-group
title="Layout Components"
description="Diese Informationen sind öffentlich sichtbar."
>
<h3 card-header>Umsatzentwicklung</h3>
<!-- Das card-body dient als Container für das Diagramm -->
<div class="chart-wrapper">
<ngx-charts-bar-vertical
[results]="salesData"
scheme="vivid"
[xAxis]="true"
[yAxis]="true"
[legend]="false"
[showXAxisLabel]="true"
[showYAxisLabel]="true"
xAxisLabel="Monat"
yAxisLabel="Umsatz in €">
</ngx-charts-bar-vertical>
</div>
</app-form-group>
</div>
<div class="grid-col-span-2"> <div class="grid-col-span-2">
<app-form-group title="Button Components" description="UI Components"> <app-form-group title="Button Components" description="UI Components">
<!-- Sektion 1: Standard-Buttons --> <!-- Sektion 1: Standard-Buttons -->

View File

@@ -47,6 +47,8 @@ import { ChipComponent } from '../../../../shared/components/ui/chip/chip.compon
import { ReactiveFormsModule } from '@angular/forms'; import { ReactiveFormsModule } from '@angular/forms';
import { NgxChartsModule } from '@swimlane/ngx-charts';
// Wir definieren ein Interface für unsere KPI-Daten für Typsicherheit // Wir definieren ein Interface für unsere KPI-Daten für Typsicherheit
interface Kpi { interface Kpi {
value: string; value: string;
@@ -73,7 +75,8 @@ interface Kpi {
PageHeaderComponent, PageHeaderComponent,
ButtonComponent, ButtonComponent,
ChipComponent, ChipComponent,
ReactiveFormsModule ReactiveFormsModule,
NgxChartsModule
], ],
templateUrl: './demo2.component.html', templateUrl: './demo2.component.html',
}) })
@@ -231,6 +234,23 @@ export class Demo2Component {
private readonly darkModeKey = 'app-dark-mode-setting'; private readonly darkModeKey = 'app-dark-mode-setting';
darkModeAktiv: boolean = false; darkModeAktiv: boolean = false;
// +++ NEUE EIGENSCHAFTEN FÜR DAS DIAGRAMM +++
// 1. Die Daten für das Diagramm im von ngx-charts erwarteten Format
salesData = [
{ name: 'Jan', value: 12500 },
{ name: 'Feb', value: 14750 },
{ name: 'Mär', value: 11800 },
{ name: 'Apr', value: 18600 },
{ name: 'Mai', value: 21500 },
{ name: 'Jun', value: 19800 }
];
// 2. (Optional) Ein benutzerdefiniertes Farbschema, das zu Ihrem Theme passt
customColorScheme = {
domain: ['#3498db', '#2980b9', '#2ecc71', '#27ae60', '#f39c12', '#f1c40f']
};
constructor( constructor(
private renderer: Renderer2, private renderer: Renderer2,

View File

@@ -1,66 +1,152 @@
/* Verschieben Sie alle .sidebar... und .nav-item... Klassen aus styles.css hierher */ /* Globale Variablen für einfachere Wartung */
:host { :host {
display: block; --sidebar-width-expanded: 280px;
--sidebar-width-collapsed: 96px;
--sidebar-padding: 1rem;
--sidebar-margin: 1rem;
--transition-speed: 0.3s;
--transition-ease: ease-in-out;
} }
/* 1. Der Sidebar-Container */
.sidebar { .sidebar {
width: 260px; position: relative;
height: 100vh;
position: sticky;
top: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 1.5rem; gap: 2rem;
background: var(--glass-bg); width: var(--sidebar-width-expanded);
backdrop-filter: var(--glass-backdrop-filter); height: calc(100vh - (var(--sidebar-margin) * 2));
-webkit-backdrop-filter: var(--glass-backdrop-filter); margin: var(--sidebar-margin);
border-right: 1px solid var(--color-border); padding: var(--sidebar-padding);
transition: background-color var(--transition-speed), background-color: #fff;
border-color var(--transition-speed); border: 1px solid #e5e7eb; /* Helle Umrandung */
border-radius: 1rem;
transition: width var(--transition-speed) var(--transition-ease);
} }
/* 2. Der Header-Bereich */
.sidebar-header { .sidebar-header {
margin-bottom: 2rem; display: flex;
align-items: center;
gap: 0.75rem; /* Abstand zwischen Logo und Titel */
padding: 0.5rem;
} }
.sidebar-logo {
flex-shrink: 0;
width: 32px;
height: 32px;
color: #111827;
}
.sidebar-title { .sidebar-title {
font-size: 1.5rem; margin: 0;
font-weight: 900; font-size: 1.25rem;
font-weight: 600;
white-space: nowrap;
opacity: 1;
overflow: hidden;
transition: opacity 0.2s ease-in-out,
width 0.3s ease-in-out 0.05s,
transform 0.3s ease-in-out;
} }
/* ======================================================= */
/* --- HIER PASSIERT DIE MAGIE FÜR DEN BUTTON --- */
/* ======================================================= */
.sidebar-header app-button {
/* Weist den Button an, den gesamten verfügbaren Platz als linken Abstand zu nutzen */
margin-left: auto;
/* Verhindert, dass der Button schrumpft */
flex-shrink: 0;
/* Fügt eine sanfte Drehanimation hinzu */
transition: transform var(--transition-speed) var(--transition-ease);
transform: rotate(0deg); /* Startposition der Animation */
}
/* 3. Die Navigation (angepasst an das neue Design) */
.sidebar-nav { .sidebar-nav {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.5rem; gap: 0.5rem;
flex-grow: 1; flex-grow: 1; /* Nimmt den restlichen vertikalen Platz ein */
}
.sidebar-footer {
margin-top: auto;
} }
.nav-item { .nav-item {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 1rem; gap: 0.75rem;
padding: 0.75rem 1rem; padding: 0.75rem 1rem;
border-radius: var(--border-radius-md); border-radius: 0.5rem;
color: var(--color-text-light);
font-weight: 500;
text-decoration: none; text-decoration: none;
transition: all var(--transition-speed); font-weight: 500;
} color: #4b5563;
.nav-item app-icon { white-space: nowrap;
font-size: 20px; /* Steuert die Größe des Icons */ transition: background-color 0.2s, color 0.2s;
transition: color var(--transition-speed);
} }
.nav-item:hover { .nav-item:hover {
background-color: rgba(0, 0, 0, 0.05); background-color: #f3f4f6;
color: var(--color-text);
}
:host-context(body.dark-theme) .nav-item:hover {
background-color: rgba(255, 255, 255, 0.05);
} }
.nav-item.active { .nav-item.active {
background: var(--color-primary-gradient); background-color: #3b82f6;
color: #fff;
box-shadow: 0 4px 10px rgba(52, 152, 219, 0.4);
}
.nav-item.active app-icon {
color: #fff; color: #fff;
} }
.nav-item app-icon {
font-size: 1.25rem;
}
.sidebar-footer {
margin-top: auto; /* Schiebt den Footer nach unten */
}
/* ======================================================= */
/* --- Stile für den eingeklappten Zustand (.collapsed) --- */
/* ======================================================= */
.sidebar.collapsed {
width: var(--sidebar-width-collapsed);
}
.sidebar.collapsed .sidebar-header {
justify-content: center; /* Zentriert das Logo, wenn der Titel weg ist */
}
.sidebar.collapsed .sidebar-title {
opacity: 0;
width: 0; /* Wichtig: expliziter Endwert für die Breiten-Animation */
transform: translateX(-10px); /* Leichte Bewegung nach links */
pointer-events: none;
}
/* Dreht den Button um 180 Grad, wenn die Sidebar eingeklappt ist */
.sidebar.collapsed .sidebar-header app-button {
transform: rotate(180deg);
margin-left: 0; /* Setzt den Margin zurück, da 'justify-content' jetzt die Positionierung übernimmt */
}
.sidebar.collapsed .nav-item {
justify-content: center;
}
.nav-item span {
white-space: nowrap;
opacity: 1;
/* === NEU: Präzise Transition auch hier === */
overflow: hidden;
transition: opacity 0.2s ease-in-out,
width 0.3s ease-in-out 0.05s;
}
.sidebar.collapsed .nav-item span {
opacity: 0;
width: 0; /* Wichtig: expliziter Endwert für die Breiten-Animation */
pointer-events: none;
}

View File

@@ -1,13 +1,33 @@
<aside class="sidebar"> <aside class="sidebar" [class.collapsed]="isCollapsed">
<div class="sidebar-header"> <div class="sidebar-header">
<h1 class="sidebar-title">CustomDash</h1> <div class="sidebar-logo">
<!-- Ersetzen Sie dies durch Ihr Logo, z.B. als <img> oder <svg> -->
<svg
viewBox="0 0 48 48"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
>
<path
d="M24 8C19.2 8 15.2 9.4 12 11.8C15.4 12.8 18.3 15.6 19.4 19C20.6 18.6 21.8 18.4 23 18.4C24.4 18.4 25.6 18.6 26.8 19C27.9 15.6 30.8 12.8 34.2 11.8C31 9.4 27.2 8 24 8ZM11.8 12.2C8.6 14.6 6 18.2 4.6 22.4C7.8 22.8 10.6 24.6 12.4 27.2C11.4 25.4 10.8 23.2 10.6 21C9.4 17.6 10 14.4 11.8 12.2ZM36.2 12.2C38 14.4 38.6 17.6 37.4 21C37.2 23.2 36.6 25.4 35.6 27.2C37.4 24.6 40.2 22.8 43.4 22.4C42 18.2 39.4 14.6 36.2 12.2ZM4.2 24C4 25.2 4 26.4 4 27.8C4 32.8 6 37.4 9.4 40.6C10.2 37.6 12 35 14.4 33C12 30.8 10.2 28.2 9.2 25.4C7.2 25.2 5.4 24.6 4.2 24ZM20.8 27.8C18.4 29.8 16.6 32.4 15.4 35.4C17.6 38.2 20.6 40 24 40C27.4 40 30.4 38.2 32.6 35.4C31.4 32.4 29.6 29.8 27.2 27.8C25.6 29 24.2 29.2 23.2 29.2C22.4 29.2 21.4 29 20.8 27.8ZM38.8 25.4C37.8 28.2 36 30.8 33.6 33C36 35 37.8 37.6 38.6 40.6C42 37.4 44 32.8 44 27.8C44 26.4 44 25.2 43.8 24C42.6 24.6 40.8 25.2 38.8 25.4Z"
/>
</svg>
</div>
<h1 class="sidebar-title">Wetask</h1>
<app-button
buttonType="icon"
iconName="double_arrow"
(click)="toggleSidebar()"
></app-button>
</div> </div>
<!-- 2. Der Button zum Ein- und Ausklappen. Er ruft unsere neue Methode auf. -->
<nav class="sidebar-nav"> <nav class="sidebar-nav">
<a <a
class="nav-item" class="nav-item"
[class.active]="activeRoute === 'dashboard'" [class.active]="activeRoute === 'dashboard'"
(click)="setActive('dashboard')" (click)="setActive('dashboard')"
title="Übersicht"
> >
<app-icon name="placeholder"></app-icon> <app-icon name="placeholder"></app-icon>
<span>Übersicht</span> <span>Übersicht</span>
@@ -17,6 +37,7 @@
class="nav-item" class="nav-item"
[class.active]="activeRoute === 'analytics'" [class.active]="activeRoute === 'analytics'"
(click)="setActive('analytics')" (click)="setActive('analytics')"
title="Analysen"
> >
<app-icon name="placeholder"></app-icon> <app-icon name="placeholder"></app-icon>
<span>Analysen</span> <span>Analysen</span>
@@ -26,6 +47,7 @@
class="nav-item" class="nav-item"
[class.active]="activeRoute === 'reports'" [class.active]="activeRoute === 'reports'"
(click)="setActive('reports')" (click)="setActive('reports')"
title="Berichte"
> >
<app-icon name="placeholder"></app-icon> <app-icon name="placeholder"></app-icon>
<span>Berichte</span> <span>Berichte</span>
@@ -37,6 +59,7 @@
class="nav-item" class="nav-item"
[class.active]="activeRoute === 'settings'" [class.active]="activeRoute === 'settings'"
(click)="setActive('settings')" (click)="setActive('settings')"
title="Einstellungen"
> >
<app-icon name="placeholder"></app-icon> <app-icon name="placeholder"></app-icon>
<span>Einstellungen</span> <span>Einstellungen</span>

View File

@@ -1,21 +1,29 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { IconComponent } from '../../ui/icon/icon.component'; import { IconComponent } from '../../ui/icon/icon.component';
import { ButtonComponent } from '../../ui/button/button.component';
@Component({ @Component({
selector: 'app-sidebar', selector: 'app-sidebar',
standalone: true, standalone: true,
imports: [CommonModule, IconComponent], imports: [CommonModule, IconComponent,ButtonComponent],
templateUrl: './sidebar.component.html', templateUrl: './sidebar.component.html',
styleUrl: './sidebar.component.css' styleUrl: './sidebar.component.css'
}) })
export class SidebarComponent { export class SidebarComponent {
// Wir verwalten nur noch, welcher Link aktiv ist. 'dashboard' ist der Standard. // Dummy-Eigenschaft für die aktive Route, damit der Code funktioniert
activeRoute = 'dashboard'; activeRoute = 'dashboard';
// Methode, um den aktiven Link bei einem Klick zu ändern. // NEU: Eigenschaft, um den Zustand der Sidebar zu speichern
// In einer echten App würde dies durch den Angular Router gesteuert werden. public isCollapsed = false;
// Dummy-Methode, damit der Code funktioniert
setActive(route: string): void { setActive(route: string): void {
this.activeRoute = route; this.activeRoute = route;
} }
// NEU: Methode, um den Zustand umzuschalten
toggleSidebar(): void {
this.isCollapsed = !this.isCollapsed;
}
} }

View File

@@ -1,7 +1,7 @@
/* ================================================================================= /* =================================================================================
GLOBALE STYLING-GRUNDLAGE (THEME & UTILITIES) GLOBALE STYLING-GRUNDLAGE (THEME & UTILITIES)
================================================================================== */ ================================================================================== */
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&display=swap"); /* @import url("https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&display=swap"); */
/* ================================================================================= /* =================================================================================
* 1. CSS-VARIABLEN (DESIGN TOKENS) * 1. CSS-VARIABLEN (DESIGN TOKENS)