Files
Hoard/GUI/style.md
T
Jonas 7e2ca4c9e2 Rename hoard- to ui- and add UI components
Mass rename of CSS classes, tokens and animations from the hoard- namespace to ui- (classes, variables like --ui-*, and keyframes). Introduces new UI components: EmptyState, StatusPill, and UserAvatar and updates admin views to import and use them. Updates many route/layout components and global.css to use the new ui- patterns and responsive variables. Also updates Impressum contact emails and adds .claude/settings.local.json to allow running npm scripts in the Claude local settings.
2026-04-28 21:52:22 +02:00

359 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Hoard Style Guide
## Zielbild
Hoard soll wirken wie eine **moderne, produktive Dateiverwaltung im Browser** ruhig, klar und mit hoher visueller Sorgfalt. Die Grundphilosophie bleibt dateiorientiert: Inhalte, Dateinamen, Pfade und Aktionen stehen im Vordergrund, nicht UI-Effekte. Gleichzeitig darf sich Hoard hochwertig und präzise anfühlen „polished" statt „fancy", näher an einer modernen Linear-/Vercel-/Notion-Sidebar als an einer alten Admin-UI.
Die Gestaltung folgt drei Prinzipien:
1. **Dateien zuerst** Inhalte, Namen, Strukturen und Aktionen sind optisch dominant, nicht die Chrome.
2. **Ruhe mit Charakter** viel Weißraum, klare Flächen, ausgewählte Akzente. Wenig Elemente, aber jedes mit Sorgfalt.
3. **Grün als Identität, nicht als Dauerfeuer** die Markenfarbe wird gezielt für Auswahl, Primäraktionen, Status und Branding eingesetzt nicht flächendeckend.
## Modernisierungs-Direktive
Beim Redesign gilt zusätzlich:
- **Hochwertige App-Shell:** Sidebar und Topbar dürfen sich „premium" anfühlen (klare Hierarchie, animierter Active-Indicator, gradient-tinged Brand-Bereich).
- **Layered Surfaces:** Statt einer einzigen Surface-Farbe gibt es eine kleine Surface-Hierarchie (`surface`, `surface-alt`, `surface-elevated`) mit subtil gestaffelten Schatten.
- **Microinteractions:** kurze, präzise Hover-/Active-/Focus-Animationen (160240 ms). Keine wabernden, dauerhaften Bewegungen.
- **Ambient Gradients:** Hero-/Brand-Bereiche dürfen sehr weiche, breit gestreute Verläufe in Markenfarbe haben. Arbeitsflächen bleiben funktional und ruhig.
- **Typografische Präzision:** klare Größen-Hierarchie, ruhige Headlines, viel `letter-spacing` Disziplin, keine dekorativen Schriften.
- **Konsistente Iconographie:** ausschließlich MDI Outline-Icons mit gleicher Größe und Farbverhalten.
- **Light- und Dark-Mode gleichwertig:** alle neuen Stile müssen in beiden Modi funktional und ästhetisch tragen, ausschließlich über Tokens (`color-mix`, CSS-Variablen) gelöst.
**Was weiterhin tabu ist:**
- kein Glassmorphism (echte Backdrop-Blur-Karten),
- kein Neon-/Gaming-Look,
- keine harten, durchgängigen Kontraste,
- keine Mehrfarbigkeit aus dem Akzent-Setup,
- keine dauerhaften Animationen oder Parallax-Spielereien.
## Visuelle Identität
Markenwirkung basiert auf neutralen, leicht warmen Flächen mit kontrolliertem Grün. Das Grün stammt aus dem Logo (Stapel-/Ordner-Idee) und steht für Ablage, Struktur und „self-hosted tool" statt „Social App". Akzent-Lime nur als gezielter Akzent-Glow im Branding und in Marketing-Sektionen.
Die App ist **light-first**, Dark-Mode ist gleichwertig zu pflegen. Neue Komponenten beziehen Farben aus Design-Tokens.
## Farbpalette
### Primärfarben (Light)
- **Primary 800:** `#10421E` tiefster Markenton, Texte auf Light-Surface.
- **Primary 700:** `#1C652F` Primärbuttons, aktive Icons, Fokusrahmen.
- **Primary 600:** `#2E7D32` Hover-Zustände, aktive Navigation.
- **Primary 500:** `#3C8F42` ausgewählte Einträge, Badges, bestätigende States.
- **Primary 300:** `#A8D5A2` weiche Hintergründe für Auswahlflächen.
- **Primary 100:** `#EAF5E8` sehr subtile Hervorhebungen, Tints.
- **Primary 050:** `#F4FAF1` fast unsichtbare Pflasterfläche für Hero-Glows.
### Akzent
- **Accent Lime:** `#B7E36B` sparsam: Logo-Glow, kleine Highlights, Upload-Fortschritt.
### Neutrale (Light)
- **Background:** `#F5F8F2`
- **Background Tint:** `#EEF3EA` ambient Hintergrund-Verlauf.
- **Surface:** `#FFFFFF` Karten, Panels, Dialoge.
- **Surface Alt:** `#F1F4EE` Toolbar, Tabellenkopf, Sekundärflächen.
- **Surface Elevated:** `#FBFCF8` höhere Layer (Drawer-Inhalt, Dropdowns).
- **Border:** `#DCE3D6`
- **Border Strong:** `#C5CFBE`
- **Border Subtle:** `#E8EDE2` innere Trennlinien.
### Text (Light)
- **Text Primary:** `#1A2A1E`
- **Text Secondary:** `#5A6A5E`
- **Text Muted:** `#7B897F`
- **Text On Primary:** `#FFFFFF`
### Dark Mode
Dark-Mode wird vollständig über Tokens gespiegelt. Eckwerte:
- Background: `#0E1115`
- Surface: `#161A20`
- Surface Alt: `#1B2028`
- Surface Elevated: `#1F252E`
- Border: `#2A323D`
- Border Strong: `#3A4452`
- Text Primary: `#E9EFF3`
- Text Secondary: `#B6BEC8`
- Primary 700 (dark): `#5FB968`
- Primary 600 (dark): `#4EA758`
- Primary 100 (dark): `#1F2922`
### Status
- **Success:** `#2E7D32`
- **Warning:** `#B7791F`
- **Danger:** `#C0392B`
- **Info:** `#2F6FB3`
## Typografie
Neutral, gut lesbar, unauffällig modern keine dekorativen Schriften.
**Stack:** `Inter, "Segoe UI", Roboto, system-ui, sans-serif`
**Skala (rem-orientiert, fixe px-Breakpoints, keine viewport-Skalierung):**
- `--font-size-2xs`: 11px Status-Labels, Mini-Meta.
- `--font-size-xs`: 12px Tabellenmeta, Helper-Text.
- `--font-size-sm`: 13px sekundärer UI-Text.
- `--font-size-md`: 14px Standard-UI-Text, Listen.
- `--font-size-lg`: 16px akzentuierte UI-Hervorhebung.
- `--font-size-xl`: 20px Bereichsüberschriften.
- `--font-size-2xl`: 26px Seitenüberschriften.
- `--font-size-3xl`: 32px Display-Headlines (Hero).
- `--font-size-display`: 44px sehr seltene Marketing-Display-Texte.
**Gewichte:**
- 400 für Fließtext.
- 500 für UI-Text und Labels.
- 600 für Titel, Kicker, aktive Items.
- 700 nur sehr gezielt (Display-Headlines, Logo-Wortmarke).
**Letter-Spacing-Disziplin:**
- Display-Headlines: leicht negatives Tracking (`-0.01em` bis `-0.02em`).
- Kicker/Labels (uppercase): `0.05em` bis `0.08em`.
- Standard: `0`.
## Spacing
Modulare Skala in 4er-Schritten:
```
--space-1: 4px
--space-2: 8px
--space-3: 12px
--space-4: 16px
--space-5: 20px
--space-6: 24px
--space-7: 28px
--space-8: 32px
--space-10: 40px
--space-12: 48px
--space-16: 64px
```
Hauptseiten: `--ui-page-width` 11201200px, Padding orientiert sich an `--space-6`/`--space-8`.
## Formensprache (Border-Radien)
- `--radius-xs`: 6px kleine Pills, Status-Badges.
- `--radius-sm`: 10px Buttons, kleine Controls.
- `--radius-md`: 14px Inputs, Dropdowns, Listzeilen.
- `--radius-lg`: 18px Cards, Panels.
- `--radius-xl`: 22px Hero-Shells, Modals.
- `--radius-full`: 999px nur für Avatar/Tag-Pills.
Keine pillenförmigen Vollflächen als Grundstil.
## Schatten & Tiefe
Mehrstufiges, sehr ruhiges Schatten-System:
```
--shadow-xs: 0 1px 1px rgba(20, 30, 22, 0.04);
--shadow-sm: 0 2px 6px rgba(20, 30, 22, 0.06);
--shadow-md: 0 8px 22px rgba(20, 30, 22, 0.08);
--shadow-lg: 0 18px 44px rgba(20, 30, 22, 0.12);
--shadow-glow: 0 12px 36px rgba(28, 101, 47, 0.18);
```
Regeln:
- Panels: `--shadow-sm`.
- Hover-Lift max. 2 px, nur bei klar interaktiven Elementen.
- Dropdowns/Modals: `--shadow-md` bis `--shadow-lg`.
- `--shadow-glow` ausschließlich für Brand-Bereiche (Login-Hero, Welcome-Hero).
- Keine farbigen Schatten in Arbeitsflächen.
## Motion
- Standard-Easing: `cubic-bezier(0.2, 0, 0, 1)`.
- `--transition-fast`: 160 ms (Hover, Buttons, Listzeilen).
- `--transition-medium`: 220 ms (Route-Wechsel, Banner).
- `--transition-slow`: 320 ms (Hero-Enter, Drawer).
- Globale Page-Enter-Animation: weicher Y-Slide + Fade (≤ 8 px).
- `prefers-reduced-motion`: alle Transitions auf 1 ms reduzieren, keine Translates.
## App-Shell
### Topbar
- Höhe ca. 64 px, opaker `surface`-Hintergrund, dünne Bottom-Border.
- Branding links: Icon + Wortmarke + dezenter Subtext („Self-hosted Workspace").
- Page-Kontext (Name + Beschreibung) als sekundäre Info, nur ab `>1180px`.
- Rechts: Theme-Toggle, Account-Menü oder Login-Button.
- Subtile bottom shadow (`--shadow-xs`).
### Sidebar
- Breite 268284 px, Hintergrund `surface-alt`, leicht abgesetzt.
- Active-Indicator: linker, animierter, vertikaler Strich (`--color-primary-600`) + grüne Tint-Fläche + dunklerer Text.
- Hover: leichte Tint-Fläche, kein Scaling.
- Sektionen mit Kicker-Labels (`Navigation`, `Admin`).
- Mindesthöhe pro Item: 44 px (Desktop), 48 px (Mobile).
- Mobile = Bottom-Sheet-Drawer mit abgerundeten Top-Ecken.
### Footer
- Sehr ruhig, kompakt, `surface` mit dünner oberer Border.
- Links nur auf rechtlich/strukturell wichtige Routen (Impressum etc.).
- Mobile: in Grid mit Tap-Größen ≥ 44 px.
## Komponenten
### Cards / Panels
- Hintergrund: `surface` mit subtilem 180°-Verlauf zu `surface-alt`.
- Border: `--color-border`.
- Radius: `--radius-lg`.
- Padding: `--space-6` (Standard), kleinere Inhalte `--space-4`.
- Hover (nur klar interaktive Cards): Border in Primary-300-Mix, `--shadow-md`, 2 px Y-Lift.
### Buttons
- **Primary:** grüner Hintergrund (`--color-primary-700`), weiße Schrift, `--shadow-xs`. Hover: `--color-primary-600` + leichter Glow. Active: ohne Lift.
- **Outlined:** transparenter Hintergrund, `--color-border-strong`, dunkler Text. Hover: leichte Primary-Tint-Fläche, Border zu Primary-Mix.
- **Text/Tertiary:** für Zeilenaktionen, Toolbar, Nav. Hover: Surface-Tint.
- **Icon-Buttons:** mind. 40×40 (Desktop), 44×44 (Mobile).
- Letter-Spacing 0, kein Uppercase.
- Pro Bereich genau **eine Primäraktion**.
### Inputs
- Outline-Variante, `surface` Hintergrund.
- Border `--color-border-strong`, Focus-Ring 3 px Primary-300-Tint + Primary-600-Border.
- Labels oberhalb (Vuetify-Outlined-Label), keine reinen Placeholder.
- Mind. 44 px Höhe auf Mobile.
### Listen / Tabellen
- Tabelle: `surface` Hintergrund, abgesetzter Tabellen-Header (`surface-alt`).
- Hover: sehr subtile Primary-Tint-Tönung.
- Selected Row: Primary-100 Hintergrund, `--color-primary-700` Text.
- Border-Bottom in `--color-border-subtle`.
- `ui-list-row` (Datei-/Item-Zeilen): luftiges Padding, klare Spalten, `transform: translateX(2px)` beim Hover.
### Status-Pills (`ui-status`)
- Kompakt, `--radius-xs`, mit dezentem Text/Background-Tint pro Status (Success/Info/Warning/Danger/Neutral).
- Optional kleines Punktindikator-Dot vor dem Text.
### Banner-Stack
- Position: fixiert unten rechts (Desktop), unten zentriert (Mobile).
- Stapelbar, einzeln dismissable.
- Opake Hintergründe, `--shadow-md`, sauber lesbar auf jedem Inhalt.
- Enter/Leave: 180 ms Fade + 10 px Y.
## Hero-/Marketing-Bereiche
- Erlauben einen **ambient Verlauf** (`ui-panel-gradient` + Variablen).
- Optional dezenter „Spotlight"-Glow (radialer Verlauf, `--color-primary-300` mit niedriger Opazität, blur).
- Inhaltsbreite max ~64ch.
- Display-Headlines mit `--font-size-3xl` oder `--font-size-display` (nur Hero).
- Hero-Tags (`ui-chip`/`ui-tag`) als kompakte, dezent gerahmte Pills.
## Vorschau-Bereich (Files)
- **PDF-Vorschau:** neutraler Hintergrund, weiße „Papier"-Fläche mit `--shadow-md`, genug Rand. Controls minimal.
- **Bildvorschau:** dunklerer neutraler Viewer-Hintergrund nur, wenn das Bild dadurch besser wirkt; UI-Chrome konsistent.
- **Markdown-Editor/Reader:** wirkt wie ein Arbeitsdokument, nicht wie Blogpost. Lesbreite ~70ch, klare Heading-Hierarchie, sehr ruhige Codeblöcke.
## Empty-/Loading-States
- Empty: kleines Outline-Icon in Primary-Tint, kurzer Titel, ein Satz Begründung, eine klare CTA.
- Loading: Skeletons (graue Pulslinien) bevorzugt, ansonsten ein kleiner zentraler Spinner mit beschreibendem Text. Keine flackernden Spinner-Felder.
## Responsive Verhalten
Desktop ist Hauptfokus, Mobile muss aber sauber funktionieren.
### Breakpoints
- `@media (width <= 1180px)` Topbar-Kontextleiste verkürzen.
- `@media (width <= 960px)` Sidebar wird Bottom-Drawer; Karten-/Grid-Bereiche werden einspaltig; Spacing wird reduziert.
- `@media (width <= 600px)` CTAs full-width; Schriften minimal kompakter; Footer als Grid; Status-Pills behalten Lesbarkeit.
### Pflicht
- Desktop-Baseregeln nicht anfassen, nur Mobile-Overrides per Media Query.
- Touch-Größen: Buttons ≥ 44 px, Icon-Buttons ≥ 44×44, Nav-Items ≥ 48 px.
- Safe-Areas via `env(safe-area-inset-*)` (Topbar-Padding, Footer/Drawer Bottom).
- Banner-Stack respektiert Safe-Area Bottom.
- Pflicht-Viewports im QA: `360x800`, `390x844`, `768x1024`, `1024x768`, `>=1280` jeweils Light + Dark.
## Interaktionsprinzipien
- Primäraktionen klar sichtbar.
- Destruktives nie direkt neben Standardaktion.
- Dateizeilen sind klickbar, dürfen aber nicht wie Buttons aussehen.
- Hover, Active und Selected klar unterscheidbar (unterschiedliche Tints/Outlines).
- Fokus für Tastaturbedienung immer sichtbar (`outline: 2px solid var(--color-primary-500); outline-offset: 2px`).
## Designregeln für die Umsetzung
### Immer
- Tokens nutzen (Farben, Spacing, Radius, Shadow).
- Patterns wiederverwenden (`ui-panel`, `ui-page`, `ui-action-row`, `ui-kicker`, `ui-status`, `ui-chip`, `ui-spotlight`).
- Light- und Dark-Mode gleichwertig prüfen.
- Animationen kurz halten und `prefers-reduced-motion` respektieren.
### Vermeiden
- zu viele Karten ohne Funktion,
- zu viele Akzentfarben gleichzeitig,
- harte 1:1-Kontraste,
- echte Glasflächen / Backdrop-Blur,
- dauernde Bewegungen,
- Schriftgrößen, die mit der Viewport-Breite skalieren.
## Beispiel: Design-Tokens
```css
:root {
/* Surfaces */
--color-bg: #f5f8f2;
--color-bg-tint: #eef3ea;
--color-surface: #ffffff;
--color-surface-alt: #f1f4ee;
--color-surface-elevated: #fbfcf8;
--color-border: #dce3d6;
--color-border-strong: #c5cfbe;
--color-border-subtle: #e8ede2;
/* Text */
--color-text: #1a2a1e;
--color-text-secondary: #5a6a5e;
--color-text-muted: #7b897f;
--color-text-on-primary: #ffffff;
/* Brand */
--color-primary-800: #10421e;
--color-primary-700: #1c652f;
--color-primary-600: #2e7d32;
--color-primary-500: #3c8f42;
--color-primary-300: #a8d5a2;
--color-primary-100: #eaf5e8;
--color-primary-050: #f4faf1;
--color-accent-lime: #b7e36b;
/* Status */
--color-success: #2e7d32;
--color-warning: #b7791f;
--color-danger: #c0392b;
--color-info: #2f6fb3;
/* Radius */
--radius-xs: 6px;
--radius-sm: 10px;
--radius-md: 14px;
--radius-lg: 18px;
--radius-xl: 22px;
--radius-full: 999px;
/* Shadows */
--shadow-xs: 0 1px 1px rgba(20, 30, 22, 0.04);
--shadow-sm: 0 2px 6px rgba(20, 30, 22, 0.06);
--shadow-md: 0 8px 22px rgba(20, 30, 22, 0.08);
--shadow-lg: 0 18px 44px rgba(20, 30, 22, 0.12);
--shadow-glow: 0 12px 36px rgba(28, 101, 47, 0.18);
/* Spacing */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 20px;
--space-6: 24px;
--space-7: 28px;
--space-8: 32px;
--space-10: 40px;
--space-12: 48px;
--space-16: 64px;
/* Motion */
--transition-fast: 160ms cubic-bezier(0.2, 0, 0, 1);
--transition-medium: 220ms cubic-bezier(0.2, 0, 0, 1);
--transition-slow: 320ms cubic-bezier(0.2, 0, 0, 1);
}
```
## Kurzfassung als Design-Leitlinie
Wenn du bei einer UI-Entscheidung unsicher bist:
**Lieber präzise als spektakulär. Lieber ruhige Flächen mit Charakter als visuelle Effekte. Grün ist Identität, nicht Dekoration. Jedes Element muss eine Funktion haben sonst fliegt es raus.**