diff --git a/src/app/app.component.css b/src/app/app.component.css
index ca98cf5..a878e6d 100644
--- a/src/app/app.component.css
+++ b/src/app/app.component.css
@@ -1,3 +1,5 @@
+/* src\app\app.component.css */
+
@import "tailwindcss";
/*
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 211245e..2057532 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,2 +1,5 @@
-
access-denied works!
++ Ihnen fehlen die erforderlichen Berechtigungen, um auf diese Seite + zuzugreifen. Bitte wenden Sie sich an einen Administrator, wenn Sie + glauben, dass dies ein Fehler ist. +
+ +cookie-consent works!
+ + \ No newline at end of file diff --git a/src/app/core/components/cookie-consent/cookie-consent.component.ts b/src/app/core/components/cookie-consent/cookie-consent.component.ts index 8fad3b5..f6ffca7 100644 --- a/src/app/core/components/cookie-consent/cookie-consent.component.ts +++ b/src/app/core/components/cookie-consent/cookie-consent.component.ts @@ -1,11 +1,53 @@ -import { Component } from '@angular/core'; +import { Component, OnInit, Inject, PLATFORM_ID } from '@angular/core'; +import { isPlatformBrowser, CommonModule } from '@angular/common'; // isPlatformBrowser importieren @Component({ selector: 'app-cookie-consent', - imports: [], + imports: [CommonModule], templateUrl: './cookie-consent.component.html', styleUrl: './cookie-consent.component.css' }) -export class CookieConsentComponent { +export class CookieConsentComponent implements OnInit { -} + isVisible = false; + private readonly consentKey = 'cookie_consent_status'; + private isBrowser: boolean; + + // Wir injizieren PLATFORM_ID, um die aktuelle Plattform (Browser/Server) zu ermitteln. + constructor(@Inject(PLATFORM_ID) private platformId: Object) { + // Speichere das Ergebnis in einer Eigenschaft, um es wiederverwenden zu können. + this.isBrowser = isPlatformBrowser(this.platformId); + } + + ngOnInit(): void { + // Wir führen die Prüfung nur aus, wenn der Code im Browser läuft. + if (this.isBrowser) { + this.checkConsent(); + } + } + + private checkConsent(): void { + const consent = localStorage.getItem(this.consentKey); + if (!consent) { + this.isVisible = true; + } + } + + accept(): void { + // Wir stellen sicher, dass wir localStorage nur im Browser schreiben. + if (this.isBrowser) { + localStorage.setItem(this.consentKey, 'accepted'); + this.isVisible = false; + console.log('Cookies wurden akzeptiert.'); + } + } + + decline(): void { + // Wir stellen sicher, dass wir localStorage nur im Browser schreiben. + if (this.isBrowser) { + localStorage.setItem(this.consentKey, 'declined'); + this.isVisible = false; + console.log('Cookies wurden abgelehnt.'); + } + } +} \ No newline at end of file diff --git a/src/app/core/components/not-found/not-found.component.css b/src/app/core/components/not-found/not-found.component.css index e69de29..11b3e1b 100644 --- a/src/app/core/components/not-found/not-found.component.css +++ b/src/app/core/components/not-found/not-found.component.css @@ -0,0 +1,77 @@ +/* src\app\core\components\not-found\not-found.component.css */ +:host { + display: block; + background-color: var(--color-body-bg); +} + +.not-found-container { + display: grid; + place-items: center; + min-height: 100vh; + padding: 1rem; +} + +.not-found-box { + position: relative; + max-width: 550px; + text-align: center; + padding: 2rem; + background-color: var(--color-surface); + border-radius: var(--border-radius-md); + border: 1px solid var(--color-border); + animation: fade-in 0.5s ease-out; +} + +.status-code { + position: absolute; + top: 1.5rem; + left: 50%; + transform: translateX(-50%); + font-size: 8rem; + font-weight: 900; + color: var(--color-border); + z-index: 0; + user-select: none; /* Text kann nicht markiert werden */ +} + +body.dark-theme .status-code { + color: rgba(255, 255, 255, 0.05); +} + +.title, .subtitle, .actions { + /* Positioniert die Inhalte VOR dem 404-Text */ + position: relative; + z-index: 1; +} + +.title { + padding-top: 6rem; /* Platz für den 404-Text schaffen */ + font-size: 2rem; + font-weight: 700; + color: var(--color-text); + margin-bottom: 0.75rem; +} + +.subtitle { + color: var(--color-text-light); + line-height: 1.7; + margin-bottom: 2.5rem; +} + +.actions { + display: flex; + justify-content: center; + gap: 1rem; + flex-wrap: wrap; +} + +.actions .btn { + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +@keyframes fade-in { + from { opacity: 0; transform: scale(0.95); } + to { opacity: 1; transform: scale(1); } +} \ No newline at end of file diff --git a/src/app/core/components/not-found/not-found.component.html b/src/app/core/components/not-found/not-found.component.html index 8071020..0d2615c 100644 --- a/src/app/core/components/not-found/not-found.component.html +++ b/src/app/core/components/not-found/not-found.component.html @@ -1 +1,23 @@ -not-found works!
++ Die von Ihnen angeforderte Seite konnte leider nicht gefunden werden. + Möglicherweise wurde sie verschoben, gelöscht oder die URL ist falsch. +
+ +kpi-card works!
diff --git a/src/app/shared/components/data-display/kpi-card/kpi-card.component.ts b/src/app/shared/components/data-display/kpi-card/kpi-card.component.ts new file mode 100644 index 0000000..1da19e9 --- /dev/null +++ b/src/app/shared/components/data-display/kpi-card/kpi-card.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-kpi-card', + imports: [], + templateUrl: './kpi-card.component.html', + styleUrl: './kpi-card.component.css' +}) +export class KpiCardComponent { + +} diff --git a/src/app/shared/components/form/form-field/form-field.component.css b/src/app/shared/components/form/form-field/form-field.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/form/form-field/form-field.component.html b/src/app/shared/components/form/form-field/form-field.component.html new file mode 100644 index 0000000..a532125 --- /dev/null +++ b/src/app/shared/components/form/form-field/form-field.component.html @@ -0,0 +1 @@ +form-field works!
diff --git a/src/app/shared/components/form/form-field/form-field.component.ts b/src/app/shared/components/form/form-field/form-field.component.ts new file mode 100644 index 0000000..aee467f --- /dev/null +++ b/src/app/shared/components/form/form-field/form-field.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-form-field', + imports: [], + templateUrl: './form-field.component.html', + styleUrl: './form-field.component.css' +}) +export class FormFieldComponent { + +} diff --git a/src/app/shared/components/form/slide-toggle/slide-toggle.component.css b/src/app/shared/components/form/slide-toggle/slide-toggle.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/form/slide-toggle/slide-toggle.component.html b/src/app/shared/components/form/slide-toggle/slide-toggle.component.html new file mode 100644 index 0000000..6627b58 --- /dev/null +++ b/src/app/shared/components/form/slide-toggle/slide-toggle.component.html @@ -0,0 +1 @@ +slide-toggle works!
diff --git a/src/app/shared/components/form/slide-toggle/slide-toggle.component.ts b/src/app/shared/components/form/slide-toggle/slide-toggle.component.ts new file mode 100644 index 0000000..3bcb3c5 --- /dev/null +++ b/src/app/shared/components/form/slide-toggle/slide-toggle.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-slide-toggle', + imports: [], + templateUrl: './slide-toggle.component.html', + styleUrl: './slide-toggle.component.css' +}) +export class SlideToggleComponent { + +} diff --git a/src/app/shared/components/layout/page-header/page-header.component.css b/src/app/shared/components/layout/page-header/page-header.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/layout/page-header/page-header.component.html b/src/app/shared/components/layout/page-header/page-header.component.html new file mode 100644 index 0000000..07f11f5 --- /dev/null +++ b/src/app/shared/components/layout/page-header/page-header.component.html @@ -0,0 +1 @@ +page-header works!
diff --git a/src/app/shared/components/layout/page-header/page-header.component.ts b/src/app/shared/components/layout/page-header/page-header.component.ts new file mode 100644 index 0000000..66b0637 --- /dev/null +++ b/src/app/shared/components/layout/page-header/page-header.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-page-header', + imports: [], + templateUrl: './page-header.component.html', + styleUrl: './page-header.component.css' +}) +export class PageHeaderComponent { + +} diff --git a/src/app/shared/components/layout/search-bar/search-bar.component.css b/src/app/shared/components/layout/search-bar/search-bar.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/layout/search-bar/search-bar.component.html b/src/app/shared/components/layout/search-bar/search-bar.component.html new file mode 100644 index 0000000..aac7a30 --- /dev/null +++ b/src/app/shared/components/layout/search-bar/search-bar.component.html @@ -0,0 +1 @@ +search-bar works!
diff --git a/src/app/shared/components/layout/search-bar/search-bar.component.ts b/src/app/shared/components/layout/search-bar/search-bar.component.ts new file mode 100644 index 0000000..1ab19c4 --- /dev/null +++ b/src/app/shared/components/layout/search-bar/search-bar.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-search-bar', + imports: [], + templateUrl: './search-bar.component.html', + styleUrl: './search-bar.component.css' +}) +export class SearchBarComponent { + +} diff --git a/src/app/shared/components/layout/user-profile/user-profile.component.css b/src/app/shared/components/layout/user-profile/user-profile.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/layout/user-profile/user-profile.component.html b/src/app/shared/components/layout/user-profile/user-profile.component.html new file mode 100644 index 0000000..fedcb8b --- /dev/null +++ b/src/app/shared/components/layout/user-profile/user-profile.component.html @@ -0,0 +1 @@ +user-profile works!
diff --git a/src/app/shared/components/layout/user-profile/user-profile.component.ts b/src/app/shared/components/layout/user-profile/user-profile.component.ts new file mode 100644 index 0000000..6b2c0d1 --- /dev/null +++ b/src/app/shared/components/layout/user-profile/user-profile.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-user-profile', + imports: [], + templateUrl: './user-profile.component.html', + styleUrl: './user-profile.component.css' +}) +export class UserProfileComponent { + +} diff --git a/src/app/shared/components/overlays/dialog/dialog.component.css b/src/app/shared/components/overlays/dialog/dialog.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/overlays/dialog/dialog.component.html b/src/app/shared/components/overlays/dialog/dialog.component.html new file mode 100644 index 0000000..80a1821 --- /dev/null +++ b/src/app/shared/components/overlays/dialog/dialog.component.html @@ -0,0 +1 @@ +dialog works!
diff --git a/src/app/shared/components/overlays/dialog/dialog.component.ts b/src/app/shared/components/overlays/dialog/dialog.component.ts new file mode 100644 index 0000000..6b029dc --- /dev/null +++ b/src/app/shared/components/overlays/dialog/dialog.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-dialog', + imports: [], + templateUrl: './dialog.component.html', + styleUrl: './dialog.component.css' +}) +export class DialogComponent { + +} diff --git a/src/app/shared/components/overlays/menu/menu.component.css b/src/app/shared/components/overlays/menu/menu.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/overlays/menu/menu.component.html b/src/app/shared/components/overlays/menu/menu.component.html new file mode 100644 index 0000000..136889f --- /dev/null +++ b/src/app/shared/components/overlays/menu/menu.component.html @@ -0,0 +1 @@ +menu works!
diff --git a/src/app/shared/components/overlays/menu/menu.component.ts b/src/app/shared/components/overlays/menu/menu.component.ts new file mode 100644 index 0000000..a35029d --- /dev/null +++ b/src/app/shared/components/overlays/menu/menu.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-menu', + imports: [], + templateUrl: './menu.component.html', + styleUrl: './menu.component.css' +}) +export class MenuComponent { + +} diff --git a/src/app/shared/snackbar/components/snackbar-container/snackbar-container.component.css b/src/app/shared/components/snackbar-container/snackbar-container.component.css similarity index 77% rename from src/app/shared/snackbar/components/snackbar-container/snackbar-container.component.css rename to src/app/shared/components/snackbar-container/snackbar-container.component.css index 1030818..1855134 100644 --- a/src/app/shared/snackbar/components/snackbar-container/snackbar-container.component.css +++ b/src/app/shared/components/snackbar-container/snackbar-container.component.css @@ -1,3 +1,4 @@ +/* src\app\shared\snackbar\components\snackbar-container\snackbar-container.component.css */ /* Stile, die NUR für den Container gelten */ .snackbar-container-wrapper { position: fixed; diff --git a/src/app/shared/snackbar/components/snackbar-container/snackbar-container.component.html b/src/app/shared/components/snackbar-container/snackbar-container.component.html similarity index 100% rename from src/app/shared/snackbar/components/snackbar-container/snackbar-container.component.html rename to src/app/shared/components/snackbar-container/snackbar-container.component.html diff --git a/src/app/shared/snackbar/components/snackbar-container/snackbar-container.component.ts b/src/app/shared/components/snackbar-container/snackbar-container.component.ts similarity index 100% rename from src/app/shared/snackbar/components/snackbar-container/snackbar-container.component.ts rename to src/app/shared/components/snackbar-container/snackbar-container.component.ts diff --git a/src/app/shared/snackbar/components/snackbar/snackbar.component.css b/src/app/shared/components/snackbar/snackbar.component.css similarity index 93% rename from src/app/shared/snackbar/components/snackbar/snackbar.component.css rename to src/app/shared/components/snackbar/snackbar.component.css index d6c00de..46a2209 100644 --- a/src/app/shared/snackbar/components/snackbar/snackbar.component.css +++ b/src/app/shared/components/snackbar/snackbar.component.css @@ -1,3 +1,4 @@ +/* src\app\shared\snackbar\components\snackbar\snackbar.component.css */ /* Stile, die NUR für eine einzelne Snackbar gelten */ :host { position: absolute; diff --git a/src/app/shared/snackbar/components/snackbar/snackbar.component.html b/src/app/shared/components/snackbar/snackbar.component.html similarity index 100% rename from src/app/shared/snackbar/components/snackbar/snackbar.component.html rename to src/app/shared/components/snackbar/snackbar.component.html diff --git a/src/app/shared/snackbar/components/snackbar/snackbar.component.ts b/src/app/shared/components/snackbar/snackbar.component.ts similarity index 100% rename from src/app/shared/snackbar/components/snackbar/snackbar.component.ts rename to src/app/shared/components/snackbar/snackbar.component.ts diff --git a/src/app/shared/components/ui/alert/alert.component.css b/src/app/shared/components/ui/alert/alert.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/ui/alert/alert.component.html b/src/app/shared/components/ui/alert/alert.component.html new file mode 100644 index 0000000..d0df429 --- /dev/null +++ b/src/app/shared/components/ui/alert/alert.component.html @@ -0,0 +1 @@ +alert works!
diff --git a/src/app/shared/components/ui/alert/alert.component.ts b/src/app/shared/components/ui/alert/alert.component.ts new file mode 100644 index 0000000..b55e120 --- /dev/null +++ b/src/app/shared/components/ui/alert/alert.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-alert', + imports: [], + templateUrl: './alert.component.html', + styleUrl: './alert.component.css' +}) +export class AlertComponent { + +} diff --git a/src/app/shared/components/ui/button/button.component.css b/src/app/shared/components/ui/button/button.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/ui/button/button.component.html b/src/app/shared/components/ui/button/button.component.html new file mode 100644 index 0000000..9cd155e --- /dev/null +++ b/src/app/shared/components/ui/button/button.component.html @@ -0,0 +1 @@ +button works!
diff --git a/src/app/shared/components/ui/button/button.component.ts b/src/app/shared/components/ui/button/button.component.ts new file mode 100644 index 0000000..0d76405 --- /dev/null +++ b/src/app/shared/components/ui/button/button.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-button', + imports: [], + templateUrl: './button.component.html', + styleUrl: './button.component.css' +}) +export class ButtonComponent { + +} diff --git a/src/app/shared/components/ui/card/card.component.css b/src/app/shared/components/ui/card/card.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/ui/card/card.component.html b/src/app/shared/components/ui/card/card.component.html new file mode 100644 index 0000000..f2fda25 --- /dev/null +++ b/src/app/shared/components/ui/card/card.component.html @@ -0,0 +1 @@ +card works!
diff --git a/src/app/shared/components/ui/card/card.component.ts b/src/app/shared/components/ui/card/card.component.ts new file mode 100644 index 0000000..1e41d97 --- /dev/null +++ b/src/app/shared/components/ui/card/card.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-card', + imports: [], + templateUrl: './card.component.html', + styleUrl: './card.component.css' +}) +export class CardComponent { + +} diff --git a/src/app/shared/components/ui/chip/chip.component.css b/src/app/shared/components/ui/chip/chip.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/ui/chip/chip.component.html b/src/app/shared/components/ui/chip/chip.component.html new file mode 100644 index 0000000..f31ccd3 --- /dev/null +++ b/src/app/shared/components/ui/chip/chip.component.html @@ -0,0 +1 @@ +chip works!
diff --git a/src/app/shared/components/ui/chip/chip.component.ts b/src/app/shared/components/ui/chip/chip.component.ts new file mode 100644 index 0000000..ad27066 --- /dev/null +++ b/src/app/shared/components/ui/chip/chip.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-chip', + imports: [], + templateUrl: './chip.component.html', + styleUrl: './chip.component.css' +}) +export class ChipComponent { + +} diff --git a/src/app/shared/components/ui/icon/icon.component.css b/src/app/shared/components/ui/icon/icon.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/ui/icon/icon.component.html b/src/app/shared/components/ui/icon/icon.component.html new file mode 100644 index 0000000..b43cd01 --- /dev/null +++ b/src/app/shared/components/ui/icon/icon.component.html @@ -0,0 +1 @@ +icon works!
diff --git a/src/app/shared/components/ui/icon/icon.component.ts b/src/app/shared/components/ui/icon/icon.component.ts new file mode 100644 index 0000000..f7e6ee3 --- /dev/null +++ b/src/app/shared/components/ui/icon/icon.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-icon', + imports: [], + templateUrl: './icon.component.html', + styleUrl: './icon.component.css' +}) +export class IconComponent { + +} diff --git a/src/app/shared/components/ui/status-pill/status-pill.component.css b/src/app/shared/components/ui/status-pill/status-pill.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/ui/status-pill/status-pill.component.html b/src/app/shared/components/ui/status-pill/status-pill.component.html new file mode 100644 index 0000000..b2cfdf4 --- /dev/null +++ b/src/app/shared/components/ui/status-pill/status-pill.component.html @@ -0,0 +1 @@ +status-pill works!
diff --git a/src/app/shared/components/ui/status-pill/status-pill.component.ts b/src/app/shared/components/ui/status-pill/status-pill.component.ts new file mode 100644 index 0000000..a1d3831 --- /dev/null +++ b/src/app/shared/components/ui/status-pill/status-pill.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-status-pill', + imports: [], + templateUrl: './status-pill.component.html', + styleUrl: './status-pill.component.css' +}) +export class StatusPillComponent { + +} diff --git a/src/app/shared/snackbar/services/snackbar.service.ts b/src/app/shared/services/snackbar.service.ts similarity index 100% rename from src/app/shared/snackbar/services/snackbar.service.ts rename to src/app/shared/services/snackbar.service.ts diff --git a/src/app/core/validators/password-match.validator.ts b/src/app/shared/validators/password-match.validator.ts similarity index 100% rename from src/app/core/validators/password-match.validator.ts rename to src/app/shared/validators/password-match.validator.ts diff --git a/src/styles.css b/src/styles.css index ecf4d61..5c263ce 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,3 +1,5 @@ + +/* src\styles.css */ /* ================================================================================= FINALES & PRODUKTIONSREIFES STYLING-SYSTEM (VERSION 5.0) ================================================================================== */ diff --git a/src/styles_OLD.css b/src/styles_OLD.css new file mode 100644 index 0000000..ecf4d61 --- /dev/null +++ b/src/styles_OLD.css @@ -0,0 +1,1068 @@ +/* ================================================================================= + FINALES & PRODUKTIONSREIFES STYLING-SYSTEM (VERSION 5.0) +================================================================================== */ +@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&display=swap"); + +/* ================================================================================= + * 1. CSS-VARIABLEN (DESIGN TOKENS) + * ================================================================================= */ +:root { + --color-primary-gradient: linear-gradient(135deg, #3498db, #2980b9); + --color-primary: #3498db; + --color-secondary: #2ecc71; + --color-danger: #e74c3c; + --color-text: #2c3e50; + --color-text-light: #7f8c8d; + --color-body-bg: #f4f7fa; + --color-surface: #ffffff; + --color-border: #e0e6ed; + --glass-backdrop-filter: blur(10px); + --glass-bg: rgba(255, 255, 255, 0.6); + --font-family-base: "Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", + sans-serif; + --font-size-base: 16px; + --line-height-base: 1.6; + --border-radius-sm: 4px; + --border-radius-md: 8px; + --box-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.05); + --box-shadow-md: 0 10px 15px -3px rgba(0, 0, 0, 0.1), + 0 4px 6px -2px rgba(0, 0, 0, 0.05); + --transition-speed: 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +body.dark-theme { + --color-text: #ecf0f1; + --color-text-light: #95a5a6; + --color-body-bg: #1a202c; + --color-surface: #2d3748; + --color-border: #4a5568; + --glass-bg: rgba(45, 55, 72, 0.6); +} + +/* ================================================================================= + * 2. GLOBALER RESET UND BASIS-STILE + * ================================================================================= */ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} +body { + font-family: var(--font-family-base); + font-size: var(--font-size-base); + line-height: var(--line-height-base); + color: var(--color-text); + background-color: var(--color-body-bg); + transition: background-color var(--transition-speed), + color var(--transition-speed); +} +body.no-scroll { + overflow: hidden; +} + +/* ================================================================================= + * 3. DASHBOARD-LAYOUT & SIDEBAR + * ================================================================================= */ +.dashboard-container { + display: flex; + background-color: var(--color-body-bg); +} +.sidebar { + width: 260px; + height: 100vh; + position: sticky; + top: 0; + display: flex; + flex-direction: column; + padding: 1.5rem; + background: var(--glass-bg); + backdrop-filter: var(--glass-backdrop-filter); + -webkit-backdrop-filter: var(--glass-backdrop-filter); + border-right: 1px solid var(--color-border); + transition: background-color var(--transition-speed), + border-color var(--transition-speed); +} +.sidebar-header { + margin-bottom: 2rem; +} +.sidebar-title { + font-size: 1.5rem; + font-weight: 900; +} +.sidebar-nav { + display: flex; + flex-direction: column; + gap: 0.5rem; + flex-grow: 1; +} +.sidebar-footer { + margin-top: auto; +} +.nav-item { + display: flex; + align-items: center; + gap: 1rem; + padding: 0.75rem 1rem; + border-radius: var(--border-radius-md); + color: var(--color-text-light); + font-weight: 500; + text-decoration: none; + transition: all var(--transition-speed); +} +.nav-item svg { + width: 20px; + height: 20px; + transition: stroke var(--transition-speed); +} +.nav-item:hover { + background-color: rgba(0, 0, 0, 0.05); + color: var(--color-text); +} +body.dark-theme .nav-item:hover { + background-color: rgba(255, 255, 255, 0.05); +} +.nav-item.active { + background: var(--color-primary-gradient); + color: #fff; + box-shadow: 0 4px 10px rgba(52, 152, 219, 0.4); +} +.nav-item.active svg { + stroke: #fff; +} + +/* ================================================================================= + * 4. HAUPTINHALT & HEADER + * ================================================================================= */ +.main-content { + flex-grow: 1; + padding: 2rem; + overflow-y: auto; +} +.main-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 2rem; +} +.search-bar { + position: relative; + width: 300px; +} +.search-bar svg { + position: absolute; + left: 1rem; + top: 50%; + transform: translateY(-50%); + color: var(--color-text-light); +} +.search-bar input { + width: 100%; + padding: 0.75rem 1rem 0.75rem 3rem; + border: 1px solid var(--color-border); + border-radius: var(--border-radius-md); + background-color: var(--color-surface); + color: var(--color-text); + font-size: 1rem; + transition: all var(--transition-speed); +} +.search-bar input:focus { + outline: none; + border-color: var(--color-primary); + box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.3); +} +.header-actions { + display: flex; + align-items: center; + gap: 1.5rem; +} +.user-profile img { + width: 40px; + height: 40px; + border-radius: 50%; + object-fit: cover; +} + +/* ================================================================================= + * 5. DASHBOARD GRID & KARTEN + * ================================================================================= */ +.dashboard-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1.5rem; +} +.grid-col-span-2 { + grid-column: span 2; +} +.card { + background-color: var(--color-surface); + border-radius: var(--border-radius-md); + box-shadow: var(--box-shadow-sm); + border: 1px solid var(--color-border); + transition: all var(--transition-speed); +} +.card:hover { + transform: translateY(-5px); + box-shadow: var(--box-shadow-md); +} +.card-header { + padding: 1rem 1.5rem; + border-bottom: 1px solid var(--color-border); + font-size: 1.1rem; + font-weight: 700; +} +.card-body { + padding: 1.5rem; +} +.kpi-card { + display: flex; + align-items: center; + gap: 1rem; + padding: 1.5rem; +} +.kpi-icon { + width: 50px; + height: 50px; + border-radius: 50%; + display: grid; + place-items: center; + color: #fff; +} +.kpi-icon svg { + width: 24px; + height: 24px; +} +.icon-sales { + background: linear-gradient(135deg, #2ecc71, #27ae60); +} +.icon-users { + background: linear-gradient(135deg, #3498db, #2980b9); +} +.icon-orders { + background: linear-gradient(135deg, #f39c12, #f1c40f); +} +.icon-performance { + background: linear-gradient(135deg, #9b59b6, #8e44ad); +} +.kpi-content { + display: flex; + flex-direction: column; +} +.kpi-value { + font-size: 1.75rem; + font-weight: 700; + color: var(--color-text); +} +.kpi-label { + font-size: 0.9rem; + color: var(--color-text-light); +} + +/* ================================================================================= + * 6. UI-KOMPONENTEN-BIBLIOTHEK (STATISCH) + * ================================================================================= */ +.component-grid { + display: flex; + flex-direction: column; + gap: 2rem; +} +.form-group-inline { + display: flex; + justify-content: space-between; + align-items: center; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.button-group { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 0.75rem; +} +.btn { + border: none; + border-radius: var(--border-radius-md); + cursor: pointer; + font-weight: 600; + padding: 0.6rem 1.2rem; + transition: all var(--transition-speed); +} +.btn:hover:not(:disabled) { + transform: translateY(-2px); + box-shadow: var(--box-shadow-md); +} +.btn-primary { + background: var(--color-primary-gradient); + color: #fff; + box-shadow: var(--box-shadow-sm); +} +.btn-secondary { + background-color: var(--color-surface); + color: var(--color-text); + border: 1px solid var(--color-border); +} +.btn-stroked { + background-color: transparent; + color: var(--color-primary); + border: 1px solid var(--color-primary); +} +.btn-flat { + background-color: transparent; + color: var(--color-primary); +} +.btn-icon { + background-color: transparent; + color: var(--color-text-light); + width: 40px; + height: 40px; + padding: 0; + border-radius: 50%; + display: grid; + place-items: center; +} +.btn-icon:hover { + background-color: var(--color-border); + box-shadow: none; +} +.btn-icon-danger:hover { + background-color: #fee2e2; + color: var(--color-danger); +} +body.dark-theme .btn-icon-danger:hover { + background-color: #991b1b; +} +.form-field { + position: relative; +} +.form-label { + position: absolute; + top: 50%; + transform: translateY(-50%); + left: 1rem; + color: var(--color-text-light); + background-color: var(--color-surface); + padding: 0 0.25rem; + transition: all 0.2s ease-out; + pointer-events: none; + border-radius: var(--border-radius-sm); +} +.form-input:focus ~ .form-label, +.form-input:not(:placeholder-shown) ~ .form-label { + top: 0; + font-size: 0.8rem; + color: var(--color-primary); +} +.form-input { + width: 100%; + padding: 0.85rem 1rem; + border: 1px solid var(--color-border); + border-radius: var(--border-radius-md); + background-color: var(--color-surface); + color: var(--color-text); + font-size: 1rem; + transition: border-color var(--transition-speed); +} +.form-input:focus { + outline: none; + border-color: var(--color-primary); +} +.slide-toggle-input { + display: none; +} +.slide-toggle-label { + display: block; + width: 44px; + height: 24px; + background-color: var(--color-border); + border-radius: 12px; + position: relative; + cursor: pointer; + transition: background-color var(--transition-speed); +} +.slide-toggle-label::before { + content: ""; + position: absolute; + width: 20px; + height: 20px; + border-radius: 50%; + background-color: #fff; + top: 2px; + left: 2px; + transition: transform var(--transition-speed); +} +.slide-toggle-input:checked + .slide-toggle-label { + background-color: var(--color-primary); +} +.slide-toggle-input:checked + .slide-toggle-label::before { + transform: translateX(20px); +} +.chip-set { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; +} +.chip { + display: inline-flex; + align-items: center; + padding: 0.25rem 0.75rem; + border-radius: 1rem; + background-color: var(--color-border); + color: var(--color-text); + font-size: 0.9rem; + cursor: pointer; + transition: all var(--transition-speed); +} +.chip:hover { + background-color: #d1d5db; +} +body.dark-theme .chip:hover { + background-color: #5a6578; +} +.chip.chip-active { + background-color: var(--color-primary); + color: #fff; +} +.chip-remove { + margin-left: 0.5rem; + font-weight: bold; + opacity: 0.5; +} +.chip-remove:hover { + opacity: 1; +} +.status-pill { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.25rem 0.75rem; + border-radius: 9999px; + font-size: 0.8rem; + font-weight: 500; + line-height: 1.4; + white-space: nowrap; + border: 1px solid transparent; + transition: all 0.2s ease-out; +} +.status-pill:hover { + transform: scale(1.05); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); +} +.status-pill::before { + content: ""; + width: 8px; + height: 8px; + border-radius: 50%; + background-color: currentColor; +} +.pill-success { + color: #15803d; + background-color: #ecfdf5; + border-color: #bbf7d0; +} +body.dark-theme .pill-success { + color: #a7f3d0; + background-color: #166534; + border-color: #22c55e; +} +.pill-warning { + color: #b45309; + background-color: #fffbeb; + border-color: #fde68a; +} +body.dark-theme .pill-warning { + color: #fde047; + background-color: #92400e; + border-color: #f59e0b; +} +.pill-danger { + color: #b91c1c; + background-color: #fef2f2; + border-color: #fecaca; +} +body.dark-theme .pill-danger { + color: #fca5a5; + background-color: #991b1b; + border-color: #ef4444; +} +.pill-info { + color: #1d4ed8; + background-color: #eff6ff; + border-color: #bfdbfe; +} +body.dark-theme .pill-info { + color: #93c5fd; + background-color: #1e40af; + border-color: #3b82f6; +} +.badge-container { + position: relative; + display: inline-block; +} +.badge-dot { + position: absolute; + top: -5px; + right: -8px; + min-width: 20px; + height: 20px; + padding: 0 6px; + border-radius: 10px; + background-color: var(--color-danger); + color: #fff; + font-size: 0.75rem; + font-weight: bold; + display: grid; + place-items: center; + border: 2px solid var(--color-surface); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} +.progress-bar { + width: 100%; + height: 8px; + background-color: var(--color-border); + border-radius: 4px; + overflow: hidden; +} +.progress-bar-value { + height: 100%; + background: var(--color-primary-gradient); + border-radius: 4px; + transition: width 0.5s ease-in-out; +} +.spinner-container { + display: grid; + place-items: center; +} +.progress-spinner { + width: 40px; + height: 40px; + border: 4px solid var(--color-border); + border-top-color: var(--color-primary); + border-radius: 50%; + animation: spin 1s linear infinite; +} +@keyframes spin { + to { + transform: rotate(360deg); + } +} +.alert { + padding: 1rem; + border-radius: var(--border-radius-md); + border: 1px solid transparent; +} +.alert-success { + background-color: #d1fae5; + color: #065f46; + border-color: #6ee7b7; +} +.alert-danger { + background-color: #fee2e2; + color: #991b1b; + border-color: #fca5a5; +} +body.dark-theme .alert-success { + background-color: #064e3b; + color: #a7f3d0; + border-color: #34d399; +} +body.dark-theme .alert-danger { + background-color: #7f1d1d; + color: #fecaca; + border-color: #f87171; +} +.table-container { + width: 100%; + overflow-x: auto; +} +.modern-table { + width: 100%; + border-collapse: collapse; + white-space: nowrap; +} +.modern-table thead th { + padding: 0.75rem 1.5rem; + color: var(--color-text-light); + font-size: 0.85rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + text-align: left; + border-bottom: 2px solid var(--color-border); +} +.modern-table th.sortable { + cursor: pointer; + position: relative; +} +.modern-table th.sortable:hover { + color: var(--color-text); +} +.modern-table .sort-icon { + color: var(--color-text-light); + position: absolute; + top: 50%; + right: 0.5rem; + transform: translateY(-50%); + opacity: 0.5; + transition: all var(--transition-speed); +} +.modern-table th.sortable:hover .sort-icon { + opacity: 1; +} +.modern-table tbody tr { + transition: background-color var(--transition-speed); + border-bottom: 1px solid var(--color-border); +} +.modern-table tbody tr:last-of-type { + border-bottom: none; +} +.modern-table tbody tr:hover { + background-color: var(--color-body-bg); +} +.modern-table tbody td { + padding: 1rem 1.5rem; + vertical-align: middle; +} +.user-cell { + display: flex; + align-items: center; + gap: 1rem; +} +.user-cell img { + width: 40px; + height: 40px; + border-radius: 50%; + object-fit: cover; +} +.user-name { + font-weight: 600; + color: var(--color-text); +} +.user-email { + font-size: 0.9rem; + color: var(--color-text-light); +} +.amount { + font-weight: 600; +} +.mono { + font-family: "Courier New", Courier, monospace; +} +.actions-cell { + display: flex; + justify-content: center; + gap: 0.5rem; +} +.tab-group { + display: flex; + border-bottom: 1px solid var(--color-border); +} +.tab-link { + padding: 0.75rem 1.25rem; + border: none; + background: none; + cursor: pointer; + font-size: 1rem; + color: var(--color-text-light); + border-bottom: 2px solid transparent; + margin-bottom: -1px; + transition: all var(--transition-speed); +} +.tab-link:hover { + color: var(--color-text); +} +.tab-link.active { + color: var(--color-primary); + border-bottom-color: var(--color-primary); +} +.tab-content { + padding: 1.5rem 0; +} +.divider { + border: none; + border-top: 1px solid var(--color-border); + margin: 1.5rem 0; +} +.expansion-panel { + border: 1px solid var(--color-border); + border-radius: var(--border-radius-md); + transition: box-shadow var(--transition-speed); +} +.expansion-panel.is-open { + box-shadow: var(--box-shadow-sm); +} +.expansion-panel-header { + background: none; + border: none; + font: inherit; + color: inherit; + text-align: left; + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + padding: 0.75rem 1.25rem; + font-size: 1rem; + font-weight: 500; + cursor: pointer; +} +.expansion-panel-icon { + transition: transform 0.3s ease-out; +} +.expansion-panel.is-open .expansion-panel-icon { + transform: rotate(180deg); +} +.expansion-panel-content-wrapper { + max-height: 0; + overflow: hidden; + transition: max-height 0.35s ease-in-out; +} +.expansion-panel.is-open .expansion-panel-content-wrapper { + max-height: 200px; +} +.expansion-panel-content { + padding: 0 1.25rem 1.25rem 1.25rem; +} +[data-tooltip] { + position: relative; +} +[data-tooltip]::after { + content: attr(data-tooltip); + position: absolute; + bottom: 100%; + left: 50%; + transform: translateX(-50%) translateY(-8px); + background-color: #2c3e50; + color: #fff; + padding: 0.25rem 0.75rem; + border-radius: var(--border-radius-sm); + font-size: 0.85rem; + white-space: nowrap; + opacity: 0; + visibility: hidden; + transition: opacity var(--transition-speed), transform var(--transition-speed); +} +[data-tooltip]:hover::after { + opacity: 1; + visibility: visible; + transform: translateX(-50%) translateY(-12px); +} +.chart-container { + display: flex; + justify-content: space-around; + align-items: flex-end; + height: 250px; + gap: 1rem; +} +.chart-bar { + width: 40px; + background: var(--color-primary-gradient); + border-radius: var(--border-radius-sm); + display: flex; + justify-content: center; + align-items: flex-end; + position: relative; + transition: height 0.5s ease-out; +} +.chart-bar span { + position: absolute; + bottom: -25px; + font-size: 0.8rem; + color: var(--color-text-light); +} +.stepper { + display: flex; + align-items: center; + width: 100%; +} +.step { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + color: var(--color-text-light); + font-weight: 500; + font-size: 0.9rem; +} +.step-icon { + width: 32px; + height: 32px; + border-radius: 50%; + border: 2px solid var(--color-border); + display: grid; + place-items: center; + font-weight: bold; + transition: all var(--transition-speed); +} +.step.step-active { + color: var(--color-primary); +} +.step.step-active .step-icon { + border-color: var(--color-primary); + color: var(--color-primary); +} +.step.step-complete { + color: var(--color-text); +} +.step.step-complete .step-icon { + background-color: var(--color-primary); + border-color: var(--color-primary); + color: #fff; +} +.step-connector { + flex-grow: 1; + height: 2px; + background-color: var(--color-border); + margin: 0 1rem; + transform: translateY(-12px); +} +.paginator { + display: flex; + justify-content: flex-end; + align-items: center; + gap: 1.5rem; + padding: 1rem; + border-top: 1px solid var(--color-border); +} +.paginator-info { + font-size: 0.9rem; + color: var(--color-text-light); + font-weight: 500; +} +.paginator-controls { + display: flex; + gap: 0.5rem; +} +.tree { + list-style: none; + padding-left: 1rem; +} +.tree-node { + position: relative; +} +.tree-node-label { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.4rem 0.5rem; + border-radius: var(--border-radius-sm); + cursor: pointer; +} +.tree-node-label:hover { + background-color: var(--color-body-bg); +} +.tree-node details > summary::-webkit-details-marker { + display: none; +} +.tree-node details > summary { + list-style: none; +} +.tree-node details > summary::before { + content: "▶"; + display: inline-block; + font-size: 0.7rem; + margin-right: 0.5rem; + transition: transform 0.2s ease-out; +} +.tree-node details[open] > summary::before { + transform: rotate(90deg); +} +.tree-node-children { + list-style: none; + padding-left: 1.75rem; + position: relative; +} +.tree-node-children::before { + content: ""; + position: absolute; + left: 8px; + top: 0; + bottom: 0; + width: 1px; + background-color: var(--color-border); +} +@keyframes skeleton-shimmer { + 0% { + background-position: -200px 0; + } + 100% { + background-position: calc(200px + 100%) 0; + } +} +.skeleton-item { + background-color: var(--color-border); + background-image: linear-gradient( + 90deg, + var(--color-border) 0px, + var(--color-body-bg) 40px, + var(--color-border) 80px + ); + background-size: 200px 100%; + background-repeat: no-repeat; + animation: skeleton-shimmer 1.5s infinite; +} +.skeleton-card { + display: flex; + align-items: center; + gap: 1rem; +} +.skeleton-avatar { + width: 50px; + height: 50px; + border-radius: 50%; +} +.skeleton-content { + flex-grow: 1; + display: flex; + flex-direction: column; + gap: 0.75rem; +} +.skeleton-line { + width: 100%; + height: 1rem; + border-radius: var(--border-radius-sm); +} + +/* ================================================================================= + * 7. OVERLAYS (DIALOG, MENÜ) + * ================================================================================= */ +.dialog-backdrop { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + display: grid; + place-items: center; + z-index: 1000; + backdrop-filter: blur(4px); +} +.dialog-container { + width: 100%; + max-width: 500px; + display: flex; + flex-direction: column; + box-shadow: var(--box-shadow-md); + border: 1px solid var(--color-border); +} +.dialog-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 1.5rem; + border-bottom: 1px solid var(--color-border); +} +.dialog-title { + font-size: 1.25rem; + font-weight: 600; + margin-bottom: 0; +} +.dialog-content { + padding: 1.5rem; + line-height: 1.7; + text-align: center; +} +.dialog-icon-container { + width: 64px; + height: 64px; + margin: 0 auto 1rem auto; + border-radius: 50%; + display: grid; + place-items: center; + background-color: #fee2e2; + color: var(--color-danger); +} +body.dark-theme .dialog-icon-container { + background-color: #7f1d1d; +} +.dialog-content p { + font-size: 1rem; + color: var(--color-text-light); +} +.dialog-content strong { + color: var(--color-text); + font-weight: 600; +} +.dialog-actions { + display: flex; + justify-content: flex-end; + gap: 0.75rem; + padding: 1rem 1.5rem; + border-top: 1px solid var(--color-border); + background-color: var(--color-body-bg); +} + +.menu-container { + position: relative; + display: inline-block; +} +.menu-container.menu-right .menu-panel { + left: auto; + right: 0; +} +.menu-panel { + position: absolute; + top: calc(100% + 8px); + left: 0; + min-width: 200px; + padding: 0.5rem 0; + z-index: 900; + border: 1px solid var(--color-border); + box-shadow: var(--box-shadow-md); + opacity: 0; + visibility: hidden; + transform: translateY(-10px); + transition: opacity var(--transition-speed), transform var(--transition-speed); +} +.menu-container.open .menu-panel { + opacity: 1; + visibility: visible; + transform: translateY(0); +} +.menu-item { + display: block; + padding: 0.6rem 1.25rem; + color: var(--color-text); + text-decoration: none; + font-size: 0.95rem; + transition: background-color 0.2s ease-out; +} +.menu-item:hover { + background-color: var(--color-body-bg); +} +.menu-item-danger { + color: var(--color-danger); +} + +/* ================================================================================= + * 8. RESPONSIVITÄT + * ================================================================================= */ +@media (max-width: 1200px) { + .dashboard-grid { + grid-template-columns: repeat(2, 1fr); + } +} +@media (max-width: 768px) { + .sidebar { + display: none; + } + .main-content { + padding: 1rem; + } + .dashboard-grid { + grid-template-columns: 1fr; + } + .main-header { + flex-direction: column; + gap: 1rem; + align-items: stretch; + } + .search-bar { + width: 100%; + } +}