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:
208
UI_GUIDELINES.md
208
UI_GUIDELINES.md
@@ -58,12 +58,24 @@ Alle Farben sind als CSS-Custom-Properties auf `html` definiert und **müssen**
|
|||||||
|
|
||||||
### Schatten
|
### Schatten
|
||||||
|
|
||||||
|
Alle globalen Schatten-Variablen sind auf `none` gesetzt – das Design ist bewusst schattenlos.
|
||||||
|
|
||||||
| Variable | Wert | Verwendung |
|
| Variable | Wert | Verwendung |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `--app-shadow-sm` | `0 12px 28px rgba(15,23,42,0.08)` | Kleine Karten |
|
| `--app-shadow-sm` | `none` | – |
|
||||||
| `--app-shadow-md` | `0 20px 44px rgba(15,23,42,0.10)` | Mittlere Panels |
|
| `--app-shadow-md` | `none` | – |
|
||||||
| `--app-shadow-lg` | `0 28px 72px rgba(15,23,42,0.12)` | Surface-Panels |
|
| `--app-shadow-lg` | `none` | – |
|
||||||
| `--app-shadow-xl` | `0 36px 88px rgba(8,18,36,0.24)` | Hero-Bereiche, Dialoge |
|
| `--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 {
|
.view-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
background: transparent;
|
||||||
margin: 20px; /* Abstand zum Browserrand */
|
margin: 20px; /* Abstand zum Browserrand */
|
||||||
width: calc(100% - 40px);
|
width: calc(100% - 40px);
|
||||||
height: calc(100dvh - 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` |
|
| `message-hub-view` | Nachrichten-Übersicht | `Main` |
|
||||||
| `statistics-chat-view` | Statistik/Chat | `VerticalLayout` |
|
| `statistics-chat-view` | Statistik/Chat | `VerticalLayout` |
|
||||||
| `dashboard-view` | Dashboard-Seiten | `VerticalLayout` |
|
| `dashboard-view` | Dashboard-Seiten | `VerticalLayout` |
|
||||||
| `landing-view` | Startseite (unauthentifiziert) | `Main` |
|
| `dashboard-home-view` | Haupt-Dashboard (transparenter Hintergrund) | `VerticalLayout` |
|
||||||
| `login-view` | Login-Seite | `Main` |
|
| `landing-view` | Startseite (unauthentifiziert, weißer Hintergrund) | `Main` |
|
||||||
|
| `login-view` | Login-Seite (weißer Hintergrund, fullscreen) | `Main` |
|
||||||
|
|
||||||
### Kritische Java-Regeln
|
### 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
|
### Nav-Rows
|
||||||
|
|
||||||
@@ -368,7 +423,7 @@ filterBar.setWidthFull();
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12. Karten-Hierarchie
|
## 13. Karten-Hierarchie
|
||||||
|
|
||||||
| Klasse | Radius | Hintergrund | Einsatz |
|
| Klasse | Radius | Hintergrund | Einsatz |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
@@ -385,7 +440,7 @@ filterBar.setWidthFull();
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13. Station Tiles & Kacheln
|
## 14. Station Tiles & Kacheln
|
||||||
|
|
||||||
### Station Tile
|
### Station Tile
|
||||||
|
|
||||||
@@ -430,7 +485,7 @@ filterBar.setWidthFull();
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14. Job Task Cards
|
## 15. Job Task Cards
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.job-task-card {
|
.job-task-card {
|
||||||
@@ -471,7 +526,7 @@ filterBar.setWidthFull();
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 15. Dashboard Stat Cards
|
## 16. Dashboard Stat Cards
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.dashboard-stat-card {
|
.dashboard-stat-card {
|
||||||
@@ -504,7 +559,7 @@ filterBar.setWidthFull();
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 16. Message & Chat Components
|
## 17. Message & Chat Components
|
||||||
|
|
||||||
### Message Card
|
### Message Card
|
||||||
|
|
||||||
@@ -561,7 +616,7 @@ filterBar.setWidthFull();
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 17. Dialoge
|
## 18. Dialoge
|
||||||
|
|
||||||
```css
|
```css
|
||||||
vaadin-dialog-overlay::part(content) {
|
vaadin-dialog-overlay::part(content) {
|
||||||
@@ -593,7 +648,7 @@ vaadin-dialog-overlay::part(content) {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 18. Detail Cards
|
## 19. Detail Cards
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.detail-card {
|
.detail-card {
|
||||||
@@ -615,7 +670,7 @@ vaadin-dialog-overlay::part(content) {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 19. Route & Summary Cards
|
## 20. Route & Summary Cards
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.route-card,
|
.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
|
```css
|
||||||
.login-shell {
|
.login-view {
|
||||||
width: min(1120px, 100%);
|
padding-inline: 0;
|
||||||
display: grid;
|
background: var(--app-shell-background) !important;
|
||||||
grid-template-columns: minmax(0, 1.15fr) minmax(360px, 440px);
|
min-height: 100vh;
|
||||||
gap: 1.5rem;
|
min-height: 100dvh;
|
||||||
}
|
}
|
||||||
.login-highlight {
|
.login-shell {
|
||||||
position: relative;
|
width: min(750px, 100%);
|
||||||
overflow: hidden;
|
display: grid;
|
||||||
min-height: 560px;
|
grid-template-columns: 1fr;
|
||||||
padding: clamp(1.8rem, 4vw, 3rem);
|
gap: 1.5rem;
|
||||||
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-card {
|
.login-card {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: clamp(1.35rem, 3vw, 2rem);
|
padding: clamp(1.35rem, 3vw, 2rem);
|
||||||
border-radius: 32px;
|
border-radius: 32px;
|
||||||
border: 1px solid var(--app-border-strong);
|
border: 1px solid var(--app-border-strong);
|
||||||
background: rgba(255,255,255,0.88);
|
background: #ffffff;
|
||||||
backdrop-filter: blur(20px);
|
|
||||||
box-shadow: var(--app-shadow-lg);
|
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
|
```css
|
||||||
.eyebrow-chip {
|
.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
|
```css
|
||||||
.landing-header {
|
.landing-header {
|
||||||
@@ -736,7 +814,7 @@ vaadin-dialog-overlay::part(content) {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 22. Timeline Components
|
## 23. Timeline Components
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.timeline-entry-card {
|
.timeline-entry-card {
|
||||||
@@ -760,7 +838,7 @@ vaadin-dialog-overlay::part(content) {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 23. Invoice Components
|
## 24. Invoice Components
|
||||||
|
|
||||||
### Invoice Generator
|
### Invoice Generator
|
||||||
|
|
||||||
@@ -821,7 +899,7 @@ vaadin-dialog-overlay::part(content) {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 24. Buttons
|
## 25. Buttons
|
||||||
|
|
||||||
```css
|
```css
|
||||||
vaadin-button {
|
vaadin-button {
|
||||||
@@ -832,26 +910,64 @@ vaadin-button {
|
|||||||
vaadin-button:not([disabled]):hover {
|
vaadin-button:not([disabled]):hover {
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Primary Buttons – eigene Schatten (Ausnahme vom globalen none) */
|
||||||
vaadin-button[theme~="primary"] {
|
vaadin-button[theme~="primary"] {
|
||||||
box-shadow: 0 8px 20px rgba(37,99,235,0.22);
|
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"] {
|
vaadin-button[theme~="primary"][theme~="success"] {
|
||||||
box-shadow: 0 8px 20px rgba(5,150,105,0.24);
|
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"] {
|
vaadin-button[theme~="primary"][theme~="error"] {
|
||||||
box-shadow: 0 8px 20px rgba(220,38,38,0.24);
|
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] {
|
vaadin-button[disabled] {
|
||||||
opacity: 0.46;
|
opacity: 0.46;
|
||||||
transform: none !important;
|
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`
|
**Pill-Buttons** (Nav, Landing): `border-radius: 999px`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 25. Overflow & Box-Model Regeln
|
## 26. Overflow & Box-Model Regeln
|
||||||
|
|
||||||
### Pflicht bei allen Container-Elementen
|
### 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
|
### Padding-Override
|
||||||
|
|
||||||
@@ -903,16 +1019,17 @@ vaadin-vertical-layout.data-view {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 27. Responsive Verhalten
|
## 28. Responsive Verhalten
|
||||||
|
|
||||||
### Breakpoints
|
### Breakpoints
|
||||||
|
|
||||||
| Breakpoint | Änderungen |
|
| Breakpoint | Änderungen |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `max-width: 980px` | Login-Shell wird einspaltig |
|
|
||||||
| `max-width: 720px` | `view-container` Margin reduziert auf 10px, border-radius auf 8px |
|
| `max-width: 720px` | `view-container` Margin reduziert auf 10px, border-radius auf 8px |
|
||||||
| `max-height: 820px` | Drawer-Header und Nav-Rows bekommen kompakteres Padding |
|
| `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
|
### Mobile View-Container
|
||||||
|
|
||||||
```css
|
```css
|
||||||
@@ -936,7 +1053,7 @@ layout.getStyle().set("flex-wrap", "wrap");
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 28. Photo Gallery
|
## 29. Photo Gallery
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.job-photo-gallery {
|
.job-photo-gallery {
|
||||||
@@ -973,7 +1090,7 @@ layout.getStyle().set("flex-wrap", "wrap");
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 29. Empty State
|
## 30. Empty State
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.empty-state-card {
|
.empty-state-card {
|
||||||
@@ -988,7 +1105,7 @@ layout.getStyle().set("flex-wrap", "wrap");
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 30. Inline Flash (Fehlermeldungen)
|
## 31. Inline Flash (Fehlermeldungen)
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.inline-flash {
|
.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:
|
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()`
|
- [ ] Grid-Panel verwendet `surface-panel data-grid-panel` mit `setWidthFull()`
|
||||||
- [ ] Schmale Formular-Container haben `setWidth("Xpx")` **und** `setMaxWidth("100%")`
|
- [ ] Schmale Formular-Container haben `setWidth("Xpx")` **und** `setMaxWidth("100%")`
|
||||||
- [ ] Inline-Styles nur für dynamische Werte verwenden, alles andere per CSS-Klassen
|
- [ ] 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`
|
||||||
|
|||||||
Reference in New Issue
Block a user