# 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:
```
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 `` ✅
- Damit funktionieren Tailwinds `dark:`-Varianten sofort überall.
Konkret heißt Migration also fast immer nur:
```tsx
// NACHHER — kein Ternary, kein useDarkMode nötig:
```
### 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.