diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts
index 3793525..1bab5f2 100644
--- a/src/app/app.routes.ts
+++ b/src/app/app.routes.ts
@@ -34,10 +34,7 @@ export const routes: Routes = [
title: 'Zugriff verweigert',
},
- // Regel 3: Fallback-Route (Wildcard)
- // JEDE ANDERE URL, die nicht von den obigen Regeln abgefangen wurde,
- // wird als ungültig betrachtet und ebenfalls zum Auth-Feature (und von dort zum Login) umgeleitet.
- // Das stellt sicher, dass Benutzer immer auf einer validen Seite landen.
+
{
path: '**',
component: NotFoundComponent,
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 0d2615c..4a982c3 100644
--- a/src/app/core/components/not-found/not-found.component.html
+++ b/src/app/core/components/not-found/not-found.component.html
@@ -1,4 +1,4 @@
-
-
\ No newline at end of file
+ -->
+
+404
\ No newline at end of file
diff --git a/src/app/features/demo/components/demo2/demo2.component.css b/src/app/features/demo/components/demo2/demo2.component.css
deleted file mode 100644
index e69de29..0000000
diff --git a/src/app/features/demo/components/demo2/demo2.component.html b/src/app/features/demo/components/demo2/demo2.component.html
index 1607bcb..d55d1ee 100644
--- a/src/app/features/demo/components/demo2/demo2.component.html
+++ b/src/app/features/demo/components/demo2/demo2.component.html
@@ -1,265 +1,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Jan
-
Feb
-
Mär
-
Apr
-
Mai
-
Jun
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Snackbar anzeigen
-
Erfolg! Ihre Änderungen wurden
- gespeichert.
-
Fehler! Bitte füllen Sie alle Felder
- aus.
-
-
-
-
-
-
-
- Profil Konto
-
-
- Lautstärke
-
-
-
- Dieser Inhalt wird dynamisch ein- und ausgeblendet. Lorem ipsum
- dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada
- lacus ex, sit amet blandit leo lobortis eget.
-
-
-
-
-
-
-
-
-
-
-
Inhalt erfolgreich geladen!
-
-
-
-
-
-
-
+
-
-
-
Sind Sie sicher? Diese Aktion kann nicht rückgängig gemacht werden.
-
-
-
Abbrechen
-
Ja, endgültig löschen
-
-
+
+
+
+
diff --git a/src/app/features/demo/components/demo2/demo2.component.ts b/src/app/features/demo/components/demo2/demo2.component.ts
index 35a7e61..00deffd 100644
--- a/src/app/features/demo/components/demo2/demo2.component.ts
+++ b/src/app/features/demo/components/demo2/demo2.component.ts
@@ -1,147 +1,157 @@
-import { Component, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
-import { SnackbarService } from '../../../../shared/services/snackbar.service';
-
-// Importieren ALLER wiederverwendbaren Komponenten, die im Template genutzt werden
-import { ButtonComponent } from '../../../../shared/components/ui/button/button.component';
import { CardComponent } from '../../../../shared/components/ui/card/card.component';
-import { ChipComponent } from '../../../../shared/components/ui/chip/chip.component';
-import { FormFieldComponent } from '../../../../shared/components/form/form-field/form-field.component';
-import { KpiCardComponent } from '../../../../shared/components/data-display/kpi-card/kpi-card.component';
-import { PageHeaderComponent } from '../../../../shared/components/layout/page-header/page-header.component';
-import { SlideToggleComponent } from '../../../../shared/components/form/slide-toggle/slide-toggle.component';
-import { StatusPillComponent } from '../../../../shared/components/ui/status-pill/status-pill.component';
-import { DialogComponent } from '../../../../shared/components/overlays/dialog/dialog.component';
+// Wir müssen KpiColor hier importieren, um es als Typ verwenden zu können
import {
- MenuComponent,
- MenuItem,
-} from '../../../../shared/components/overlays/menu/menu.component';
-import { AlertComponent } from '../../../../shared/components/ui/alert/alert.component';
+ KpiCardComponent,
+ KpiColor,
+} from '../../../../shared/components/data-display/kpi-card/kpi-card.component';
+import {
+ OrdersTableComponent,
+ Order,
+} from '../../../../shared/components/data-display/orders-table/orders-table.component';
import { PaginatorComponent } from '../../../../shared/components/data-display/paginator/paginator.component';
-import { SkeletonComponent } from '../../../../shared/components/ui/skeleton/skeleton.component';
-import { ExpansionPanelComponent } from '../../../../shared/components/layout/expansion-panel/expansion-panel.component';
-import { SidebarComponent } from '../../../../shared/components/layout/sidebar/sidebar.component';
-import { OrdersTableComponent, Order } from '../../../../shared/components/data-display/orders-table/orders-table.component';
-import { FormSelectComponent, SelectOption } from '../../../../shared/components/form/form-select/form-select.component';
-import { FormTextareaComponent } from '../../../../shared/components/form/form-textarea/form-textarea.component';
+// Wir definieren ein Interface für unsere KPI-Daten für Typsicherheit
+interface Kpi {
+ value: string;
+ label: string;
+ color: KpiColor; // <-- Hier verwenden wir den importierten Typ
+ iconName: string;
+}
+
@Component({
selector: 'app-demo2',
standalone: true,
imports: [
CommonModule,
- ButtonComponent,
CardComponent,
- ChipComponent,
- FormFieldComponent,
KpiCardComponent,
- PageHeaderComponent,
- SlideToggleComponent,
- StatusPillComponent,
- DialogComponent,
- MenuComponent,
- AlertComponent,
- PaginatorComponent,
- SkeletonComponent,
- ExpansionPanelComponent,
- SidebarComponent,
OrdersTableComponent,
- FormSelectComponent,
- FormTextareaComponent
+ PaginatorComponent,
],
templateUrl: './demo2.component.html',
- styleUrl: './demo2.component.css',
})
-export class Demo2Component implements OnInit {
- // Zustands-Variablen für diese Demo-Seite
- isLoading = true;
- isDialogOpen = false;
- // isComponentMenuOpen = false; // <--- DIESE ZEILE ENTFERNEN, DA SIE NICHT MEHR BENÖTIGT WIRD
-
- // Eigenschaften für den Paginator
- currentPage = 1;
- totalItems = 123;
- itemsPerPage = 10;
-
- actionMenuItems: MenuItem[] = [
+export class Demo2Component {
+ kpiData: Kpi[] = [
{
- label: 'Bearbeiten',
- action: () => this.snackbarService.show('Bearbeiten geklickt!'),
+ value: '€ 14.750',
+ label: 'Umsatz',
+ color: 'green',
+ iconName: 'placeholder',
},
{
- label: 'Kopieren',
- action: () => console.log('Kopieren geklickt!'),
+ value: '1.284',
+ label: 'Neue Nutzer',
+ color: 'blue',
+ iconName: 'placeholder',
},
{
- dividerBefore: true,
- label: 'Löschen',
- action: () => this.openDialog(), // Öffnet z.B. den Bestätigungs-Dialog
- isDanger: true,
+ value: '312',
+ label: 'Bestellungen',
+ color: 'orange',
+ iconName: 'placeholder',
+ },
+ {
+ value: '99.8%',
+ label: 'Verfügbarkeit',
+ color: 'purple',
+ iconName: 'placeholder',
},
];
- ordersData: Order[] = [
+ ordersData: Order[] = [
{
id: '10543',
- user: { name: 'Max Mustermann', email: 'max.mustermann@example.com', avatarUrl: 'https://i.pravatar.cc/40?u=max' },
+ user: {
+ name: 'Max Mustermann',
+ email: 'max.m@example.com',
+ avatarUrl: 'https://i.pravatar.cc/40?u=max',
+ },
amount: '€ 129,99',
status: 'success',
- statusText: 'Abgeschlossen'
+ statusText: 'Abgeschlossen',
},
{
id: '10542',
- user: { name: 'Erika Mustermann', email: 'erika.m@example.com', avatarUrl: 'https://i.pravatar.cc/40?u=erika' },
+ user: {
+ name: 'Erika Mustermann',
+ email: 'erika.m@example.com',
+ avatarUrl: 'https://i.pravatar.cc/40?u=erika',
+ },
amount: '€ 49,50',
status: 'warning',
- statusText: 'In Bearbeitung'
+ statusText: 'In Bearbeitung',
},
{
id: '10541',
- user: { name: 'Peter Pan', email: 'peter.pan@example.com', avatarUrl: 'https://i.pravatar.cc/40?u=peter' },
+ user: {
+ name: 'Peter Pan',
+ email: 'peter.p@example.com',
+ avatarUrl: 'https://i.pravatar.cc/40?u=peter',
+ },
amount: '€ 87,00',
status: 'danger',
- statusText: 'Storniert'
- }
+ statusText: 'Storniert',
+ },
+ {
+ id: '10543',
+ user: {
+ name: 'Max Mustermann',
+ email: 'max.m@example.com',
+ avatarUrl: 'https://i.pravatar.cc/40?u=max',
+ },
+ amount: '€ 129,99',
+ status: 'success',
+ statusText: 'Abgeschlossen',
+ },
+ {
+ id: '10542',
+ user: {
+ name: 'Erika Mustermann',
+ email: 'erika.m@example.com',
+ avatarUrl: 'https://i.pravatar.cc/40?u=erika',
+ },
+ amount: '€ 49,50',
+ status: 'warning',
+ statusText: 'In Bearbeitung',
+ },
+ {
+ id: '10541',
+ user: {
+ name: 'Peter Pan',
+ email: 'peter.p@example.com',
+ avatarUrl: 'https://i.pravatar.cc/40?u=peter',
+ },
+ amount: '€ 87,00',
+ status: 'danger',
+ statusText: 'Storniert',
+ },
];
- cityOptions: SelectOption[] = [
- { value: 'berlin', label: 'Berlin' },
- { value: 'munich', label: 'München' },
- { value: 'hamburg', label: 'Hamburg' }
- ];
+ // Eigenschaften für den Paginator
+ currentPage = 1;
+ totalItems = this.ordersData.length;
+ itemsPerPage = 10;
+ // --- EVENT-HANDLER FÜR DIE KIND-KOMPONENTEN ---
- constructor(private snackbarService: SnackbarService) {}
-
- ngOnInit(): void {
- setTimeout(() => {
- this.isLoading = false;
- }, 2000);
- }
-
- // Methoden für den Dialog
- openDialog(): void {
- this.isDialogOpen = true;
- }
- closeDialog(): void {
- this.isDialogOpen = false;
- }
-
- // Methode für den Snackbar-Trigger
- triggerSnackbar(): void {
- const time = new Date().toLocaleTimeString();
- this.snackbarService.show('Neues Ereignis um ' + time);
- }
-
- // Methode für den Paginator
onPageChange(newPage: number): void {
this.currentPage = newPage;
- console.log('Wechsle zu Seite:', newPage);
- // Hier würde die Logik zum Neuladen der Tabellendaten folgen
+ console.log('Seite gewechselt zu:', newPage);
+ // In einer echten Anwendung würden Sie hier die Daten neu laden
}
- handleDeleteOrder(orderId: string) {
+ handleDeleteOrder(orderId: string): void {
console.log('Lösche Bestellung mit ID:', orderId);
- this.openDialog(); // Öffnet z.B. den globalen Dialog
+ // Hier könnten Sie z.B. einen Bestätigungs-Dialog öffnen
+ }
+ handleViewDetails(orderId: string): void {
+ console.log('View Bestellung mit ID:', orderId);
+ // Hier könnten Sie z.B. einen Bestätigungs-Dialog öffnen
+ }
+ handleEditOrder(orderId: string): void {
+ console.log('Edit Bestellung mit ID:', orderId);
+ // Hier könnten Sie z.B. einen Bestätigungs-Dialog öffnen
}
}
diff --git a/src/app/shared/components/data-display/data-display.css b/src/app/shared/components/data-display/data-display.css
deleted file mode 100644
index 63c8f92..0000000
--- a/src/app/shared/components/data-display/data-display.css
+++ /dev/null
@@ -1,166 +0,0 @@
-/* WICHTIG: Diese Stile sollten aus der globalen styles.css HIERHER VERSCHOBEN werden. */
-:host {
- display: block;
-}
-
-.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;
- flex-shrink: 0;
- background-color: var(--color-surface);
-}
-
-.kpi-icon app-icon {
- width: 24px;
- height: 24px;
- color: #fff;
-}
-
-.icon-blue {
- background: linear-gradient(135deg, #3498db, #2980b9);
-}
-.icon-green {
- background: linear-gradient(135deg, #2ecc71, #27ae60);
-}
-.icon-orange {
- background: linear-gradient(135deg, #f39c12, #f1c40f);
-}
-.icon-purple {
- 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);
-}
-
-
-/* Verschieben Sie alle Tabellen-Stile aus styles.css hierher */
-:host {
- display: block;
-}
-
-.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;
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
-}
-.modern-table th.sortable:hover {
- color: var(--color-text);
-}
-.modern-table .sort-icon {
- 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;
-}
-.no-data-cell {
- text-align: center;
- padding: 2rem;
- color: var(--color-text-light);
-}
-
-/* Verschieben Sie diese Stile aus der globalen styles.css hierher */
-:host {
- display: block;
-}
-
-.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;
-}
\ No newline at end of file
diff --git a/src/app/shared/components/data-display/kpi-card/kpi-card.component.css b/src/app/shared/components/data-display/kpi-card/kpi-card.component.css
new file mode 100644
index 0000000..474073a
--- /dev/null
+++ b/src/app/shared/components/data-display/kpi-card/kpi-card.component.css
@@ -0,0 +1,56 @@
+:host {
+ display: block;
+}
+
+/* Die .kpi-card-Regel wird jetzt auf den Host angewendet, da das Template nur den Inhalt enthält */
+:host .kpi-card-content {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ padding: 1.5rem;
+}
+
+.kpi-icon {
+ width: 50px;
+ height: 50px;
+ border-radius: 50%;
+ display: grid;
+ place-items: center;
+ flex-shrink: 0;
+}
+
+.kpi-icon app-icon {
+ width: 24px;
+ height: 24px;
+ color: #fff; /* Standardfarbe für das Icon (currentColor) */
+}
+
+/* Farbvarianten für den Hintergrund des Icons */
+.icon-blue {
+ background: linear-gradient(135deg, #3498db, #2980b9);
+}
+.icon-green {
+ background: linear-gradient(135deg, #2ecc71, #27ae60);
+}
+.icon-orange {
+ background: linear-gradient(135deg, #f39c12, #f1c40f);
+}
+.icon-purple {
+ 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);
+}
\ No newline at end of file
diff --git a/src/app/shared/components/data-display/kpi-card/kpi-card.component.html b/src/app/shared/components/data-display/kpi-card/kpi-card.component.html
index 768cb10..6f818d4 100644
--- a/src/app/shared/components/data-display/kpi-card/kpi-card.component.html
+++ b/src/app/shared/components/data-display/kpi-card/kpi-card.component.html
@@ -1,4 +1,4 @@
-
+
@@ -16,4 +16,4 @@
{{ value }}
{{ label }}
-
+
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
index 9c1db25..bbbfe33 100644
--- 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
@@ -1,15 +1,16 @@
import { Component, Input } from '@angular/core';
import { CommonModule } from '@angular/common';
import { IconComponent } from '../../ui/icon/icon.component';
+import { CardComponent } from '../../ui/card/card.component';
-type KpiColor = 'blue' | 'green' | 'orange' | 'purple';
+export type KpiColor = 'blue' | 'green' | 'orange' | 'purple';
@Component({
selector: 'app-kpi-card',
standalone: true,
- imports: [CommonModule, IconComponent],
+ imports: [CommonModule, IconComponent,CardComponent],
templateUrl: './kpi-card.component.html',
- styleUrl: '../data-display.css',
+ styleUrl: './kpi-card.component.css',
})
export class KpiCardComponent {
@Input() value: string = '';
diff --git a/src/app/shared/components/data-display/orders-table/orders-table.component.css b/src/app/shared/components/data-display/orders-table/orders-table.component.css
new file mode 100644
index 0000000..bcc7205
--- /dev/null
+++ b/src/app/shared/components/data-display/orders-table/orders-table.component.css
@@ -0,0 +1,104 @@
+/* Das Host-Element der Komponente wird zum Flex-Container, um das Layout zu steuern */
+:host {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ overflow: hidden; /* Verhindert, dass die Komponente selbst überläuft */
+}
+
+/* Der Container für die Tabelle wird zum scrollbaren Bereich */
+.table-container {
+ overflow-x: auto;
+ flex-grow: 1;
+ min-width: 0; /* Erlaubt dem Flex-Item, kleiner als sein Inhalt zu werden */
+}
+
+.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;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.modern-table th.sortable:hover {
+ color: var(--color-text);
+}
+
+.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-hover);
+}
+
+.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;
+ text-align: right;
+}
+
+.mono {
+ font-family: 'Courier New', Courier, monospace;
+}
+
+.actions-cell {
+ display: flex;
+ justify-content: center;
+ gap: 0.5rem;
+}
+
+.no-data-cell {
+ text-align: center;
+ padding: 2rem;
+ color: var(--color-text-light);
+}
\ No newline at end of file
diff --git a/src/app/shared/components/data-display/orders-table/orders-table.component.html b/src/app/shared/components/data-display/orders-table/orders-table.component.html
index 9ff911d..0a21740 100644
--- a/src/app/shared/components/data-display/orders-table/orders-table.component.html
+++ b/src/app/shared/components/data-display/orders-table/orders-table.component.html
@@ -2,10 +2,7 @@
-
- Kunde
-
-
+ Kunde
Bestell-ID
Status
Betrag
@@ -14,46 +11,64 @@
-
+
-
+
{{ order.user.name }}
{{ order.user.email }}
- #{{ order.id }}
-
+ #{{ order.id }}
- {{ order.amount }}
+
+ {{
+ order.statusText
+ }}
+
+ {{ order.amount }}
-
+
-
+
-
+
-
-
+
Keine Bestellungen gefunden.
-
\ No newline at end of file
+
+
diff --git a/src/app/shared/components/data-display/orders-table/orders-table.component.ts b/src/app/shared/components/data-display/orders-table/orders-table.component.ts
index 3d5a5e7..9a53309 100644
--- a/src/app/shared/components/data-display/orders-table/orders-table.component.ts
+++ b/src/app/shared/components/data-display/orders-table/orders-table.component.ts
@@ -1,8 +1,8 @@
-import { Component, Input, Output, EventEmitter } from '@angular/core';
+import { Component, Input, Output, EventEmitter, SimpleChanges } from '@angular/core';
import { CommonModule } from '@angular/common';
import { StatusPillComponent } from '../../ui/status-pill/status-pill.component';
import { ButtonComponent } from '../../ui/button/button.component';
-import { IconComponent } from '../../ui/icon/icon.component';
+import { PaginatorComponent } from '../paginator/paginator.component';
// Interfaces für die Datenstruktur
export interface OrderUser {
@@ -24,19 +24,44 @@ export interface Order {
standalone: true,
imports: [
CommonModule,
-
+ StatusPillComponent,
ButtonComponent,
- IconComponent
+ PaginatorComponent
],
templateUrl: './orders-table.component.html',
- styleUrl: '../data-display.css'
+ styleUrl: './orders-table.component.css'
})
export class OrdersTableComponent {
// Nimmt die anzuzeigenden Bestelldaten entgegen
- @Input() orders: Order[] = [];
+ @Input() data: Order[] = [];
+ @Input() itemsPerPage = 5;
+
+ currentPage = 1;
+ displayedOrders: Order[] = [];
// Gibt Events für die Aktionen aus, mit der ID der betroffenen Bestellung
- @Output() viewDetails = new EventEmitter();
- @Output() editOrder = new EventEmitter();
- @Output() deleteOrder = new EventEmitter();
+ @Output() view = new EventEmitter();
+ @Output() edit = new EventEmitter();
+ @Output() delete = new EventEmitter();
+
+ ngOnChanges(changes: SimpleChanges): void {
+ // Wenn sich die Eingabedaten (allOrders) ändern, aktualisieren wir die Ansicht
+ if (changes['data']) {
+ this.updateDisplayedOrders();
+ }
+ }
+
+ // Wird aufgerufen, wenn der Paginator die Seite wechselt
+ onPageChange(newPage: number): void {
+ this.currentPage = newPage;
+ this.updateDisplayedOrders();
+ }
+
+ // Diese Methode berechnet, welcher Teil der Daten angezeigt werden soll
+ private updateDisplayedOrders(): void {
+ const startIndex = (this.currentPage - 1) * this.itemsPerPage;
+ const endIndex = startIndex + this.itemsPerPage;
+ this.displayedOrders = this.data.slice(startIndex, endIndex);
+ }
+
}
\ No newline at end of file
diff --git a/src/app/shared/components/data-display/paginator/paginator.component.css b/src/app/shared/components/data-display/paginator/paginator.component.css
new file mode 100644
index 0000000..914513a
--- /dev/null
+++ b/src/app/shared/components/data-display/paginator/paginator.component.css
@@ -0,0 +1,26 @@
+:host {
+ display: block;
+ /* Sorgt dafür, dass der Paginator im Flex-Layout der Tabelle nicht schrumpft */
+ flex-shrink: 0;
+}
+
+.paginator {
+ display: flex;
+ 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;
+ /* Schiebt diesen Text und die Controls garantiert nach rechts */
+ margin-left: auto;
+}
+
+.paginator-controls {
+ display: flex;
+ gap: 0.5rem;
+}
\ No newline at end of file
diff --git a/src/app/shared/components/data-display/paginator/paginator.component.ts b/src/app/shared/components/data-display/paginator/paginator.component.ts
index 6735e4d..9e67b9c 100644
--- a/src/app/shared/components/data-display/paginator/paginator.component.ts
+++ b/src/app/shared/components/data-display/paginator/paginator.component.ts
@@ -7,7 +7,7 @@ import { ButtonComponent } from '../../ui/button/button.component';
standalone: true,
imports: [CommonModule, ButtonComponent],
templateUrl: './paginator.component.html',
- styleUrl: '../data-display.css'
+ styleUrl: './paginator.component.css',
})
export class PaginatorComponent {
// --- EINGABEN von außen ---
@@ -26,7 +26,7 @@ export class PaginatorComponent {
get rangeStart(): number {
return (this.currentPage - 1) * this.itemsPerPage + 1;
}
-
+
get rangeEnd(): number {
const end = this.currentPage * this.itemsPerPage;
return end > this.totalItems ? this.totalItems : end;
@@ -43,4 +43,4 @@ export class PaginatorComponent {
this.pageChange.emit(this.currentPage + 1);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/app/shared/components/ui/button/button.component.html b/src/app/shared/components/ui/button/button.component.html
index 7a05149..2c034a2 100644
--- a/src/app/shared/components/ui/button/button.component.html
+++ b/src/app/shared/components/ui/button/button.component.html
@@ -10,6 +10,6 @@
[class.btn-icon-danger]="buttonType === 'icon-danger'"
[class.btn-full-width]="fullWidth"
>
-
+
diff --git a/src/app/shared/components/ui/card/card.component.css b/src/app/shared/components/ui/card/card.component.css
index e69de29..4f7972a 100644
--- a/src/app/shared/components/ui/card/card.component.css
+++ b/src/app/shared/components/ui/card/card.component.css
@@ -0,0 +1,20 @@
+.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;
+}
\ No newline at end of file
diff --git a/src/app/shared/components/ui/icon/icon.component.ts b/src/app/shared/components/ui/icon/icon.component.ts
index f117ae5..eeaa3e1 100644
--- a/src/app/shared/components/ui/icon/icon.component.ts
+++ b/src/app/shared/components/ui/icon/icon.component.ts
@@ -27,9 +27,8 @@ const ICON_SVG_KEY_PREFIX = 'icon-svg-';
styleUrl: './icon.component.css'
})
export class IconComponent implements OnChanges {
- @Input() name: string = '';
- // --- HIER IST DIE KORREKTUR: Umbenennung zu svgColor ---
- @Input() svgColor: string | null = null; // Farbe des SVG-Inhalts (Füllung/Linie)
+ @Input() iconName: string = '';
+ @Input() svgColor: string | null = null;
constructor(
private http: HttpClient,
@@ -41,13 +40,13 @@ export class IconComponent implements OnChanges {
ngOnChanges(changes: SimpleChanges): void {
// Überprüfe Änderungen an 'name' ODER 'svgColor'
- if ((changes['name'] && this.name) || (changes['svgColor'] && this.name)) {
+ if ((changes['name'] && this.iconName) || (changes['svgColor'] && this.iconName)) {
this.loadSvg();
}
}
private loadSvg(): void {
- const svgStateKey: StateKey = makeStateKey(ICON_SVG_KEY_PREFIX + this.name);
+ const svgStateKey: StateKey = makeStateKey(ICON_SVG_KEY_PREFIX + this.iconName);
const cachedSvg = this.transferState.get(svgStateKey, null);
this.el.nativeElement.innerHTML = '';
@@ -55,7 +54,7 @@ export class IconComponent implements OnChanges {
if (cachedSvg) {
this.setSvg(cachedSvg);
} else {
- this.http.get(`icons/${this.name}.svg`, { responseType: 'text' })
+ this.http.get(`icons/${this.iconName}.svg`, { responseType: 'text' })
.pipe(
tap(svg => {
if (!isPlatformBrowser(this.platformId)) {
diff --git a/src/styles.css b/src/styles.css
index 0b07cc6..cdd3810 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1,29 +1,36 @@
-
-/* src\styles.css */
/* =================================================================================
- FINALES & PRODUKTIONSREIFES STYLING-SYSTEM (VERSION 5.0)
+ GLOBALE STYLING-GRUNDLAGE (THEME & UTILITIES)
================================================================================== */
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&display=swap");
/* =================================================================================
* 1. CSS-VARIABLEN (DESIGN TOKENS)
+ * Dies ist die einzige Quelle der Wahrheit für Ihr Design.
* ================================================================================= */
:root {
+ /* Farbpalette */
--color-primary-gradient: linear-gradient(135deg, #3498db, #2980b9);
--color-primary: #3498db;
- --color-secondary: #2ecc71;
+ --color-primary-dark: #2980b9;
--color-danger: #e74c3c;
+ --color-success: #27ae60;
+ --color-warning: #f39c12;
+
+ /* Neutrale Farben (Light Mode) */
--color-text: #2c3e50;
--color-text-light: #7f8c8d;
--color-body-bg: #f4f7fa;
+ --color-body-bg-hover: #f2f3f5;
--color-surface: #ffffff;
--color-border: #e0e6ed;
- --glass-backdrop-filter: blur(10px);
- --glass-bg: rgba(255, 255, 255, 0.6);
+
+ /* Typografie */
--font-family-base: "Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI",
sans-serif;
--font-size-base: 16px;
--line-height-base: 1.6;
+
+ /* Abstände, Kanten & Schatten */
--border-radius-sm: 4px;
--border-radius-md: 8px;
--box-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.05);
@@ -38,7 +45,6 @@ body.dark-theme {
--color-body-bg: #1a202c;
--color-surface: #2d3748;
--color-border: #4a5568;
- --glass-bg: rgba(45, 55, 72, 0.6);
}
/* =================================================================================
@@ -51,6 +57,7 @@ body.dark-theme {
margin: 0;
padding: 0;
}
+
body {
font-family: var(--font-family-base);
font-size: var(--font-size-base);
@@ -60,616 +67,52 @@ body {
transition: background-color var(--transition-speed),
color var(--transition-speed);
}
+
+/* Globale Klasse, um das Scrollen zu unterbinden, wenn ein Overlay offen ist */
body.no-scroll {
overflow: hidden;
}
/* =================================================================================
- * 3. DASHBOARD-LAYOUT & SIDEBAR
+ * 3. GLOBALE HELFER- & UTILITY-KLASSEN
+ * Diese Klassen können überall in der Anwendung verwendet werden.
* ================================================================================= */
-.dashboard-container {
- display: flex;
- background-color: var(--color-body-bg);
+
+/* -- Textausrichtung -- */
+.text-right {
+ text-align: right !important;
+}
+.text-left {
+ text-align: left !important;
+}
+.text-center {
+ text-align: center !important;
}
-
-.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 Layout (da es ein grundlegendes Layout-Muster ist) -- */
.dashboard-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1.5rem;
}
+
+.grid-col-span-1 {
+ grid-column: span 1;
+}
+
.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);
+
+.grid-col-span-3 {
+ grid-column: span 3;
}
-/* =================================================================================
- * 6. UI-KOMPONENTEN-BIBLIOTHEK (STATISCH)
- * ================================================================================= */
-.component-grid {
- display: flex;
- flex-direction: column;
- gap: 2rem;
+.grid-col-span-4 {
+ grid-column: span 4;
}
-.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;
-}
-
-/* -- Autofill Fix in styles.css lassen-- */
-.form-input:-webkit-autofill ~ .form-label {
- top: 0;
- font-size: 0.8rem;
- color: var(--color-primary);
- border-radius: var(--border-radius-sm);
-}
-
-.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;
-}
+/* -- Tooltip (muss global sein, da es auf jedes Element angewendet werden kann) -- */
[data-tooltip] {
position: relative;
}
@@ -684,306 +127,21 @@ body.dark-theme .alert-danger {
padding: 0.25rem 0.75rem;
border-radius: var(--border-radius-sm);
font-size: 0.85rem;
+ font-weight: 500;
white-space: nowrap;
opacity: 0;
visibility: hidden;
- transition: opacity var(--transition-speed), transform var(--transition-speed);
+ pointer-events: none;
+ transition: opacity 0.2s ease-out, transform 0.2s ease-out;
}
[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
+ * 4. GLOBALE RESPONSIVITÄT
* ================================================================================= */
@media (max-width: 1200px) {
.dashboard-grid {
@@ -991,21 +149,8 @@ body.dark-theme .dialog-icon-container {
}
}
@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%;
- }
+ /* Stile für .main-content etc. gehören in die Layout-Komponente (z.B. demo2.component.css) */
}