aufräumen

This commit is contained in:
Tizian.Breuch
2025-09-26 11:30:14 +02:00
parent c066476cc3
commit 7d10ecf1cc
47 changed files with 503 additions and 253 deletions

View File

@@ -0,0 +1 @@
/* src\app\features\demo\components\demo\demo.component.css */

View File

@@ -0,0 +1,801 @@
<!-- =================================================================================
FINALES & VOLLSTÄNDIGES DEMO-LAYOUT (VERSION 3.0)
================================================================================== -->
<div class="dashboard-container">
<!-- =================================================================== -->
<!-- 1. SIDEBAR -->
<!-- =================================================================== -->
<aside class="sidebar">
<div class="sidebar-header"><h1 class="sidebar-title">CustomDash</h1></div>
<nav class="sidebar-nav">
<a href="#" class="nav-item active"
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
<polyline points="9 22 9 12 15 12 15 22"></polyline></svg
><span>Übersicht</span></a
>
<a href="#" class="nav-item"
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="18" y1="20" x2="18" y2="10"></line>
<line x1="12" y1="20" x2="12" y2="4"></line>
<line x1="6" y1="20" x2="6" y2="14"></line></svg
><span>Analysen</span></a
>
<a href="#" class="nav-item"
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"
></path></svg
><span>Berichte</span></a
>
</nav>
<div class="sidebar-footer">
<a href="#" class="nav-item"
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M10.3 21.7c.9.9 2.5.9 3.4 0l6.9-6.9c.9-.9.9-2.5 0-3.4l-6.9-6.9c-.9-.9-2.5-.9-3.4 0l-6.9 6.9c-.9.9-.9-2.5 0 3.4l6.9 6.9z"
></path></svg
><span>Einstellungen</span></a
>
</div>
</aside>
<!-- =================================================================== -->
<!-- 2. HAUPTINHALT -->
<!-- =================================================================== -->
<main class="main-content">
<header class="main-header">
<div class="search-bar">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg
><input type="text" placeholder="Dashboard durchsuchen..." />
</div>
<div class="header-actions">
<div class="theme-switcher">
<label for="theme-toggle">Dark Mode</label
><input
type="checkbox"
id="theme-toggle"
class="slider-checkbox"
(change)="toggleTheme()"
[checked]="isDarkMode"
/>
</div>
<div class="user-profile">
<img src="https://i.pravatar.cc/40" alt="User Avatar" />
</div>
</div>
</header>
<!-- Haupt-Grid für alle Dashboard-Inhalte und Komponenten -->
<div class="dashboard-grid">
<!-- Sektion: KPI-Karten -->
<div class="card kpi-card">
<div class="kpi-icon icon-sales">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="12" y1="1" x2="12" y2="23"></line>
<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path>
</svg>
</div>
<div class="kpi-content">
<span class="kpi-value">€ 14.750</span
><span class="kpi-label">Umsatz (Monat)</span>
</div>
</div>
<div class="card kpi-card">
<div class="kpi-icon icon-users">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
</div>
<div class="kpi-content">
<span class="kpi-value">1.284</span
><span class="kpi-label">Neue Nutzer</span>
</div>
</div>
<div class="card kpi-card">
<div class="kpi-icon icon-orders">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"></path>
<line x1="3" y1="6" x2="21" y2="6"></line>
<path d="M16 10a4 4 0 0 1-8 0"></path>
</svg>
</div>
<div class="kpi-content">
<span class="kpi-value">312</span
><span class="kpi-label">Bestellungen</span>
</div>
</div>
<div class="card kpi-card">
<div class="kpi-icon icon-performance">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon>
</svg>
</div>
<div class="kpi-content">
<span class="kpi-value">99.8%</span
><span class="kpi-label">Verfügbarkeit</span>
</div>
</div>
<!-- Sektion: Diagramm -->
<section class="card grid-col-span-2">
<h3 class="card-header">Umsatzentwicklung</h3>
<div class="card-body chart-container">
<div class="chart-bar" style="height: 60%"><span>Jan</span></div>
<div class="chart-bar" style="height: 75%"><span>Feb</span></div>
<div class="chart-bar" style="height: 50%"><span>Mär</span></div>
<div class="chart-bar" style="height: 85%"><span>Apr</span></div>
<div class="chart-bar" style="height: 90%"><span>Mai</span></div>
<div class="chart-bar" style="height: 65%"><span>Jun</span></div>
</div>
</section>
<!-- Sektion: Datentabelle -->
<section class="card grid-col-span-2">
<h3 class="card-header">Letzte Bestellungen</h3>
<div class="table-container">
<table class="modern-table">
<thead>
<tr>
<th class="sortable">
<span>Kunde</span
><svg
class="sort-icon"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M8 3v18l8-9L8 3z"
transform="rotate(90 12 12)"
></path>
</svg>
</th>
<th>Bestell-ID</th>
<th>Status</th>
<th class="text-right">Betrag</th>
<th class="text-center">Aktionen</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="user-cell">
<img
src="https://i.pravatar.cc/40?u=max"
alt="Avatar Max Mustermann"
/>
<div>
<div class="user-name">Max Mustermann</div>
<div class="user-email">max.mustermannATexample.com</div>
</div>
</div>
</td>
<td><span class="mono">#10543</span></td>
<td>
<span class="status-pill pill-success">Abgeschlossen</span>
</td>
<td class="text-right amount">€ 129,99</td>
<td class="actions-cell">
<button class="btn btn-icon" data-tooltip="Details anzeigen">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"
></path>
<circle cx="12" cy="12" r="3"></circle>
</svg></button
><button class="btn btn-icon" data-tooltip="Bearbeiten">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"
></path>
<path
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
></path>
</svg></button
><button
class="btn btn-icon btn-icon-danger"
data-tooltip="Löschen"
(click)="openDialog()"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="3 6 5 6 21 6"></polyline>
<path
d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
></path>
<line x1="10" y1="11" x2="10" y2="17"></line>
<line x1="14" y1="11" x2="14" y2="17"></line>
</svg>
</button>
</td>
</tr>
<tr>
<td>
<div class="user-cell">
<img
src="https://i.pravatar.cc/40?u=erika"
alt="Avatar Erika Mustermann"
/>
<div>
<div class="user-name">Erika Mustermann</div>
<div class="user-email">erika.mATexample.com</div>
</div>
</div>
</td>
<td><span class="mono">#10542</span></td>
<td>
<span class="status-pill pill-warning">In Bearbeitung</span>
</td>
<td class="text-right amount">€ 49,50</td>
<td class="actions-cell">
<button class="btn btn-icon" data-tooltip="Details anzeigen">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"
></path>
<circle cx="12" cy="12" r="3"></circle>
</svg></button
><button class="btn btn-icon" data-tooltip="Bearbeiten">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"
></path>
<path
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
></path>
</svg></button
><button
class="btn btn-icon btn-icon-danger"
data-tooltip="Löschen"
(click)="openDialog()"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="3 6 5 6 21 6"></polyline>
<path
d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
></path>
<line x1="10" y1="11" x2="10" y2="17"></line>
<line x1="14" y1="11" x2="14" y2="17"></line>
</svg>
</button>
</td>
</tr>
<tr>
<td>
<div class="user-cell">
<img
src="https://i.pravatar.cc/40?u=peter"
alt="Avatar Peter Pan"
/>
<div>
<div class="user-name">Peter Pan</div>
<div class="user-email">peter.panATexample.com</div>
</div>
</div>
</td>
<td><span class="mono">#10541</span></td>
<td><span class="status-pill pill-danger">Storniert</span></td>
<td class="text-right amount">€ 87,00</td>
<td class="actions-cell">
<button class="btn btn-icon" data-tooltip="Details anzeigen">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"
></path>
<circle cx="12" cy="12" r="3"></circle>
</svg></button
><button class="btn btn-icon" data-tooltip="Bearbeiten">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"
></path>
<path
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
></path>
</svg></button
><button
class="btn btn-icon btn-icon-danger"
data-tooltip="Löschen"
(click)="openDialog()"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="3 6 5 6 21 6"></polyline>
<path
d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
></path>
<line x1="10" y1="11" x2="10" y2="17"></line>
<line x1="14" y1="11" x2="14" y2="17"></line>
</svg>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</section>
<!-- BEGINN DER UI-KOMPONENTEN-BIBLIOTHEK -->
<section class="card grid-col-span-2">
<h3 class="card-header">Moderne Formular-Elemente</h3>
<div class="card-body component-grid">
<div class="form-field">
<input
type="text"
class="form-input"
id="name"
placeholder=" "
/><label for="name" class="form-label">Name</label>
</div>
<div class="form-field">
<select class="form-input" id="city">
<option>Berlin</option>
<option>München</option></select
><label for="city" class="form-label">Stadt</label>
</div>
<div class="form-field">
<textarea
class="form-input"
id="message"
placeholder=" "
rows="2"
></textarea
><label for="message" class="form-label">Nachricht</label>
</div>
<div class="form-group-inline">
<label>Benachrichtigungen</label>
<div class="slide-toggle">
<input
type="checkbox"
id="toggle-1"
class="slide-toggle-input"
/><label for="toggle-1" class="slide-toggle-label"></label>
</div>
</div>
</div>
</section>
<section class="card grid-col-span-2">
<h3 class="card-header">Buttons, Chips & Interaktion</h3>
<div class="card-body component-grid">
<div class="button-group">
<button class="btn btn-primary">Primary</button
><button class="btn btn-secondary">Secondary</button
><button class="btn btn-stroked">Stroked</button
><button class="btn btn-flat">Flat</button
><button class="btn btn-icon" data-tooltip="Favorit">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"
></path>
</svg>
</button>
</div>
<div class="chip-set">
<span class="chip"
>Technologie<span class="chip-remove">&times;</span></span
><span class="chip"
>Design<span class="chip-remove">&times;</span></span
><span class="chip chip-active"
>Angular<span class="chip-remove">&times;</span></span
>
</div>
<div class="badge-showcase">
<div class="badge-container">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
<path d="M13.73 21a2 2 0 0 1-3.46 0"></path></svg
><span class="badge-dot">3</span>
</div>
</div>
<div class="menu-container" [class.open]="isMenuOpen">
<button
class="btn btn-secondary"
(click)="isMenuOpen = !isMenuOpen"
>
Menü öffnen
</button>
<div class="menu-panel card">
<a href="#" class="menu-item">Bearbeiten</a
><a href="#" class="menu-item">Kopieren</a>
<hr class="divider" />
<a href="#" class="menu-item menu-item-danger">Löschen</a>
</div>
</div>
</div>
</section>
<section class="card grid-col-span-2">
<h3 class="card-header">Indikatoren & Feedback</h3>
<div class="button-group" style="align-items: center">
<button class="btn btn-secondary" (click)="triggerSnackbar()">
Snackbar anzeigen
</button>
</div>
</section>
<section class="card grid-col-span-2">
<h3 class="card-header">Navigation & Layout</h3>
<div class="card-body component-grid">
<div class="tab-group">
<button class="tab-link active">Profil</button
><button class="tab-link">Konto</button
><button class="tab-link">Sicherheit</button>
</div>
<div class="tab-content">
<p>Hier wäre der Inhalt für den aktiven Tab "Profil".</p>
</div>
<hr class="divider" />
<div class="expansion-panel" [class.is-open]="isPanelOpen">
<!-- Das <summary> wird zu einem <button> für bessere Kontrolle & Zugänglichkeit -->
<button
type="button"
class="expansion-panel-header"
(click)="isPanelOpen = !isPanelOpen"
>
<span>Weitere Details anzeigen</span>
<svg
class="expansion-panel-icon"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
ViewBox="0 0 0 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
<!-- Der Inhalt bleibt strukturell gleich -->
<div class="expansion-panel-content-wrapper">
<div class="expansion-panel-content">
Hier steht der Inhalt, der ein- und ausgeklappt werden kann.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Suspendisse malesuada lacus ex, sit amet blandit leo lobortis
eget.
</div>
</div>
</div>
<div class="stepper">
<div class="step step-complete">
<div class="step-icon"></div>
<span>Profil</span>
</div>
<div class="step-connector"></div>
<div class="step step-active">
<div class="step-icon">2</div>
<span>Konto</span>
</div>
<div class="step-connector"></div>
<div class="step">
<div class="step-icon">3</div>
<span>Abschluss</span>
</div>
</div>
</div>
</section>
<section class="card grid-col-span-2">
<h3 class="card-header">Hierarchische Daten & Paginierung</h3>
<div class="card-body component-grid">
<ul class="tree">
<li class="tree-node">
<details open>
<summary class="tree-node-label">Ordner 1</summary>
<ul class="tree-node-children">
<li class="tree-node">
<span class="tree-node-label">Datei 1.1</span>
</li>
<li class="tree-node">
<span class="tree-node-label">Datei 1.2</span>
</li>
</ul>
</details>
</li>
<li class="tree-node">
<details>
<summary class="tree-node-label">Ordner 2</summary>
<ul class="tree-node-children">
<li class="tree-node">
<span class="tree-node-label">Datei 2.1</span>
</li>
</ul>
</details>
</li>
</ul>
<div class="paginator">
<span class="paginator-info">1-10 von 100</span>
<div class="paginator-controls">
<button class="btn btn-icon">&lt;</button
><button class="btn btn-icon">&gt;</button>
</div>
</div>
</div>
</section>
<section class="card grid-col-span-2">
<h3 class="card-header">Ladezustände (Skeleton)</h3>
<div class="card-body component-grid">
<div class="skeleton-card card">
<div class="skeleton-item skeleton-avatar"></div>
<div class="skeleton-content">
<div class="skeleton-item skeleton-line"></div>
<div class="skeleton-item skeleton-line" style="width: 70%"></div>
</div>
</div>
</div>
</section>
</div>
<!-- Ende .dashboard-grid -->
</main>
<!-- =================================================================== -->
<!-- 3. OVERLAYS (Dynamisch, außerhalb des Haupt-Layouts) -->
<!-- =================================================================== -->
<div
class="dialog-backdrop"
*ngIf="isDialogOpen"
(click)="closeDialog()"
[@fade]
>
<div
class="dialog-container card"
(click)="$event.stopPropagation()"
[@slideIn]
>
<div class="dialog-header">
<h3 class="dialog-title">Aktion bestätigen</h3>
<button
class="btn btn-icon"
(click)="closeDialog()"
data-tooltip="Schließen"
>
&times;
</button>
</div>
<div class="dialog-content">
<div class="dialog-icon-container">
<svg
xmlns="http://www.w3.org/2000/svg"
width="48"
height="48"
ViewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"
></path>
<line x1="12" y1="9" x2="12" y2="13"></line>
<line x1="12" y1="17" x2="12.01" y2="17"></line>
</svg>
</div>
<p>
Sind Sie sicher, dass Sie die Bestellung
<strong>#10543</strong> löschen möchten? Diese Aktion kann nicht
rückgängig gemacht werden.
</p>
</div>
<div class="dialog-actions">
<button class="btn btn-stroked" (click)="closeDialog()">
Abbrechen</button
><button class="btn btn-danger" (click)="closeDialog()">
Ja, endgültig löschen
</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,122 @@
import { Component, Renderer2, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { trigger, transition, style, animate } from '@angular/animations';
import { SnackbarService } from '../../../../shared/services/snackbar.service';
@Component({
selector: 'app-demo1',
// Hinzugefügt für moderne, eigenständige Komponenten
imports: [CommonModule],
templateUrl: './demo1.component.html',
styleUrl: './demo1.component.css',
animations: [
trigger('fade', [
transition(':enter', [
style({ opacity: 0 }),
animate('300ms ease-out', style({ opacity: 1 })),
]),
transition(':leave', [animate('300ms ease-in', style({ opacity: 0 }))]),
]),
trigger('slideIn', [
transition(':enter', [
style({ transform: 'translateY(20px)', opacity: 0 }),
animate(
'300ms ease-out',
style({ transform: 'translateY(0)', opacity: 1 })
),
]),
transition(':leave', [
animate(
'300ms ease-in',
style({ transform: 'translateY(20px)', opacity: 0 })
),
]),
]),
trigger('fadeSlideIn', [
transition(':enter', [
style({ bottom: '-100px', opacity: 0 }),
animate('300ms ease-out', style({ bottom: '2rem', opacity: 1 })),
]),
transition(':leave', [
animate('300ms ease-in', style({ bottom: '-100px', opacity: 0 })),
]),
]),
],
})
export class Demo1Component implements OnInit {
// ===================================================================
// 1. ZUSTANDS-EIGENSCHAFTEN DER KOMPONENTE
// ===================================================================
isDarkMode = false;
isLoading = true; // Startet im Ladezustand, um Skeleton Loader zu zeigen
isDialogOpen = false;
isSnackbarVisible = false;
isMenuOpen = false; // Hinzugefügt für das interaktive Menü
isPanelOpen = false;
snackbarMessage = '';
private snackbarTimer: any;
// Eindeutige Variablen für jedes Menü
isComponentMenuOpen = false;
// ===================================================================
// 2. DEPENDENCY INJECTION & LIFECYCLE
// ===================================================================
constructor(
private renderer: Renderer2,
private snackbarService: SnackbarService
) {}
/**
* Wird einmalig nach der Initialisierung der Komponente aufgerufen.
* Perfekt, um initiale Daten zu laden.
*/
ngOnInit(): void {
// Simuliert das Laden von Daten. Nach 2 Sekunden wird der Inhalt angezeigt.
setTimeout(() => {
this.isLoading = false;
}, 2000);
}
// ===================================================================
// 3. METHODEN FÜR DAS THEME-MANAGEMENT
// ===================================================================
toggleTheme(): void {
this.isDarkMode = !this.isDarkMode;
if (this.isDarkMode) {
this.renderer.addClass(document.body, 'dark-theme');
} else {
this.renderer.removeClass(document.body, 'dark-theme');
}
}
// ===================================================================
// 4. METHODEN FÜR DEN DIALOG
// ===================================================================
openDialog(): void {
this.isDialogOpen = true;
this.renderer.addClass(document.body, 'no-scroll');
}
closeDialog(): void {
this.isDialogOpen = false;
this.renderer.removeClass(document.body, 'no-scroll');
}
// demo.component.ts
// ===================================================================
// FINALE, ROBUSTE METHODEN FÜR DIE SNACKBAR (VERSION 5.0)
// ===================================================================
triggerSnackbar(): void {
const time = new Date().toLocaleTimeString();
this.snackbarService.show('Neues Ereignis um ' + time);
}
}

View File

@@ -0,0 +1,228 @@
<main>
<div class="grid-col-span-4">
<app-page-header></app-page-header>
</div>
<!-- <app-kpi-card
*ngFor="let kpi of kpiData"
[value]="kpi.value"
[label]="kpi.label"
[color]="kpi.color"
[iconName]="kpi.iconName"
>
</app-kpi-card> -->
<div class="grid-col-span-4">
<!-- <app-form-group title="Data-display Components">
<app-orders-table
[data]="ordersData"
[itemsPerPage]="5"
(view)="handleViewDetails($event)"
(edit)="handleEditOrder($event)"
(delete)="handleDeleteOrder($event)"
>
</app-orders-table>
</app-form-group> -->
</div>
<div class="grid-col-span-2">
<form [formGroup]="demoForm">
<app-form-group
title="Form Components 1"
description="Diese Informationen sind öffentlich sichtbar."
>
<app-form-select
label="Land"
[options]="countryOptions"
[(ngModel)]="selectedCountry"
[ngModelOptions]="{standalone: true}"> <!-- Wichtig für die Mischung von ngModel und formGroup -->
</app-form-select>
<!-- Diese Felder verwenden jetzt formControlName -->
<app-form-field
label="Benutzername"
type="text"
formControlName="username">
</app-form-field>
<app-form-field
label="E-Mail-Adresse"
type="email"
formControlName="email">
</app-form-field>
<app-form-field
label="Passwort"
type="password"
formControlName="password">
</app-form-field>
<app-form-textarea
label="Biografie"
[rows]="5"
[(ngModel)]="biografie"
[ngModelOptions]="{standalone: true}">
</app-form-textarea>
</app-form-group>
</form>
</div>
<div class="grid-col-span-2">
<app-form-group
title="Form Components 2"
description="Diese Informationen sind öffentlich sichtbar."
>
<app-slide-toggle
labelPosition="right"
label="Push-Benachrichtigungen"
[(ngModel)]="benachrichtigungenAktiv"
name="notificationsToggle"
></app-slide-toggle>
<app-slide-toggle
label="Dark Mode"
[ngModel]="darkModeAktiv"
(ngModelChange)="onDarkModeChange($event)"
name="mainDarkModeToggle"
></app-slide-toggle>
<app-slide-toggle
label="Privates Profil (Feature gesperrt)"
[(ngModel)]="profilIstPrivat"
name="privacyToggle"
[disabled]="true"
></app-slide-toggle>
</app-form-group>
</div>
<div class="grid-col-span-2">
<app-form-group
title="Layout Components"
description="Diese Informationen sind öffentlich sichtbar."
>
<app-expansion-panel title="Weitere Details anzeigen...">
Dieser Inhalt wird jetzt von einer wiederverwendbaren Komponente
gesteuert. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</app-expansion-panel>
</app-form-group>
</div>
<div class="grid-col-span-2">
<app-form-group
title="Layout Components"
description="Diese Informationen sind öffentlich sichtbar."
>
<h3 card-header>Umsatzentwicklung</h3>
<!-- Das card-body dient als Container für das Diagramm -->
<div class="chart-wrapper">
<ngx-charts-bar-vertical
[results]="salesData"
scheme="vivid"
[xAxis]="true"
[yAxis]="true"
[legend]="false"
[showXAxisLabel]="true"
[showYAxisLabel]="true"
xAxisLabel="Monat"
yAxisLabel="Umsatz in €">
</ngx-charts-bar-vertical>
</div>
</app-form-group>
</div>
<div class="grid-col-span-2">
<app-form-group title="Button Components" description="UI Components">
<!-- Sektion 1: Standard-Buttons -->
<div class="button-group">
<app-button buttonType="primary" tooltip="Primäre Aktion"
>Primary</app-button
>
<app-button buttonType="secondary" tooltip="Sekundäre Aktion"
>Secondary</app-button
>
<app-button buttonType="stroked" tooltip="Hervorgehoben"
>Stroked</app-button
>
<app-button buttonType="flat" tooltip="Weniger wichtige Aktion"
>Flat</app-button
>
</div>
<!-- Sektion 2: Buttons mit Icon und Text -->
<div class="button-group">
<app-button buttonType="primary" iconName="edit">Bearbeiten</app-button>
<app-button buttonType="secondary" iconName="shopping_bag"
>Zum Warenkorb</app-button
>
</div>
<!-- Sektion 3: Reine Icon-Buttons -->
<div class="button-group">
<app-button
buttonType="icon"
tooltip="Favorit hinzufügen"
iconName="favorite"
svgColor="red"
></app-button>
<app-button
buttonType="icon"
tooltip="Details anzeigen"
iconName="eye"
></app-button>
<app-button
buttonType="icon"
tooltip="Benutzer"
iconName="group"
></app-button>
<app-button
buttonType="icon"
tooltip="Performance"
iconName="bolt"
></app-button>
<app-button
buttonType="icon-danger"
tooltip="Löschen"
iconName="delete"
></app-button>
</div>
<!-- Sektion 4: Paginator Icon-Buttons (Beispiel) -->
<div class="button-group">
<app-button
buttonType="icon"
tooltip="Zurück"
iconName="chevron_backward"
></app-button>
<app-button
buttonType="icon"
tooltip="Weiter"
iconName="chevron_forward"
></app-button>
</div>
<!-- Sektion 5: Deaktivierte Zustände -->
<div class="button-group">
<app-button buttonType="primary" [disabled]="true"
>Deaktiviert</app-button
>
<app-button
buttonType="icon"
iconName="money"
[disabled]="true"
tooltip="Nicht verfügbar"
></app-button>
</div>
<div class="chip-set">
<app-chip label="Technologie" [removable]="true"></app-chip>
<app-chip label="Angular" [active]="true" [removable]="true"></app-chip>
</div>
</app-form-group>
</div>
</main>

View File

@@ -0,0 +1,325 @@
import {
Component,
Inject,
OnInit,
PLATFORM_ID,
Renderer2,
} from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { CommonModule } from '@angular/common';
import { CardComponent } from '../../../../shared/components/ui/card/card.component';
// Wir müssen KpiColor hier importieren, um es als Typ verwenden zu können
import { KpiCardComponent } from '../../../components/dashboard/kpi-card/kpi-card.component';
import { KpiColor } from '../../../../core/types/dashboard';
import {
OrdersTableComponent,
} from '../../../../shared/components/data-display/orders-table/orders-table.component';
import { FormFieldComponent } from '../../../../shared/components/form/form-field/form-field.component';
import { FormGroupComponent } from '../../../../shared/components/form/form-group/form-group.component';
import {
FormSelectComponent,
SelectOption,
} from '../../../../shared/components/form/form-select/form-select.component';
import {
FormBuilder,
FormGroup,
FormsModule,
Validators,
} from '@angular/forms';
import { FormTextareaComponent } from '../../../../shared/components/form/form-textarea/form-textarea.component';
import { SlideToggleComponent } from '../../../../shared/components/form/slide-toggle/slide-toggle.component';
import { isPlatformBrowser } from '@angular/common';
import { ExpansionPanelComponent } from '../../../../shared/components/layout/expansion-panel/expansion-panel.component';
import { PageHeaderComponent } from '../../../../shared/components/layout/page-header/page-header.component';
import { ButtonComponent } from '../../../../shared/components/ui/button/button.component';
import { ChipComponent } from '../../../../shared/components/ui/chip/chip.component';
import { ReactiveFormsModule } from '@angular/forms';
import { NgxChartsModule } from '@swimlane/ngx-charts';
// 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,
KpiCardComponent,
OrdersTableComponent,
FormGroupComponent,
FormFieldComponent,
FormSelectComponent,
FormsModule,
FormTextareaComponent,
SlideToggleComponent,
ExpansionPanelComponent,
PageHeaderComponent,
ButtonComponent,
ChipComponent,
ReactiveFormsModule,
NgxChartsModule
],
templateUrl: './demo2.component.html',
})
export class Demo2Component {
demoForm: FormGroup;
// kpiData: Kpi[] = [
// {
// value: '€ 14.750',
// label: 'Umsatz',
// color: 'green',
// iconName: 'placeholder',
// },
// {
// value: '1.284',
// label: 'Neue Nutzer',
// color: 'blue',
// iconName: 'placeholder',
// },
// {
// value: '312',
// label: 'Bestellungen',
// color: 'orange',
// iconName: 'placeholder',
// },
// {
// value: '99.8%',
// label: 'Verfügbarkeit',
// color: 'purple',
// iconName: 'placeholder',
// },
// ];
// ordersData: Order[] = [
// {
// 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',
// },
// {
// 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',
// },
// {
// 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',
// },
// ];
aktuellesPasswort: any = '';
neuesPasswort: any = '';
selectedCountry: string | null = null;
countryOptions: SelectOption[] = [
{ value: 'de', label: 'Deutschland' },
{ value: 'at', label: 'Österreich' },
{ value: 'ch', label: 'Schweiz' },
];
biografie: string =
'Dies ist eine Beispiel-Biografie, die über mehrere Zeilen gehen kann.';
benachrichtigungenAktiv: boolean = true;
profilIstPrivat: boolean = false;
private readonly darkModeKey = 'app-dark-mode-setting';
darkModeAktiv: boolean = false;
// +++ NEUE EIGENSCHAFTEN FÜR DAS DIAGRAMM +++
// 1. Die Daten für das Diagramm im von ngx-charts erwarteten Format
salesData = [
{ name: 'Jan', value: 12500 },
{ name: 'Feb', value: 14750 },
{ name: 'Mär', value: 11800 },
{ name: 'Apr', value: 18600 },
{ name: 'Mai', value: 21500 },
{ name: 'Jun', value: 19800 }
];
// 2. (Optional) Ein benutzerdefiniertes Farbschema, das zu Ihrem Theme passt
customColorScheme = {
domain: ['#3498db', '#2980b9', '#2ecc71', '#27ae60', '#f39c12', '#f1c40f']
};
constructor(
private renderer: Renderer2,
@Inject(DOCUMENT) private document: Document,
@Inject(PLATFORM_ID) private platformId: Object,
private fb: FormBuilder
) {
this.demoForm = this.fb.group({
username: [''], // Entspricht dem [(value)]="benutzername"
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required]]
});
}
ngOnInit(): void {
this.loadThemeSetting();
}
private loadThemeSetting(): void {
if (isPlatformBrowser(this.platformId)) {
try {
const storedValue = localStorage.getItem(this.darkModeKey);
// Setze den Zustand der Komponente basierend auf dem gespeicherten Wert.
this.darkModeAktiv = storedValue === 'true';
} catch (e) {
console.error('Could not access localStorage:', e);
}
}
// Wende das Theme an - entweder den Standardwert (false) oder den geladenen Wert.
this.updateTheme(this.darkModeAktiv);
}
onDarkModeChange(isEnabled: boolean): void {
this.darkModeAktiv = isEnabled;
// --- KORREKTUR 2: Speichere die neue Einstellung ---
if (isPlatformBrowser(this.platformId)) {
try {
localStorage.setItem(this.darkModeKey, String(isEnabled));
} catch (e) {
console.error('Could not write to localStorage:', e);
}
}
// Wende die visuelle Änderung an.
this.updateTheme(isEnabled);
}
// This method is CORRECT. It just needs to be called.
private updateTheme(isEnabled: boolean): void {
if (isEnabled) {
this.renderer.addClass(this.document.body, 'dark-theme');
} else {
this.renderer.removeClass(this.document.body, 'dark-theme');
}
}
handleDeleteOrder(orderId: string): void {
console.log('Lösche Bestellung mit ID:', orderId);
// 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
}
}

View File

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

View File

@@ -0,0 +1,29 @@
import { Routes } from '@angular/router';
import { Demo1Component } from './components/demo1/demo1.component';
import { Demo2Component } from './components/demo2/demo2.component';
export const DEMO_ROUTES: Routes = [
{
// Diese Route ist relativ zu '/demo'.
// Ein leerer Pfad leitet direkt weiter zu '/demo/1'.
path: '',
redirectTo: '1',
pathMatch: 'full',
},
{
// Diese Route passt auf '/demo/1' und lädt die Komponente genau einmal.
path: '1',
component: Demo1Component,
title: 'Demo1',
},
{
// Diese Route passt auf '/demo/1' und lädt die Komponente genau einmal.
path: '2',
component: Demo2Component,
title: 'Demo2',
},
// Hier könntest du weitere Routen wie '2', '3' etc. hinzufügen,
// die andere Komponenten laden.
// { path: '2', component: AnotherDemoComponent },
];