docs: Design-2.0-Briefing zur Uebergabe an Gemini + ROADMAP-Zeiger
Ampel / ampel (push) Successful in 27s
Ampel / ampel (push) Successful in 27s
Vollstaendige Auftragsbeschreibung fuer den UI-Umbau: 428 theme-Ternaries -> Tailwind-dark: + UI-Primitives, Ist-Zustand vermessen (Datei-Inventar mit Ternary-Zahlen), harte Regeln (nur UI, Funktion 1:1, Deutsch, Ampel gruen), empfohlener Weg, Definition of Done, Copy-Paste-Startprompt. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
# Design 2.0 — Briefing (Übergabe an Gemini)
|
||||
|
||||
> Dieses Dokument ist die vollständige Auftragsbeschreibung für den UI-Umbau
|
||||
> „Design 2.0". Es ist so geschrieben, dass ein zweites KI-Modell (Gemini)
|
||||
> eigenständig loslegen kann. Stand: 24.07.2026, vorbereitet von Claude.
|
||||
|
||||
---
|
||||
|
||||
## 0. Auftrag in einem Satz
|
||||
|
||||
Das Rippy-Web-UI von 428 handgeschriebenen `theme === 'dark' ? … : …`-
|
||||
Ternaries auf ein **sauberes, token-basiertes Tailwind-`dark:`-System**
|
||||
umstellen und dabei die Optik auf ein modernes, konsistentes „Design 2.0"
|
||||
heben — **ohne** Funktion, API-Aufrufe, deutsche Texte oder die
|
||||
Deploy-Kette anzufassen.
|
||||
|
||||
---
|
||||
|
||||
## 1. Was Rippy ist (Kontext in 30 Sekunden)
|
||||
|
||||
Rippy ist eine self-hosted Disc-Ripping-Maschine (CD/DVD/Blu-ray/4K-UHD):
|
||||
Disc rein → automatisch erkannt → verlustfrei gerippt (MakeMKV) →
|
||||
komprimiert (HandBrake) → Media-Server-fertig abgelegt. Alles Docker,
|
||||
alles im Heimnetz. Das UI ist die einzige Bedienoberfläche.
|
||||
|
||||
**Tech-Stack UI** (`docker/ui/`):
|
||||
- React 18 + TypeScript + Vite
|
||||
- TailwindCSS (`darkMode: 'class'`)
|
||||
- lucide-react (Icons)
|
||||
- Kein Router (Seitenwechsel über `useState` in `App.tsx`)
|
||||
- State: lokale Hooks + Polling gegen die REST-API (`src/lib/api.ts`,
|
||||
axios, `baseURL: '/api'`)
|
||||
|
||||
**Sprach-Konvention (AGENTS.md Regel 4):** Variablen-/Funktionsnamen auf
|
||||
Englisch, **alle Kommentare, UI-Texte und Docs auf Deutsch**. Der Betreiber
|
||||
(„Commander") ist Nicht-Entwickler und liest alles.
|
||||
|
||||
---
|
||||
|
||||
## 2. Der Kern des Problems
|
||||
|
||||
Jede Komponente entscheidet Farben **zur Laufzeit per Ternary**:
|
||||
|
||||
```tsx
|
||||
// SO sieht es HEUTE ~428× aus:
|
||||
<div className={`rounded-xl border ${theme === 'dark'
|
||||
? 'bg-slate-800 border-slate-700'
|
||||
: 'bg-white border-slate-200'}`}>
|
||||
```
|
||||
|
||||
Das ist der größte technische Schuldenberg des UI:
|
||||
- **428 Ternaries** in 18 Dateien (Inventar unten) — jede Farbe doppelt
|
||||
gepflegt, Copy-Paste-Fehler vorprogrammiert.
|
||||
- Jede Komponente zieht dafür `const { theme } = useDarkMode()` — Rendering
|
||||
hängt an einem Context-Wert, den es fast nie bräuchte.
|
||||
- Wiederkehrende Farb-Mappings sind **mehrfach dupliziert** statt zentral:
|
||||
`StatusBadge` (Dashboard), `getLevelColor` (Logs), `getTypeColor`
|
||||
(DeviceDiscovery) definieren jeweils eigene Status→Farbe-Tabellen.
|
||||
|
||||
### Warum das JETZT ein leichter Umbau ist
|
||||
|
||||
Die Infrastruktur für den sauberen Weg **steht bereits vollständig**:
|
||||
- `tailwind.config.js`: `darkMode: 'class'` ✅
|
||||
- `ThemeContext.tsx` setzt beim Umschalten `document.documentElement.
|
||||
classList.add('dark')` — also `.dark` auf `<html>` ✅
|
||||
- Damit funktionieren Tailwinds `dark:`-Varianten sofort überall.
|
||||
|
||||
Konkret heißt Migration also fast immer nur:
|
||||
|
||||
```tsx
|
||||
// NACHHER — kein Ternary, kein useDarkMode nötig:
|
||||
<div className="rounded-xl border bg-white border-slate-200
|
||||
dark:bg-slate-800 dark:border-slate-700">
|
||||
```
|
||||
|
||||
### Drei Altlasten, die mit aufgeräumt werden sollten
|
||||
|
||||
1. **Tote CSS-Variablen** (`src/index.css`): Es gibt `:root { --bg-color … }`
|
||||
und `[data-theme="dark"] { … }`. Der Dark-Block ist **toter Code** —
|
||||
nichts setzt jemals `data-theme` (der Theme-Umschalter nutzt die
|
||||
`.dark`-Klasse). Entweder die Variablen korrekt an `.dark` binden ODER
|
||||
(empfohlen) ganz auf Tailwind-`dark:` setzen und die Variablen entfernen.
|
||||
2. **Globale Transition** (`src/index.css`): `* { transition:
|
||||
background-color .3s, color .3s, border-color .3s; }` lässt bei jedem
|
||||
Theme-Wechsel die GESAMTE Seite animieren (Jank-Risiko) und macht die
|
||||
überall verstreuten `transition-colors duration-300`-Klassen doppelt.
|
||||
Auf einen bewussten, schmalen Transition-Ansatz reduzieren.
|
||||
3. **Icon-Inkonsistenz**: Fast alles nutzt `lucide-react`, aber
|
||||
`ConfirmDialog.tsx` nutzt Emoji (⚠️✅🤔) als „Icons". Vereinheitlichen.
|
||||
|
||||
---
|
||||
|
||||
## 3. Empfohlener Weg (technisch)
|
||||
|
||||
**Nicht** blind 428 Ternaries per Hand ersetzen — das ist fehleranfällig.
|
||||
Stattdessen in zwei Schichten:
|
||||
|
||||
### Schicht A — Wiederverwendbare Primitives (`src/components/ui/`)
|
||||
|
||||
Ein kleines Set typisierter Bausteine, die das Design kapseln. Heute wird
|
||||
jedes davon in jeder Datei neu zusammengeklöppelt:
|
||||
|
||||
- `Card` / `CardHeader` — die `rounded-xl border bg-white dark:bg-slate-800`-
|
||||
Kachel (kommt ~30× vor)
|
||||
- `Button` (Varianten: primary / secondary / ghost / danger)
|
||||
- `Badge` (Status/Typ-Pill mit zentraler Farbtabelle — löst die 3 Duplikate)
|
||||
- `Input` / `Select` / `Toggle` (Formularfelder, heute inline-dupliziert)
|
||||
- `Modal` (der `fixed inset-0 … backdrop-blur`-Rahmen — 4× dupliziert:
|
||||
RipTargetModal, JobDetailModal, MetadataKorrektur, ConfirmDialog)
|
||||
- `Section` / `PageHeader` (Seiten-Titel + Untertitel, überall gleich)
|
||||
|
||||
Farbwelt/Status **einmal zentral** definieren (z. B.
|
||||
`src/lib/design.ts`), damit Status→Farbe nur an EINER Stelle lebt:
|
||||
|
||||
```ts
|
||||
export const STATUS_STYLES = {
|
||||
pending: 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400',
|
||||
processing: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',
|
||||
transcoding: 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400',
|
||||
completed: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400',
|
||||
failed: 'bg-rose-100 text-rose-700 dark:bg-rose-900/30 dark:text-rose-400',
|
||||
// Disc-Typen: cd=blue, dvd=purple, bluray=pink, uhd=amber
|
||||
} as const
|
||||
```
|
||||
|
||||
### Schicht B — Seiten/Komponenten auf die Primitives umstellen
|
||||
|
||||
Datei für Datei die Ternaries durch `dark:`-Klassen bzw. die neuen
|
||||
Primitives ersetzen. `const { theme } = useDarkMode()` fällt dabei in
|
||||
fast allen Dateien weg (nur `App.tsx` braucht `toggleTheme` noch).
|
||||
|
||||
### Optional als echtes „2.0": Tailwind-Theme-Tokens
|
||||
|
||||
Statt roher `slate-*`/`indigo-*`-Klassen semantische Tokens in
|
||||
`tailwind.config.js` (`theme.extend.colors`) definieren
|
||||
(`surface`, `surface-muted`, `border-subtle`, `accent`, `text-primary`,
|
||||
`text-muted` …) und diese nutzen. Das macht spätere Farb-Anpassungen zu
|
||||
einer Ein-Zeilen-Änderung. **Kür, kein Muss** — die `dark:`-Umstellung
|
||||
ist der Pflichtteil.
|
||||
|
||||
---
|
||||
|
||||
## 4. Design-Richtung (Leitplanken, nicht Korsett)
|
||||
|
||||
Die bestehende Farbwelt ist bereits kohärent — bitte **systematisieren und
|
||||
verfeinern, nicht wild neu erfinden**. Referenz aus dem Ist-Zustand:
|
||||
|
||||
- **Akzent/Primär:** Indigo (`indigo-600`), Verlauf `indigo-500 → purple-600`
|
||||
(Logo, Buttons, aktive Nav)
|
||||
- **Flächen:** hell `slate-50` (Seite) / `white` (Karten); dunkel
|
||||
`slate-950`/`slate-900` (Seite) / `slate-800` (Karten)
|
||||
- **Ränder:** `slate-200` hell / `slate-700` dunkel
|
||||
- **Status:** amber=wartend/Warnung, blue=Bearbeitung/Info,
|
||||
purple=Komprimieren, emerald=fertig/Erfolg, rose=Fehler; Disc-Typen:
|
||||
cd=blue, dvd=purple, bluray=pink, **uhd=amber** (bewusst abgesetzt)
|
||||
- **Typo:** system-sans (siehe `index.css`), Überschriften `font-bold`
|
||||
|
||||
**Spielraum für 2.0** (gern, solange konsistent + zugänglich):
|
||||
Abstände/Rhythmus vereinheitlichen, Karten-Schatten/Radien harmonisieren,
|
||||
Empty-States aufwerten, Fokus-/Hover-Zustände konsistent, bessere
|
||||
Dichte in den Tabellen, der neue **Anleitung**-Tab (`pages/Anleitung.tsx`)
|
||||
darf visuell aufgewertet werden. Barrierefreiheit im Blick behalten
|
||||
(Kontrast, Fokus-Ringe, `aria-*` wo sinnvoll).
|
||||
|
||||
Es gibt eine `Skill`/Guideline „Web Interface Guidelines" — an modernen
|
||||
Best-Practices orientieren.
|
||||
|
||||
---
|
||||
|
||||
## 5. HARTE Regeln (nicht verhandelbar)
|
||||
|
||||
1. **Nur UI, nur `docker/ui/src/`** (+ ggf. `tailwind.config.js`,
|
||||
`index.css`, `index.html`). **Kein** Backend (`docker/api`,
|
||||
`docker/worker`), **keine** API-Verträge, **keine** `docker-compose.yml`.
|
||||
2. **Funktion bleibt 1:1.** Alle bestehenden Features, Flows, API-Calls,
|
||||
Polling-Intervalle, Feldnamen im POST-Body bleiben exakt erhalten. Das
|
||||
ist ein **Re-Skin + Refactor**, kein Feature-Umbau. Im Zweifel:
|
||||
Verhalten unverändert lassen.
|
||||
3. **Deutsch bleibt Deutsch.** Kein UI-Text wird übersetzt oder
|
||||
umformuliert (außer offensichtliche Tippfehler). Kommentare Deutsch.
|
||||
4. **Die CI-Ampel MUSS grün bleiben** (`.gitea/workflows/ci.yml`): bei
|
||||
jedem Push laufen Ruff, pytest UND `npm run build` (Vite). Ein
|
||||
TypeScript-/Build-Fehler = rot = nicht fertig. Nach JEDER umgestellten
|
||||
Komponente lokal `npm run build` grün halten.
|
||||
5. **`package-lock.json` committen**, falls neue Abhängigkeiten dazukommen
|
||||
(die Ampel prüft Reproduzierbarkeit). Neue Runtime-Deps sparsam — das
|
||||
Ziel ist weniger Code, nicht mehr.
|
||||
6. **AGENTS.md gelesen halten** (Repo-Wurzel) — die dortigen Regeln gelten.
|
||||
|
||||
---
|
||||
|
||||
## 6. Datei-Inventar (Fahrplan, Stand 24.07.2026)
|
||||
|
||||
Sortiert nach Aufwand. Zahlen = `theme === 'dark'`-Ternaries in der Datei.
|
||||
|
||||
| Datei | Zeilen | Ternaries | Hinweis |
|
||||
|---|---:|---:|---|
|
||||
| `pages/Settings.tsx` | 860 | **128** | Größter Brocken; viele Tabs — evtl. in Unterkomponenten pro Tab zerlegen |
|
||||
| `pages/Dashboard.tsx` | 504 | 44 | Enthält `StatusBadge`/`TypeBadge`/`ProgressBar`/`StatCard` → in Primitives heben |
|
||||
| `components/DeviceDiscovery.tsx` | 381 | 43 | Disc-Karte + Laufwerks-Liste; `getTypeColor`/`getStatusColor` zentralisieren |
|
||||
| `components/RipTargetModal.tsx` | 401 | 37 | Modal + Track-Tabelle + Serien-Felder |
|
||||
| `pages/Logs.tsx` | 246 | 34 | `getLevelColor`/`getLevelIcon`/`getLevelLabel` → zentral |
|
||||
| `components/StorageMounts.tsx` | 361 | 33 | Mounts + Ordner-Browser |
|
||||
| `components/JobDetailModal.tsx` | 239 | 28 | Modal, Download-Liste |
|
||||
| `components/FirstRunWizard.tsx` | 192 | 22 | Onboarding |
|
||||
| `components/WorkerVerwaltung.tsx` | 214 | 18 | Worker-Liste + Anbinde-Befehle |
|
||||
| `components/LiveLogSection.tsx` | 147 | 15 | Live-Log-Kachel |
|
||||
| `components/MetadataKorrektur.tsx` | 145 | 10 | Korrektur-Popup |
|
||||
| `pages/Anleitung.tsx` | 180 | 7 | Neu; darf visuell aufgewertet werden |
|
||||
| `components/ConfirmDialog.tsx` | 83 | 6 | Emoji-Icons → lucide |
|
||||
| `App.tsx` | 101 | 2 | Sidebar/Nav/Footer; behält `toggleTheme` |
|
||||
| `context/ThemeContext.tsx` | 52 | 1 | Bleibt im Kern; ggf. `data-theme` synchron setzen, falls CSS-Variablen genutzt werden |
|
||||
| `context/ToastContext.tsx` | 62 | 0 | Nutzt schon `dark:` teils — als Vorbild ansehen |
|
||||
|
||||
**Gesamt: 428 Ternaries.** Bereits `dark:`-Klassen im Code: nur 7 —
|
||||
d. h. `ToastContext` und Reste zeigen das Zielbild.
|
||||
|
||||
**Empfohlene Reihenfolge:** erst Schicht A (Primitives + `design.ts`),
|
||||
dann die kleinen Dateien (`ConfirmDialog`, `App`, `LiveLogSection`) als
|
||||
Kalibrierung, dann die großen. `Settings.tsx` zuletzt (größter Nutzen aus
|
||||
den dann fertigen Primitives).
|
||||
|
||||
---
|
||||
|
||||
## 7. Arbeitsweise & Branch
|
||||
|
||||
- **Auf einem eigenen Branch arbeiten** (angelegt: `design-2.0`). Wichtig:
|
||||
Die Deploy-Kette befördert **nur `main`** automatisch auf `stable` und
|
||||
von dort auf die Live-VM. Ein Feature-Branch lässt die Ampel laufen
|
||||
(Feedback grün/rot), deployt aber NICHT — ideal für einen großen Umbau.
|
||||
Erst wenn Design 2.0 fertig & abgenommen ist, wird der Branch nach `main`
|
||||
gemerged.
|
||||
- **Klein committen**, eine sinnvolle Einheit pro Commit (z. B. „Primitives:
|
||||
Card + Button", dann „Dashboard auf Primitives umgestellt"). Commit-Text
|
||||
Deutsch, WAS + WARUM.
|
||||
- **Nach jeder Komponente**: `npm run build` muss grün sein. Nie einen
|
||||
roten Zwischenstand pushen.
|
||||
- Visuell gegenprüfen: hell UND dunkel testen (Theme-Umschalter oben in der
|
||||
Sidebar).
|
||||
|
||||
---
|
||||
|
||||
## 8. Verifikation (die exakten Befehle)
|
||||
|
||||
```bash
|
||||
cd docker/ui
|
||||
npm ci # einmalig
|
||||
npm run build # MUSS grün sein — das prüft auch die Ampel
|
||||
```
|
||||
|
||||
Lokal ansehen (Dev-Server):
|
||||
```bash
|
||||
cd docker/ui && npm run dev
|
||||
```
|
||||
Das UI erwartet die API unter `/api` (nginx-Proxy). Für reine Design-
|
||||
Arbeit reicht der Dev-Server; leere Listen/Fehlerzustände sind normal ohne
|
||||
laufendes Backend. Wer gegen echte Daten testen will: Das Live-System läuft
|
||||
im Heimnetz (Zugang beim Commander erfragen).
|
||||
|
||||
Die **komplette** Ampel (wie in CI) prüft zusätzlich Backend-Tests — die
|
||||
sind von reiner UI-Arbeit nicht betroffen, müssen aber grün bleiben (nicht
|
||||
anfassen).
|
||||
|
||||
---
|
||||
|
||||
## 9. Definition of Done
|
||||
|
||||
- [ ] `src/components/ui/`-Primitives existieren und werden genutzt
|
||||
- [ ] Status/Typ/Level-Farben zentral (`src/lib/design.ts`), keine
|
||||
duplizierten Farb-Mappings mehr
|
||||
- [ ] `grep -rn "theme === 'dark'" src/` ergibt **~0** Treffer (idealerweise
|
||||
nur noch in `ThemeContext`/`App` das Nötigste)
|
||||
- [ ] Tote CSS-Variablen (`[data-theme="dark"]`) und globale `* {
|
||||
transition }` bereinigt
|
||||
- [ ] `ConfirmDialog` nutzt lucide statt Emoji
|
||||
- [ ] Hell- UND Dunkelmodus überall konsistent, keine „weiße Karte im
|
||||
Darkmode"-Ausrutscher
|
||||
- [ ] `npm run build` grün; keine neuen TS-Fehler/Warnungen
|
||||
- [ ] Keine funktionale Änderung (alle API-Calls/Flows identisch)
|
||||
- [ ] Alle deutschen Texte unverändert
|
||||
- [ ] Auf Branch `design-2.0`, sauber committet, bereit für Review/Merge
|
||||
|
||||
---
|
||||
|
||||
## 10. Copy-Paste-Startprompt für Gemini
|
||||
|
||||
> Du übernimmst „Design 2.0" für das Rippy-Web-UI (React + TypeScript +
|
||||
> Vite + TailwindCSS, `darkMode: 'class'`). Lies zuerst
|
||||
> `docs/DESIGN-2.0-BRIEFING.md` KOMPLETT — dort stehen Auftrag, harte
|
||||
> Regeln, Datei-Inventar, empfohlener Weg und die Definition of Done.
|
||||
> Arbeite ausschließlich in `docker/ui/`, auf dem Branch `design-2.0`.
|
||||
> Kernauftrag: 428 `theme === 'dark' ? …`-Ternaries durch Tailwind-`dark:`-
|
||||
> Klassen + wiederverwendbare UI-Primitives ersetzen und die Optik
|
||||
> modernisieren — OHNE Funktion, API-Aufrufe oder deutsche Texte zu ändern.
|
||||
> Halte nach jeder umgestellten Komponente `npm run build` grün. Beginne
|
||||
> mit den UI-Primitives (`src/components/ui/`) und `src/lib/design.ts`,
|
||||
> dann die kleinen Dateien, dann die großen (`Settings.tsx` zuletzt).
|
||||
> Kommentare und Commit-Texte auf Deutsch.
|
||||
Reference in New Issue
Block a user