styling
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
<router-outlet style="height: 100vh; width: 100vw;"></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
<app-snackbar-container></app-snackbar-container>
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
|
import { SnackbarContainerComponent } from './shared/snackbar/components/snackbar-container/snackbar-container.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
imports: [RouterOutlet],
|
imports: [RouterOutlet,SnackbarContainerComponent],
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrl: './app.component.css'
|
styleUrl: './app.component.css'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
<!-- FINALE demo.component.html -->
|
<!-- =================================================================================
|
||||||
|
FINALES & VOLLSTÄNDIGES DEMO-LAYOUT (VERSION 3.0)
|
||||||
|
================================================================================== -->
|
||||||
<div class="dashboard-container">
|
<div class="dashboard-container">
|
||||||
<!-- =================================================================== -->
|
<!-- =================================================================== -->
|
||||||
<!-- SIDEBAR -->
|
<!-- 1. SIDEBAR -->
|
||||||
<!-- =================================================================== -->
|
<!-- =================================================================== -->
|
||||||
<aside class="sidebar">
|
<aside class="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header"><h1 class="sidebar-title">CustomDash</h1></div>
|
||||||
<h1 class="sidebar-title">CustomDash</h1>
|
|
||||||
</div>
|
|
||||||
<nav class="sidebar-nav">
|
<nav class="sidebar-nav">
|
||||||
<a href="#" class="nav-item active">
|
<a href="#" class="nav-item active"
|
||||||
<svg
|
><svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
@@ -21,12 +21,11 @@
|
|||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
>
|
>
|
||||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
|
<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>
|
<polyline points="9 22 9 12 15 12 15 22"></polyline></svg
|
||||||
</svg>
|
><span>Übersicht</span></a
|
||||||
<span>Übersicht</span>
|
>
|
||||||
</a>
|
<a href="#" class="nav-item"
|
||||||
<a href="#" class="nav-item">
|
><svg
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
@@ -39,12 +38,11 @@
|
|||||||
>
|
>
|
||||||
<line x1="18" y1="20" x2="18" y2="10"></line>
|
<line x1="18" y1="20" x2="18" y2="10"></line>
|
||||||
<line x1="12" y1="20" x2="12" y2="4"></line>
|
<line x1="12" y1="20" x2="12" y2="4"></line>
|
||||||
<line x1="6" y1="20" x2="6" y2="14"></line>
|
<line x1="6" y1="20" x2="6" y2="14"></line></svg
|
||||||
</svg>
|
><span>Analysen</span></a
|
||||||
<span>Analysen</span>
|
>
|
||||||
</a>
|
<a href="#" class="nav-item"
|
||||||
<a href="#" class="nav-item">
|
><svg
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
@@ -57,14 +55,13 @@
|
|||||||
>
|
>
|
||||||
<path
|
<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"
|
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>
|
></path></svg
|
||||||
</svg>
|
><span>Berichte</span></a
|
||||||
<span>Berichte</span>
|
>
|
||||||
</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="sidebar-footer">
|
<div class="sidebar-footer">
|
||||||
<a href="#" class="nav-item">
|
<a href="#" class="nav-item"
|
||||||
<svg
|
><svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
@@ -77,15 +74,14 @@
|
|||||||
>
|
>
|
||||||
<path
|
<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"
|
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>
|
></path></svg
|
||||||
</svg>
|
><span>Einstellungen</span></a
|
||||||
<span>Einstellungen</span>
|
>
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- =================================================================== -->
|
<!-- =================================================================== -->
|
||||||
<!-- HAUPTINHALT -->
|
<!-- 2. HAUPTINHALT -->
|
||||||
<!-- =================================================================== -->
|
<!-- =================================================================== -->
|
||||||
<main class="main-content">
|
<main class="main-content">
|
||||||
<header class="main-header">
|
<header class="main-header">
|
||||||
@@ -102,14 +98,13 @@
|
|||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
>
|
>
|
||||||
<circle cx="11" cy="11" r="8"></circle>
|
<circle cx="11" cy="11" r="8"></circle>
|
||||||
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
<line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg
|
||||||
</svg>
|
><input type="text" placeholder="Dashboard durchsuchen..." />
|
||||||
<input type="text" placeholder="Dashboard durchsuchen..." />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<div class="theme-switcher">
|
<div class="theme-switcher">
|
||||||
<label for="theme-toggle">Dark Mode</label>
|
<label for="theme-toggle">Dark Mode</label
|
||||||
<input
|
><input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="theme-toggle"
|
id="theme-toggle"
|
||||||
class="slider-checkbox"
|
class="slider-checkbox"
|
||||||
@@ -132,7 +127,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -154,7 +149,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -178,7 +173,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -201,7 +196,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -230,24 +225,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- =================================================================== -->
|
<!-- Sektion: Datentabelle -->
|
||||||
<!-- Sektion: Datentabelle (Final & Korrigiert) -->
|
|
||||||
<!-- =================================================================== -->
|
|
||||||
<section class="card grid-col-span-2">
|
<section class="card grid-col-span-2">
|
||||||
<h3 class="card-header">Letzte Bestellungen</h3>
|
<h3 class="card-header">Letzte Bestellungen</h3>
|
||||||
|
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<table class="modern-table">
|
<table class="modern-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="sortable">
|
<th class="sortable">
|
||||||
<span>Kunde</span>
|
<span>Kunde</span
|
||||||
<svg
|
><svg
|
||||||
class="sort-icon"
|
class="sort-icon"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="16"
|
width="16"
|
||||||
height="16"
|
height="16"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -267,7 +259,6 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<!-- Zeile 1 -->
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="user-cell">
|
<div class="user-cell">
|
||||||
@@ -282,7 +273,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td><span class="mono">#10543</span></td>
|
<td><span class="mono">#10543</span></td>
|
||||||
<!-- HIER WURDE DIE KORREKTE STATUS-PILLE HINZUGEFÜGT -->
|
|
||||||
<td>
|
<td>
|
||||||
<span class="status-pill pill-success">Abgeschlossen</span>
|
<span class="status-pill pill-success">Abgeschlossen</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -293,7 +283,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="20"
|
width="20"
|
||||||
height="20"
|
height="20"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -304,14 +294,13 @@
|
|||||||
d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"
|
d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"
|
||||||
></path>
|
></path>
|
||||||
<circle cx="12" cy="12" r="3"></circle>
|
<circle cx="12" cy="12" r="3"></circle>
|
||||||
</svg>
|
</svg></button
|
||||||
</button>
|
><button class="btn btn-icon" data-tooltip="Bearbeiten">
|
||||||
<button class="btn btn-icon" data-tooltip="Bearbeiten">
|
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="20"
|
width="20"
|
||||||
height="20"
|
height="20"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -324,11 +313,33 @@
|
|||||||
<path
|
<path
|
||||||
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
|
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
|
||||||
></path>
|
></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>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<!-- Zeile 2 -->
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="user-cell">
|
<div class="user-cell">
|
||||||
@@ -343,7 +354,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td><span class="mono">#10542</span></td>
|
<td><span class="mono">#10542</span></td>
|
||||||
<!-- HIER WURDE DIE KLASSE ZU status-pill GEÄNDERT -->
|
|
||||||
<td>
|
<td>
|
||||||
<span class="status-pill pill-warning">In Bearbeitung</span>
|
<span class="status-pill pill-warning">In Bearbeitung</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -354,7 +364,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="20"
|
width="20"
|
||||||
height="20"
|
height="20"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -365,14 +375,13 @@
|
|||||||
d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"
|
d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"
|
||||||
></path>
|
></path>
|
||||||
<circle cx="12" cy="12" r="3"></circle>
|
<circle cx="12" cy="12" r="3"></circle>
|
||||||
</svg>
|
</svg></button
|
||||||
</button>
|
><button class="btn btn-icon" data-tooltip="Bearbeiten">
|
||||||
<button class="btn btn-icon" data-tooltip="Bearbeiten">
|
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="20"
|
width="20"
|
||||||
height="20"
|
height="20"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -385,11 +394,33 @@
|
|||||||
<path
|
<path
|
||||||
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
|
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
|
||||||
></path>
|
></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>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<!-- Zeile 3 -->
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="user-cell">
|
<div class="user-cell">
|
||||||
@@ -404,7 +435,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td><span class="mono">#10541</span></td>
|
<td><span class="mono">#10541</span></td>
|
||||||
<!-- HIER WURDE DIE KLASSE ZU status-pill GEÄNDERT -->
|
|
||||||
<td><span class="status-pill pill-danger">Storniert</span></td>
|
<td><span class="status-pill pill-danger">Storniert</span></td>
|
||||||
<td class="text-right amount">€ 87,00</td>
|
<td class="text-right amount">€ 87,00</td>
|
||||||
<td class="actions-cell">
|
<td class="actions-cell">
|
||||||
@@ -413,7 +443,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="20"
|
width="20"
|
||||||
height="20"
|
height="20"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -424,14 +454,13 @@
|
|||||||
d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"
|
d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"
|
||||||
></path>
|
></path>
|
||||||
<circle cx="12" cy="12" r="3"></circle>
|
<circle cx="12" cy="12" r="3"></circle>
|
||||||
</svg>
|
</svg></button
|
||||||
</button>
|
><button class="btn btn-icon" data-tooltip="Bearbeiten">
|
||||||
<button class="btn btn-icon" data-tooltip="Bearbeiten">
|
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="20"
|
width="20"
|
||||||
height="20"
|
height="20"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -444,65 +473,29 @@
|
|||||||
<path
|
<path
|
||||||
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
|
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
|
||||||
></path>
|
></path>
|
||||||
</svg>
|
</svg></button
|
||||||
</button>
|
><button
|
||||||
</td>
|
class="btn btn-icon btn-icon-danger"
|
||||||
</tr>
|
data-tooltip="Löschen"
|
||||||
<!-- Zeile 4 (Bonus) -->
|
(click)="openDialog()"
|
||||||
<tr>
|
>
|
||||||
<td>
|
|
||||||
<div class="user-cell">
|
|
||||||
<img
|
|
||||||
src="https://i.pravatar.cc/40?u=anna"
|
|
||||||
alt="Avatar Anna Kurz"
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<div class="user-name">Anna Kurz</div>
|
|
||||||
<div class="user-email">anna.kurzATexample.com</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td><span class="mono">#10540</span></td>
|
|
||||||
<!-- HIER WURDE DIE KLASSE ZU status-pill GEÄNDERT -->
|
|
||||||
<td><span class="status-pill pill-info">Versendet</span></td>
|
|
||||||
<td class="text-right amount">€ 214,20</td>
|
|
||||||
<td class="actions-cell">
|
|
||||||
<button class="btn btn-icon" data-tooltip="Details anzeigen">
|
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="20"
|
width="20"
|
||||||
height="20"
|
height="20"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
>
|
>
|
||||||
|
<polyline points="3 6 5 6 21 6"></polyline>
|
||||||
<path
|
<path
|
||||||
d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"
|
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>
|
|
||||||
<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>
|
></path>
|
||||||
|
<line x1="10" y1="11" x2="10" y2="17"></line>
|
||||||
|
<line x1="14" y1="11" x2="14" y2="17"></line>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
@@ -552,7 +545,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="card grid-col-span-2">
|
<section class="card grid-col-span-2">
|
||||||
<h3 class="card-header">Buttons, Chips & Badges</h3>
|
<h3 class="card-header">Buttons, Chips & Interaktion</h3>
|
||||||
<div class="card-body component-grid">
|
<div class="card-body component-grid">
|
||||||
<div class="button-group">
|
<div class="button-group">
|
||||||
<button class="btn btn-primary">Primary</button
|
<button class="btn btn-primary">Primary</button
|
||||||
@@ -564,7 +557,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -592,7 +585,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -604,33 +597,33 @@
|
|||||||
><span class="badge-dot">3</span>
|
><span class="badge-dot">3</span>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="card grid-col-span-2">
|
<section class="card grid-col-span-2">
|
||||||
<h3 class="card-header">Indikatoren & Feedback</h3>
|
<h3 class="card-header">Indikatoren & Feedback</h3>
|
||||||
<div class="card-body component-grid">
|
<div class="button-group" style="align-items: center">
|
||||||
<div>
|
<button class="btn btn-secondary" (click)="triggerSnackbar()">
|
||||||
<label>Fortschritt</label>
|
Snackbar anzeigen
|
||||||
<div class="progress-bar">
|
</button>
|
||||||
<div class="progress-bar-value" style="width: 75%"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="spinner-container">
|
|
||||||
<div class="progress-spinner"></div>
|
|
||||||
</div>
|
|
||||||
<div class="alert alert-success">
|
|
||||||
<strong>Erfolg!</strong> Ihre Änderungen wurden gespeichert.
|
|
||||||
</div>
|
|
||||||
<div class="alert alert-danger">
|
|
||||||
<strong>Fehler!</strong> Bitte füllen Sie alle Felder aus.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Karte: Navigation & Layout -->
|
|
||||||
<section class="card grid-col-span-2">
|
<section class="card grid-col-span-2">
|
||||||
<h3 class="card-header">Navigation & Layout</h3>
|
<h3 class="card-header">Navigation & Layout</h3>
|
||||||
<div class="card-body">
|
<div class="card-body component-grid">
|
||||||
<div class="tab-group">
|
<div class="tab-group">
|
||||||
<button class="tab-link active">Profil</button
|
<button class="tab-link active">Profil</button
|
||||||
><button class="tab-link">Konto</button
|
><button class="tab-link">Konto</button
|
||||||
@@ -640,16 +633,20 @@
|
|||||||
<p>Hier wäre der Inhalt für den aktiven Tab "Profil".</p>
|
<p>Hier wäre der Inhalt für den aktiven Tab "Profil".</p>
|
||||||
</div>
|
</div>
|
||||||
<hr class="divider" />
|
<hr class="divider" />
|
||||||
<!-- HIER IST DIE WICHTIGE ÄNDERUNG FÜR DIE ANIMATION -->
|
<div class="expansion-panel" [class.is-open]="isPanelOpen">
|
||||||
<details class="expansion-panel">
|
<!-- Das <summary> wird zu einem <button> für bessere Kontrolle & Zugänglichkeit -->
|
||||||
<summary class="expansion-panel-header">
|
<button
|
||||||
|
type="button"
|
||||||
|
class="expansion-panel-header"
|
||||||
|
(click)="isPanelOpen = !isPanelOpen"
|
||||||
|
>
|
||||||
<span>Weitere Details anzeigen</span>
|
<span>Weitere Details anzeigen</span>
|
||||||
<svg
|
<svg
|
||||||
class="expansion-panel-icon"
|
class="expansion-panel-icon"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
viewBox="0 0 24 24"
|
ViewBox="0 0 0 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -658,7 +655,9 @@
|
|||||||
>
|
>
|
||||||
<polyline points="6 9 12 15 18 9"></polyline>
|
<polyline points="6 9 12 15 18 9"></polyline>
|
||||||
</svg>
|
</svg>
|
||||||
</summary>
|
</button>
|
||||||
|
|
||||||
|
<!-- Der Inhalt bleibt strukturell gleich -->
|
||||||
<div class="expansion-panel-content-wrapper">
|
<div class="expansion-panel-content-wrapper">
|
||||||
<div class="expansion-panel-content">
|
<div class="expansion-panel-content">
|
||||||
Hier steht der Inhalt, der ein- und ausgeklappt werden kann.
|
Hier steht der Inhalt, der ein- und ausgeklappt werden kann.
|
||||||
@@ -667,129 +666,151 @@
|
|||||||
eget.
|
eget.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</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"><</button
|
||||||
|
><button class="btn btn-icon">></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>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<!-- Ende .dashboard-grid -->
|
<!-- Ende .dashboard-grid -->
|
||||||
</main>
|
</main>
|
||||||
</div>
|
|
||||||
<!-- =================================================================== -->
|
|
||||||
<!-- DYNAMISCHER DIALOG (Standardmäßig unsichtbar) -->
|
|
||||||
<!-- =================================================================== -->
|
|
||||||
<div
|
|
||||||
class="dialog-backdrop"
|
|
||||||
*ngIf="isDialogOpen"
|
|
||||||
(click)="closeDialog()"
|
|
||||||
[@fade]> <!-- Angular Animation -->
|
|
||||||
|
|
||||||
<!-- (click.stop) verhindert, dass der Klick auf den Container den Backdrop schließt -->
|
<!-- =================================================================== -->
|
||||||
<div class="dialog-container card" (click)="$event.stopPropagation()" [@slideIn]>
|
<!-- 3. OVERLAYS (Dynamisch, außerhalb des Haupt-Layouts) -->
|
||||||
|
<!-- =================================================================== -->
|
||||||
|
|
||||||
<div class="dialog-header">
|
<div
|
||||||
<h3 class="dialog-title">Aktion bestätigen</h3>
|
class="dialog-backdrop"
|
||||||
<!-- (click) ruft die closeDialog Methode auf -->
|
*ngIf="isDialogOpen"
|
||||||
<button class="btn btn-icon" (click)="closeDialog()" data-tooltip="Schließen">×</button>
|
(click)="closeDialog()"
|
||||||
</div>
|
[@fade]
|
||||||
|
>
|
||||||
<div class="dialog-content">
|
<div
|
||||||
<div class="dialog-icon-container">
|
class="dialog-container card"
|
||||||
<!-- Ein Icon, um die Art des Dialogs zu verdeutlichen -->
|
(click)="$event.stopPropagation()"
|
||||||
<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>
|
[@slideIn]
|
||||||
|
>
|
||||||
|
<div class="dialog-header">
|
||||||
|
<h3 class="dialog-title">Aktion bestätigen</h3>
|
||||||
|
<button
|
||||||
|
class="btn btn-icon"
|
||||||
|
(click)="closeDialog()"
|
||||||
|
data-tooltip="Schließen"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</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>
|
||||||
<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>
|
||||||
|
|
||||||
<div class="dialog-actions">
|
|
||||||
<!-- (click) ruft die closeDialog Methode auf -->
|
|
||||||
<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 class="menu-container">
|
|
||||||
<button class="btn btn-icon">...</button> <!-- Der Auslöser -->
|
|
||||||
|
|
||||||
<div class="menu-panel card"> <!-- Das Panel, das erscheint -->
|
|
||||||
<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 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 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 class="paginator">
|
|
||||||
<span class="paginator-info">1-10 von 100</span>
|
|
||||||
<div class="paginator-controls">
|
|
||||||
<button class="btn btn-icon"><</button>
|
|
||||||
<button class="btn btn-icon">></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div *ngIf="isLoading; else content">
|
|
||||||
<div class="skeleton-card">...</div>
|
|
||||||
</div>
|
|
||||||
<ng-template #content>
|
|
||||||
<!-- Echte Daten hier -->
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- =================================================================== -->
|
|
||||||
<!-- DYNAMISCHE SNACKBAR (Standardmäßig unsichtbar) -->
|
|
||||||
<!-- =================================================================== -->
|
|
||||||
<div
|
|
||||||
class="snackbar"
|
|
||||||
*ngIf="isSnackbarVisible"
|
|
||||||
[@fadeSlideIn]> <!-- Angular Animation -->
|
|
||||||
|
|
||||||
<!-- Das Icon ist optional, wertet die Snackbar aber auf -->
|
|
||||||
<div class="snackbar-icon-container">
|
|
||||||
<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="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="snackbar-message">{{ snackbarMessage }}</span>
|
<!-- <div class="snackbar-container-wrapper" [class.position-top]="snackbarPosition === 'top'">
|
||||||
|
<div
|
||||||
|
*ngFor="let snack of snackbars; let i = index"
|
||||||
|
class="snackbar"
|
||||||
|
[style]="getSnackbarStyle(i, snack.state)">
|
||||||
|
|
||||||
<button class="btn btn-icon snackbar-close-btn" (click)="closeSnackbar()" data-tooltip="Schließen">
|
<div class="snackbar-icon-container">icon</div>
|
||||||
×
|
<span class="snackbar-message">{{ snack.message }}</span>
|
||||||
</button>
|
<button class="btn btn-icon snackbar-close-btn" (click)="closeSnackbar(snack.id)">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,58 +1,93 @@
|
|||||||
import { Component, Renderer2 } from '@angular/core';
|
import { Component, Renderer2, OnInit } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { trigger, state, style, transition, animate } from '@angular/animations';
|
import { trigger, transition, style, animate } from '@angular/animations';
|
||||||
|
|
||||||
|
import { SnackbarService } from '../../../../shared/snackbar/services/snackbar.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-demo',
|
selector: 'app-demo',
|
||||||
|
standalone: true, // Hinzugefügt für moderne, eigenständige Komponenten
|
||||||
imports: [CommonModule],
|
imports: [CommonModule],
|
||||||
templateUrl: './demo.component.html',
|
templateUrl: './demo.component.html',
|
||||||
styleUrl: './demo.component.css',
|
styleUrl: './demo.component.css',
|
||||||
animations: [
|
animations: [
|
||||||
trigger('fade', [
|
trigger('fade', [
|
||||||
transition(':enter', [
|
transition(':enter', [
|
||||||
style({ opacity: 0 }),
|
style({ opacity: 0 }),
|
||||||
animate('300ms ease-out', style({ opacity: 1 }))
|
animate('300ms ease-out', style({ opacity: 1 })),
|
||||||
]),
|
]),
|
||||||
transition(':leave', [
|
transition(':leave', [animate('300ms ease-in', style({ opacity: 0 }))]),
|
||||||
animate('300ms ease-in', style({ opacity: 0 }))
|
|
||||||
])
|
|
||||||
]),
|
]),
|
||||||
trigger('slideIn', [
|
trigger('slideIn', [
|
||||||
transition(':enter', [
|
transition(':enter', [
|
||||||
style({ transform: 'translateY(20px)', opacity: 0 }),
|
style({ transform: 'translateY(20px)', opacity: 0 }),
|
||||||
animate('300ms ease-out', style({ transform: 'translateY(0)', opacity: 1 }))
|
animate(
|
||||||
|
'300ms ease-out',
|
||||||
|
style({ transform: 'translateY(0)', opacity: 1 })
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
transition(':leave', [
|
transition(':leave', [
|
||||||
animate('300ms ease-in', style({ transform: 'translateY(20px)', opacity: 0 }))
|
animate(
|
||||||
])
|
'300ms ease-in',
|
||||||
|
style({ transform: 'translateY(20px)', opacity: 0 })
|
||||||
|
),
|
||||||
|
]),
|
||||||
]),
|
]),
|
||||||
trigger('fadeSlideIn', [
|
trigger('fadeSlideIn', [
|
||||||
transition(':enter', [
|
transition(':enter', [
|
||||||
style({ bottom: '-100px', opacity: 0 }),
|
style({ bottom: '-100px', opacity: 0 }),
|
||||||
animate('300ms ease-out', style({ bottom: '2rem', opacity: 1 }))
|
animate('300ms ease-out', style({ bottom: '2rem', opacity: 1 })),
|
||||||
]),
|
]),
|
||||||
transition(':leave', [
|
transition(':leave', [
|
||||||
animate('300ms ease-in', style({ bottom: '-100px', opacity: 0 }))
|
animate('300ms ease-in', style({ bottom: '-100px', opacity: 0 })),
|
||||||
])
|
]),
|
||||||
])
|
]),
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
export class DemoComponent {
|
export class DemoComponent implements OnInit {
|
||||||
// 1. Eine Eigenschaft, die den aktuellen Zustand des Dark Mode speichert.
|
// ===================================================================
|
||||||
// Sie ist an [checked]="isDarkMode" in der HTML gebunden.
|
// 1. ZUSTANDS-EIGENSCHAFTEN DER KOMPONENTE
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
isDarkMode = false;
|
isDarkMode = false;
|
||||||
isLoading = true;
|
isLoading = true; // Startet im Ladezustand, um Skeleton Loader zu zeigen
|
||||||
// 2. Wir "injizieren" den Renderer2. Das ist der sichere Weg in Angular,
|
isDialogOpen = false;
|
||||||
// um das DOM (z.B. den <body>-Tag) zu manipulieren.
|
isSnackbarVisible = false;
|
||||||
constructor(private renderer: Renderer2) {}
|
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
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
// 3. Das ist die Funktion, die vom (change)-Event des Schalters aufgerufen wird.
|
|
||||||
toggleTheme(): void {
|
toggleTheme(): void {
|
||||||
// Kehre den aktuellen Zustand um (true -> false, false -> true)
|
|
||||||
this.isDarkMode = !this.isDarkMode;
|
this.isDarkMode = !this.isDarkMode;
|
||||||
|
|
||||||
// Überprüfe den neuen Zustand und füge die Klasse 'dark-theme'
|
|
||||||
// zum <body>-Tag hinzu oder entferne sie.
|
|
||||||
if (this.isDarkMode) {
|
if (this.isDarkMode) {
|
||||||
this.renderer.addClass(document.body, 'dark-theme');
|
this.renderer.addClass(document.body, 'dark-theme');
|
||||||
} else {
|
} else {
|
||||||
@@ -60,54 +95,28 @@ export class DemoComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isDialogOpen = false;
|
// ===================================================================
|
||||||
|
// 4. METHODEN FÜR DEN DIALOG
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
// 2. Eine Methode, um den Dialog zu öffnen
|
|
||||||
openDialog(): void {
|
openDialog(): void {
|
||||||
this.isDialogOpen = true;
|
this.isDialogOpen = true;
|
||||||
// Optional: Verhindert das Scrollen der Seite im Hintergrund
|
|
||||||
this.renderer.addClass(document.body, 'no-scroll');
|
this.renderer.addClass(document.body, 'no-scroll');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Eine Methode, um den Dialog zu schließen
|
|
||||||
closeDialog(): void {
|
closeDialog(): void {
|
||||||
this.isDialogOpen = false;
|
this.isDialogOpen = false;
|
||||||
// Optional: Gibt das Scrollen der Seite wieder frei
|
|
||||||
this.renderer.removeClass(document.body, 'no-scroll');
|
this.renderer.removeClass(document.body, 'no-scroll');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// demo.component.ts
|
||||||
|
|
||||||
isSnackbarVisible = false;
|
// ===================================================================
|
||||||
snackbarMessage = '';
|
// FINALE, ROBUSTE METHODEN FÜR DIE SNACKBAR (VERSION 5.0)
|
||||||
private snackbarTimer: any; // Hier speichern wir den Timer
|
// ===================================================================
|
||||||
|
|
||||||
// 2. Eine Methode, um die Snackbar anzuzeigen
|
triggerSnackbar(): void {
|
||||||
// Wir übergeben eine Nachricht, um sie wiederverwendbar zu machen
|
const time = new Date().toLocaleTimeString();
|
||||||
showSnackbar(message: string): void {
|
this.snackbarService.show('Neues Ereignis um ' + time);
|
||||||
// Falls bereits eine Snackbar sichtbar ist, schließen wir sie zuerst
|
|
||||||
if (this.isSnackbarVisible) {
|
|
||||||
this.closeSnackbar();
|
|
||||||
// Kurze Verzögerung, damit die Animation sauber neustartet
|
|
||||||
setTimeout(() => this.displaySnackbar(message), 300);
|
|
||||||
} else {
|
|
||||||
this.displaySnackbar(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private displaySnackbar(message: string): void {
|
|
||||||
this.snackbarMessage = message;
|
|
||||||
this.isSnackbarVisible = true;
|
|
||||||
|
|
||||||
// Setze einen Timer, um die Snackbar nach 5 Sekunden automatisch zu schließen
|
|
||||||
this.snackbarTimer = setTimeout(() => {
|
|
||||||
this.closeSnackbar();
|
|
||||||
}, 5000); // 5000 Millisekunden = 5 Sekunden
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Eine Methode, um die Snackbar zu schließen (manuell oder durch Timer)
|
|
||||||
closeSnackbar(): void {
|
|
||||||
// Lösche den Timer, falls der Benutzer manuell schließt
|
|
||||||
clearTimeout(this.snackbarTimer);
|
|
||||||
this.isSnackbarVisible = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/* Stile, die NUR für den Container gelten */
|
||||||
|
.snackbar-container-wrapper {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 2rem;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 1050;
|
||||||
|
width: 350px;
|
||||||
|
max-width: 90vw;
|
||||||
|
height: 300px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snackbar-container-wrapper.position-top {
|
||||||
|
bottom: auto;
|
||||||
|
top: 2rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<div class="snackbar-container-wrapper" [class.position-top]="(position$ | async) === 'top'">
|
||||||
|
<app-snackbar
|
||||||
|
*ngFor="let snack of (snackbars$ | async); let i = index"
|
||||||
|
[message]="snack.message"
|
||||||
|
[style]="getSnackbarStyle(i, snack.state, (position$ | async)!)"
|
||||||
|
(close)="closeSnackbar(snack.id)">
|
||||||
|
</app-snackbar>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { Snackbar, SnackbarService } from '../../services/snackbar.service';
|
||||||
|
import { SnackbarComponent } from '../snackbar/snackbar.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-snackbar-container',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, SnackbarComponent],
|
||||||
|
templateUrl: './snackbar-container.component.html',
|
||||||
|
styleUrl: './snackbar-container.component.css'
|
||||||
|
})
|
||||||
|
export class SnackbarContainerComponent {
|
||||||
|
snackbars$: Observable<Snackbar[]>;
|
||||||
|
position$: Observable<'top' | 'bottom'>;
|
||||||
|
|
||||||
|
constructor(private snackbarService: SnackbarService) {
|
||||||
|
this.snackbars$ = this.snackbarService.snackbars$;
|
||||||
|
this.position$ = this.snackbarService.position$;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diese Methode gehört hierher, da der Container die Position aller Kinder kennen muss.
|
||||||
|
getSnackbarStyle(index: number, state: 'visible' | 'fading', position: 'top' | 'bottom'): { [key: string]: any } {
|
||||||
|
const snackbarHeight = 75;
|
||||||
|
const verticalOffset = index * snackbarHeight;
|
||||||
|
const positionProperty = position === 'bottom' ? 'bottom' : 'top';
|
||||||
|
|
||||||
|
const opacity = 1 - (index * 0.2);
|
||||||
|
const scale = 1 - (index * 0.02);
|
||||||
|
|
||||||
|
const visibleStyle = {
|
||||||
|
[positionProperty]: `${verticalOffset}px`,
|
||||||
|
'opacity': opacity,
|
||||||
|
'transform': `scale(${scale})`,
|
||||||
|
'z-index': 1000 - index
|
||||||
|
};
|
||||||
|
const fadingStyle = { ...visibleStyle, 'opacity': 0, 'transform': 'scale(0.8)' };
|
||||||
|
|
||||||
|
return state === 'visible' ? visibleStyle : fadingStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeSnackbar(id: number): void {
|
||||||
|
this.snackbarService.close(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/* Stile, die NUR für eine einzelne Snackbar gelten */
|
||||||
|
:host {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: var(--border-radius-md);
|
||||||
|
background-color: var(--color-surface);
|
||||||
|
color: var(--color-text);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
box-shadow: var(--box-shadow-md);
|
||||||
|
pointer-events: auto;
|
||||||
|
transition: all 0.5s cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.snackbar-icon-container {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
background-color: #dcfce7;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
:host-context(body.dark-theme) .snackbar-icon-container {
|
||||||
|
background-color: #166534;
|
||||||
|
color: #dcfce7;
|
||||||
|
}
|
||||||
|
.snackbar-message {
|
||||||
|
flex-grow: 1;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.snackbar-close-btn {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--color-text-light);
|
||||||
|
}
|
||||||
|
.snackbar-close-btn:hover {
|
||||||
|
background-color: var(--color-body-bg);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<div class="snackbar-icon-container">
|
||||||
|
<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="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
||||||
|
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span class="snackbar-message">{{ message }}</span>
|
||||||
|
<button class="btn btn-icon snackbar-close-btn" (click)="onClose()" data-tooltip="Schließen">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-snackbar',
|
||||||
|
standalone: true,
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './snackbar.component.html',
|
||||||
|
styleUrl: './snackbar.component.css'
|
||||||
|
})
|
||||||
|
export class SnackbarComponent {
|
||||||
|
@Input() message: string = '';
|
||||||
|
@Output() close = new EventEmitter<void>();
|
||||||
|
|
||||||
|
onClose() {
|
||||||
|
this.close.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/app/shared/snackbar/services/snackbar.service.ts
Normal file
55
src/app/shared/snackbar/services/snackbar.service.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
|
||||||
|
// Exportiere das Interface, damit es wiederverwendbar ist
|
||||||
|
export interface Snackbar {
|
||||||
|
id: number;
|
||||||
|
message: string;
|
||||||
|
state: 'visible' | 'fading';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class SnackbarService {
|
||||||
|
// BehaviorSubject hält den aktuellen Zustand und benachrichtigt alle "Zuhörer"
|
||||||
|
private snackbarsSubject = new BehaviorSubject<Snackbar[]>([]);
|
||||||
|
snackbars$: Observable<Snackbar[]> = this.snackbarsSubject.asObservable();
|
||||||
|
|
||||||
|
// Die Position wird ebenfalls hier als globaler Zustand verwaltet
|
||||||
|
private positionSubject = new BehaviorSubject<'top' | 'bottom'>('top');
|
||||||
|
position$: Observable<'top' | 'bottom'> = this.positionSubject.asObservable();
|
||||||
|
|
||||||
|
private nextId = 0;
|
||||||
|
|
||||||
|
// Öffentliche Methode zum Anzeigen einer Snackbar
|
||||||
|
show(message: string): void {
|
||||||
|
const newSnackbar: Snackbar = { id: this.nextId++, message, state: 'visible' };
|
||||||
|
const currentSnackbars = [newSnackbar, ...this.snackbarsSubject.value];
|
||||||
|
this.snackbarsSubject.next(currentSnackbars);
|
||||||
|
|
||||||
|
// Timer zum automatischen Schließen
|
||||||
|
setTimeout(() => this.close(newSnackbar.id), 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Öffentliche Methode zum Schließen einer Snackbar
|
||||||
|
close(id: number): void {
|
||||||
|
let currentSnackbars = this.snackbarsSubject.value;
|
||||||
|
const index = currentSnackbars.findIndex(s => s.id === id);
|
||||||
|
|
||||||
|
if (index > -1 && currentSnackbars[index].state === 'visible') {
|
||||||
|
currentSnackbars[index].state = 'fading';
|
||||||
|
this.snackbarsSubject.next([...currentSnackbars]);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
currentSnackbars = this.snackbarsSubject.value.filter(s => s.id !== id);
|
||||||
|
this.snackbarsSubject.next(currentSnackbars);
|
||||||
|
}, 100); // Muss zur CSS-Dauer passen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Öffentliche Methode zum Ändern der Position
|
||||||
|
setPosition(position: 'top' | 'bottom'): void {
|
||||||
|
this.positionSubject.next(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
1211
src/styles.css
1211
src/styles.css
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user