docs: update UI guidelines with shadowless design and new view layouts

- Set all shadow variables to none for flat design

- Add dashboard-home-view with transparent background

- Redesign login page to single-column centered layout

- Update landing page with white background

- Add button variant conventions (LUMO_TERTIARY/LUMO_PRIMARY)

- Reorder sections and update responsive breakpoints
This commit is contained in:
2026-03-19 19:56:33 +01:00
parent 1bb5026b85
commit 84f8531bbf

View File

@@ -58,12 +58,24 @@ Alle Farben sind als CSS-Custom-Properties auf `html` definiert und **müssen**
### Schatten
Alle globalen Schatten-Variablen sind auf `none` gesetzt das Design ist bewusst schattenlos.
| Variable | Wert | Verwendung |
|---|---|---|
| `--app-shadow-sm` | `0 12px 28px rgba(15,23,42,0.08)` | Kleine Karten |
| `--app-shadow-md` | `0 20px 44px rgba(15,23,42,0.10)` | Mittlere Panels |
| `--app-shadow-lg` | `0 28px 72px rgba(15,23,42,0.12)` | Surface-Panels |
| `--app-shadow-xl` | `0 36px 88px rgba(8,18,36,0.24)` | Hero-Bereiche, Dialoge |
| `--app-shadow-sm` | `none` | |
| `--app-shadow-md` | `none` | |
| `--app-shadow-lg` | `none` | |
| `--app-shadow-xl` | `none` | |
Auch die Lumo-Schatten-Overrides sind `none`:
```css
--lumo-box-shadow-xs: none;
--lumo-box-shadow-s: var(--app-shadow-sm); /* → none */
--lumo-box-shadow-m: var(--app-shadow-md); /* → none */
--lumo-box-shadow-l: var(--app-shadow-lg); /* → none */
```
**Ausnahme**: Buttons behalten eigene Schatten (siehe Abschnitt 24).
---
@@ -117,6 +129,7 @@ Der Container, in dem alle gerouteten Views dargestellt werden:
.view-container {
display: flex;
flex-direction: column;
background: transparent;
margin: 20px; /* Abstand zum Browserrand */
width: calc(100% - 40px);
height: calc(100dvh - 40px);
@@ -145,8 +158,9 @@ Jede View muss **genau eine** der folgenden Root-Klassen tragen:
| `message-hub-view` | Nachrichten-Übersicht | `Main` |
| `statistics-chat-view` | Statistik/Chat | `VerticalLayout` |
| `dashboard-view` | Dashboard-Seiten | `VerticalLayout` |
| `landing-view` | Startseite (unauthentifiziert) | `Main` |
| `login-view` | Login-Seite | `Main` |
| `dashboard-home-view` | Haupt-Dashboard (transparenter Hintergrund) | `VerticalLayout` |
| `landing-view` | Startseite (unauthentifiziert, weißer Hintergrund) | `Main` |
| `login-view` | Login-Seite (weißer Hintergrund, fullscreen) | `Main` |
### Kritische Java-Regeln
@@ -335,7 +349,48 @@ filterBar.setWidthFull();
---
## 11. Sidebar / Navigation
## 11. Dashboard Home View
Die `dashboard-home-view` hat einen transparenten Hintergrund, der den Shell-Gradient durchscheinen lässt.
```css
.dashboard-home-view {
background: transparent !important;
}
.view-container:has(.dashboard-home-view) {
border-radius: 12px;
background: transparent;
overflow: auto;
}
body:has(.dashboard-home-view) {
background: var(--app-shell-background);
}
/* Surface-Panels und Hero-Panels im Dashboard: kein Border, kein Schatten */
.dashboard-home-view .surface-panel {
border: 0;
background: transparent;
backdrop-filter: none;
box-shadow: none;
}
.dashboard-home-view .hero-panel {
box-shadow: none;
}
```
---
## 12. Sidebar / Navigation
### Drawer Header (klickbar)
Der Drawer-Header (Logo + App-Name) ist klickbar und navigiert zum Dashboard:
```java
header.getStyle().set("cursor", "pointer");
header.getElement().setProperty("title", "Zum Dashboard");
header.addClickListener(event -> UI.getCurrent().navigate("dashboard"));
// AdminLayout navigiert zu "admin-dashboard"
```
### Nav-Rows
@@ -368,7 +423,7 @@ filterBar.setWidthFull();
---
## 12. Karten-Hierarchie
## 13. Karten-Hierarchie
| Klasse | Radius | Hintergrund | Einsatz |
|---|---|---|---|
@@ -385,7 +440,7 @@ filterBar.setWidthFull();
---
## 13. Station Tiles & Kacheln
## 14. Station Tiles & Kacheln
### Station Tile
@@ -430,7 +485,7 @@ filterBar.setWidthFull();
---
## 14. Job Task Cards
## 15. Job Task Cards
```css
.job-task-card {
@@ -471,7 +526,7 @@ filterBar.setWidthFull();
---
## 15. Dashboard Stat Cards
## 16. Dashboard Stat Cards
```css
.dashboard-stat-card {
@@ -504,7 +559,7 @@ filterBar.setWidthFull();
---
## 16. Message & Chat Components
## 17. Message & Chat Components
### Message Card
@@ -561,7 +616,7 @@ filterBar.setWidthFull();
---
## 17. Dialoge
## 18. Dialoge
```css
vaadin-dialog-overlay::part(content) {
@@ -593,7 +648,7 @@ vaadin-dialog-overlay::part(content) {
---
## 18. Detail Cards
## 19. Detail Cards
```css
.detail-card {
@@ -615,7 +670,7 @@ vaadin-dialog-overlay::part(content) {
---
## 19. Route & Summary Cards
## 20. Route & Summary Cards
```css
.route-card,
@@ -638,37 +693,47 @@ vaadin-dialog-overlay::part(content) {
---
## 20. Login Seite
## 21. Login Seite
Die Login-Seite verwendet ein **einspaltiges**, zentriertes Layout ohne Highlight-Panel.
```css
.login-shell {
width: min(1120px, 100%);
display: grid;
grid-template-columns: minmax(0, 1.15fr) minmax(360px, 440px);
gap: 1.5rem;
.login-view {
padding-inline: 0;
background: var(--app-shell-background) !important;
min-height: 100vh;
min-height: 100dvh;
}
.login-highlight {
position: relative;
overflow: hidden;
min-height: 560px;
padding: clamp(1.8rem, 4vw, 3rem);
border-radius: 32px;
border: 1px solid rgba(255,255,255,0.14);
background: linear-gradient(140deg, #081224 0%, #173d8d 52%, #0f766e 100%);
box-shadow: var(--app-shadow-xl);
.login-shell {
width: min(750px, 100%);
display: grid;
grid-template-columns: 1fr;
gap: 1.5rem;
}
.login-card {
width: 100%;
padding: clamp(1.35rem, 3vw, 2rem);
border-radius: 32px;
border: 1px solid var(--app-border-strong);
background: rgba(255,255,255,0.88);
backdrop-filter: blur(20px);
background: #ffffff;
box-shadow: var(--app-shadow-lg);
}
.login-card vaadin-login-form-wrapper {
background: #ffffff !important;
}
```
### Eyebrow Chip
### Java-Aufbau (LoginView)
```java
// Login-Card enthält direkt: flashBox, loginForm, 2FA-Felder, registerButton, versionSpan
// KEIN login-highlight Panel, KEIN H1-Titel (login-card-title entfernt)
loginLayout.add(flashBox, loginForm, twoFaField, verify2faButton, registerButton, versionSpan);
Div loginShell = new Div(loginLayout);
loginShell.addClassName("login-shell");
```
### Eyebrow Chip (Landing Page)
```css
.eyebrow-chip {
@@ -687,7 +752,20 @@ vaadin-dialog-overlay::part(content) {
---
## 21. Landing Page
## 22. Landing Page
```css
.landing-view {
padding: 20px;
gap: 20px;
background: #ffffff !important;
min-height: 100vh;
min-height: 100dvh;
}
body:has(.landing-view) {
background: #ffffff;
}
```
```css
.landing-header {
@@ -736,7 +814,7 @@ vaadin-dialog-overlay::part(content) {
---
## 22. Timeline Components
## 23. Timeline Components
```css
.timeline-entry-card {
@@ -760,7 +838,7 @@ vaadin-dialog-overlay::part(content) {
---
## 23. Invoice Components
## 24. Invoice Components
### Invoice Generator
@@ -821,7 +899,7 @@ vaadin-dialog-overlay::part(content) {
---
## 24. Buttons
## 25. Buttons
```css
vaadin-button {
@@ -832,26 +910,64 @@ vaadin-button {
vaadin-button:not([disabled]):hover {
transform: translateY(-1px);
}
/* Primary Buttons eigene Schatten (Ausnahme vom globalen none) */
vaadin-button[theme~="primary"] {
box-shadow: 0 8px 20px rgba(37,99,235,0.22);
}
vaadin-button[theme~="primary"]:not([disabled]):hover {
box-shadow: 0 12px 28px rgba(37,99,235,0.32);
}
/* Success Primary */
vaadin-button[theme~="primary"][theme~="success"] {
box-shadow: 0 8px 20px rgba(5,150,105,0.24);
}
vaadin-button[theme~="primary"][theme~="success"]:not([disabled]):hover {
box-shadow: 0 12px 28px rgba(5,150,105,0.34);
}
/* Error Primary */
vaadin-button[theme~="primary"][theme~="error"] {
box-shadow: 0 8px 20px rgba(220,38,38,0.24);
}
/* Tertiary Error Hover */
vaadin-button[theme~="tertiary"][theme~="error"]:not([disabled]):hover {
background: rgba(220,38,38,0.08);
transform: translateY(-1px);
}
/* Disabled */
vaadin-button[disabled] {
opacity: 0.46;
transform: none !important;
}
```
### Button-Varianten-Konvention (Java)
| Rolle | Theme-Variante | Beispiel |
|---|---|---|
| Hauptaktion (Erstellen, Speichern, Anwenden) | `LUMO_PRIMARY` | `addButton`, `applyFilter` |
| Sekundäraktion (Abbrechen, Zurück, Export, Paginierung) | `LUMO_TERTIARY` | `cancelButton`, `backButton`, `exportButton` |
| Gefährliche Aktion (Löschen) | `LUMO_ERROR` | `deleteButton` |
```java
// ✅ Sekundäre Buttons immer mit LUMO_TERTIARY:
cancelButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
backButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
exportButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
// ✅ Primäre Buttons mit LUMO_PRIMARY:
addButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
```
**Pill-Buttons** (Nav, Landing): `border-radius: 999px`
---
## 25. Overflow & Box-Model Regeln
## 26. Overflow & Box-Model Regeln
### Pflicht bei allen Container-Elementen
@@ -878,7 +994,7 @@ In Flex-Containern verhindert die Default-Eigenschaft `min-width: auto`, dass Fl
---
## 26. Lumo-Override-Strategie
## 27. Lumo-Override-Strategie
### Padding-Override
@@ -903,16 +1019,17 @@ vaadin-vertical-layout.data-view {
---
## 27. Responsive Verhalten
## 28. Responsive Verhalten
### Breakpoints
| Breakpoint | Änderungen |
|---|---|
| `max-width: 980px` | Login-Shell wird einspaltig |
| `max-width: 720px` | `view-container` Margin reduziert auf 10px, border-radius auf 8px |
| `max-height: 820px` | Drawer-Header und Nav-Rows bekommen kompakteres Padding |
> **Hinweis**: Login-Shell ist jetzt immer einspaltig der alte 980px-Breakpoint entfällt.
### Mobile View-Container
```css
@@ -936,7 +1053,7 @@ layout.getStyle().set("flex-wrap", "wrap");
---
## 28. Photo Gallery
## 29. Photo Gallery
```css
.job-photo-gallery {
@@ -973,7 +1090,7 @@ layout.getStyle().set("flex-wrap", "wrap");
---
## 29. Empty State
## 30. Empty State
```css
.empty-state-card {
@@ -988,7 +1105,7 @@ layout.getStyle().set("flex-wrap", "wrap");
---
## 30. Inline Flash (Fehlermeldungen)
## 31. Inline Flash (Fehlermeldungen)
```css
.inline-flash {
@@ -1004,7 +1121,7 @@ layout.getStyle().set("flex-wrap", "wrap");
---
## 31. Checkliste für neue Views
## 32. Checkliste für neue Views
Beim Erstellen einer neuen View folgende Punkte prüfen:
@@ -1018,3 +1135,4 @@ Beim Erstellen einer neuen View folgende Punkte prüfen:
- [ ] Grid-Panel verwendet `surface-panel data-grid-panel` mit `setWidthFull()`
- [ ] Schmale Formular-Container haben `setWidth("Xpx")` **und** `setMaxWidth("100%")`
- [ ] Inline-Styles nur für dynamische Werte verwenden, alles andere per CSS-Klassen
- [ ] Sekundäre Buttons (`Abbrechen`, `Zurück`, `Export`) haben `LUMO_TERTIARY`, Hauptaktionen haben `LUMO_PRIMARY`