# Design 2.0 — Briefing (Übergabe an Gemini) > ✅ **ERLEDIGT (24.07.2026).** Design 2.0 wurde umgesetzt und ist in `main`. > Der Arbeitsbranch `design-2.0` wurde nach dem Merge gelöscht (es gibt nur > noch `main`). Dieses Dokument bleibt als historische Auftragsbeschreibung. > > 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** (war: `design-2.0`). Ein Feature-Branch lässt die Ampel laufen (Feedback grün/rot), deployt aber nicht — ideal für einen großen Umbau; nach Abnahme nach `main` gemerged. (Hinweis: Seit 24.07.2026 ist `main` der einzige Branch — deployt wird direkt daraus, die Ampel prüft nur noch.) - **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.