From 50df83fda1b3cb3daa7997b4ccb7059030f5ae02 Mon Sep 17 00:00:00 2001 From: Gilles Soulier Date: Fri, 5 Jun 2026 04:52:50 +0200 Subject: [PATCH] docs: spec jalon 2 (polish design system) Co-Authored-By: Claude Opus 4.8 --- ...6-05-jalon2-polish-design-system-design.md | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-05-jalon2-polish-design-system-design.md diff --git a/docs/superpowers/specs/2026-06-05-jalon2-polish-design-system-design.md b/docs/superpowers/specs/2026-06-05-jalon2-polish-design-system-design.md new file mode 100644 index 0000000..946098c --- /dev/null +++ b/docs/superpowers/specs/2026-06-05-jalon2-polish-design-system-design.md @@ -0,0 +1,107 @@ +# Jalon 2 — Polish design system — Design + +> Spec du deuxième jalon : refonte de l'UI avec le design system Gruvbox seventies. +> Statut : **validé** (2026-06-05). Langue de travail : français. +> Voir aussi : `CLAUDE.md`, `design_system/consigne_design_system.md`, jalon 1 (`docs/superpowers/specs/2026-06-04-jalon1-tranche-verticale-apt-design.md`). + +## Objectif + +Le jalon 1 a livré une UI fonctionnelle mais "brute" : des `` (ouvre la modale via callback remonté), et ``. Hauteur 48-56px, fond `--bg-2`. +- **`StatusBar.tsx`** : 1re cellule mode « SYSTEM UPDATE » fond `--accent` ; cellules suivantes séparées par `border-right: 1px solid var(--border-1)` ; nb machines, total updates ; horloge live (Share Tech Mono, tick 1s via `setInterval`, nettoyé au démontage) à droite. Hauteur 24-28px. +- **`lib/theme.ts`** : + - `type Theme = "dark" | "light"` + - `getInitialTheme(): Theme` — lit `localStorage["su-theme"]`, défaut `"dark"`, robuste si localStorage indisponible. + - `applyTheme(t: Theme): void` — `document.documentElement.dataset.theme = t` + persiste. + - `nextTheme(t: Theme): Theme` — bascule dark↔light (fonction pure, testable). +- **`lib/stats.ts`** : `sumUpdates(counts: Record): number` (fonction pure, testable). + +### Refondus +- **`MachineTile.tsx`** : point d'état → `` ; compteur → `UPDATES {count}` ; actions → ``, ``, ``. Conserver `className="glass"`, `onClick` sélection (les IconButton stoppent la propagation). +- **`AddMachineModal.tsx`** : enveloppé dans `` ; footer = `` + `` ; champs en inputs tokenisés ; erreur affichée avec `` + texte `--err`. Logique de soumission inchangée (POST /api/machines). +- **`Dashboard.tsx`** : retirer le bouton « + Ajouter » local (déplacé dans le Header) ; le Dashboard expose l'ouverture de la modale via prop/état remonté à `App`. Grille de tuiles inchangée. État vide : texte `--ink-3`. +- **`HermesPanel.tsx`** : en-tête `.label` + `` (ou autre), texte stub inchangé. +- **`TerminalPanel.tsx`** : ajouter un petit en-tête `.label` « TERMINAL · {machineId ?? "—"} » au-dessus du conteneur xterm. xterm inchangé. + +## Flux thème + +Au montage de `App` : `applyTheme(getInitialTheme())`. État `theme` dans `App` ; le toggle du Header appelle `setTheme(nextTheme(theme))` puis `applyTheme`. `data-theme` initial dans `index.html` reste `dark` (cohérent avec le défaut). + +## Gestion d'erreurs / cas limites +- `localStorage` indisponible (mode privé) → `getInitialTheme` retombe sur `"dark"`, `applyTheme` ignore l'échec de persistance (try/catch) sans casser l'UI. +- Icône inconnue → le composant `Icon` retombe déjà sur `circle-question`. +- Horloge : l'intervalle est nettoyé dans le cleanup du `useEffect`. + +## Tests +- **`lib/theme.test.ts`** : `nextTheme("dark")==="light"` et inverse ; `getInitialTheme()` retombe sur `"dark"` quand localStorage vide. (localStorage mocké, pas d'import de `ui-kit`.) +- **`lib/stats.test.ts`** : `sumUpdates({a:2,b:3})===5` ; `sumUpdates({})===0`. +- Vérif build : `pnpm check` + `pnpm build` verts. +- **Vérif visuelle manuelle** (utilisateur) : dark ET light lisibles ; icônes FA affichées ; polices Inter/JetBrains Mono/Share Tech Mono appliquées ; tooltips sur les IconButton ; modale Popup OK ; status bar + horloge ; aucun hover sur boutons/tuiles (pression 3D seulement). + +## Critères d'acceptation +- [ ] `ui-kit` exporte ses composants en ESM ; les écrans les importent (plus aucun `