diff --git a/docs/DEVELOPMENT_PRINCIPLES.md b/docs/DEVELOPMENT_PRINCIPLES.md index 9d70607..4257a81 100644 --- a/docs/DEVELOPMENT_PRINCIPLES.md +++ b/docs/DEVELOPMENT_PRINCIPLES.md @@ -143,6 +143,24 @@ Voir `SECURITY.md` pour le détail. Claude Code ne crée jamais de worktree Git. Toutes les modifications se font directement dans le dossier du projet principal. +### Règle L — Tokens du design system, jamais de valeurs brutes +Toutes les couleurs dans le JSX passent exclusivement par les tokens Direction H : +- Utilitaires Tailwind : `bg-canvas`, `text-ink-2`, `border-line`, `bg-expria`, `text-danger`, etc. +- Jamais de classes couleur Tailwind par défaut : `bg-slate-100`, `text-gray-500`, `blue-600`… +- Jamais de valeurs inline brutes : `#1B4FD8`, `oklch(…)`, `rgb(…)` dans les className ou style +- Pour les inline styles dynamiques uniquement : `style={{ background: 'var(--color-expria)' }}` +- Tout nouveau token est ajouté exclusivement dans `@theme {}` (et `.dark {}`) de `src/index.css` + +```tsx +// ❌ JAMAIS +
+
+ +// ✅ TOUJOURS +
+
{/* inline style dynamique uniquement */} +``` + --- ## 3. Structure du code — conventions @@ -461,3 +479,4 @@ Avant chaque session Claude Code, vérifier : | Version | Date | Changements | |---|---|---| | 1.0 | 2026-04-17 | Création, adaptée de la version backend | +| 1.1 | 2026-04-18 | Ajout Règle L — tokens du design system (Sprint 0.5) | diff --git a/docs/TECH_DEBT.md b/docs/TECH_DEBT.md index 315c96f..c7beafa 100644 --- a/docs/TECH_DEBT.md +++ b/docs/TECH_DEBT.md @@ -123,30 +123,41 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s --- -### FTD-11 — `@theme` Tailwind 4 non défini -**Priorité :** 🟢 Mineur -**Statut :** Ouvert — à faire dans session design system -**Estimation de session :** 1 jour (palette + typo + itérations design) -**Description :** `src/index.css` a été nettoyé à l'étape 11 du Sprint 0 et réduit à la seule ligne `@import 'tailwindcss';`. L'ADR 006 (§Configuration Tailwind 4) décrit le bloc `@theme { ... }` comme le mécanisme officiel de configuration Tailwind 4 (CSS-first) : +### FTD-14 — Anti-FOUC thème : script inline manquant dans `` +**Priorité :** 🟡 Important +**Statut :** Ouvert — à faire avant déploiement production +**Estimation de session :** 30 min +**Description :** Le `ThemeProvider` applique la classe `.dark` sur `` après l'hydratation React (`useEffect`). Entre le premier paint du navigateur et l'exécution de React, la page s'affiche brièvement en mode clair même si l'utilisateur a choisi le mode sombre — c'est le FOUC (Flash Of Unstyled Content). -```css -@theme { - --color-primary: #1B4FD8; - --font-sans: 'Plus Jakarta Sans', system-ui, sans-serif; -} +**Fix :** ajouter un script inline bloquant dans le `` de `index.html` qui lit `localStorage.getItem('expria-theme')` (et `prefers-color-scheme` en fallback) et applique `.dark` sur `document.documentElement` avant le premier paint. Ce script doit être minifié et inliné (non-async, non-defer) pour garantir l'exécution avant le CSS. + +```html + ``` -La palette brand Expria et la typographie ne sont pas encore décidées, donc `@theme` est volontairement absent pour ne pas poser de valeurs placeholder qu'il faudrait repasser plus tard. +**Impact actuel :** visible uniquement pour les utilisateurs en mode sombre — bref flash de fond clair au chargement. Acceptable en dev, indésirable en production. -**Impact actuel :** les composants utilisent les couleurs Tailwind par défaut (`bg-slate-*`, `text-gray-*`). Visuellement cohérent mais pas brand. +**Condition de résolution :** avant la première mise en production (Sprint 1 ou avant). -**À faire au Sprint 1 (design system) :** -- Définir la palette brand Expria (primary, secondary, neutrals, danger, success) -- Choisir + installer la typo (Plus Jakarta Sans ou autre) via `` dans `index.html` ou `@import` dans `index.css` -- Ajouter le bloc `@theme` dans `src/index.css` -- Mettre à jour ADR 006 avec les valeurs retenues +--- -**Condition de résolution :** Sprint 1 — session dédiée au design system. +### FTD-15 — Option `'system'` manquante dans ThemeProvider +**Priorité :** 🟢 Mineur +**Statut :** Reporté — après MVP +**Estimation de session :** 2h +**Description :** Le `ThemeProvider` est bi-state (`'light' | 'dark'`). L'option `'system'` (qui suit `prefers-color-scheme` en temps réel via `MediaQueryList.addEventListener`) a été volontairement différée (décision Sprint 0.5). + +**À faire :** +- Étendre le type `Theme` à `'light' | 'dark' | 'system'` +- Dans `ThemeProvider`, si `theme === 'system'` : écouter `matchMedia('(prefers-color-scheme: dark)')` et appliquer/retirer `.dark` dynamiquement +- `ThemeToggle` : cycle light → dark → system (ou un sélecteur 3 états) +- Mettre à jour `getInitialTheme()` pour retourner `'system'` si aucune préférence stockée + +**Condition de résolution :** après MVP — confort utilisateur, pas bloquant. --- @@ -244,6 +255,7 @@ La palette brand Expria et la typographie ne sont pas encore décidées, donc `@ | ID | Description | Résolu le | Comment | |---|---|---|---| +| FTD-11 | `@theme` Tailwind 4 non défini — palette et typographie absentes | 2026-04-18 | Résolu au Sprint 0.5 (design system). Palette Direction H complète (canvas/surface/ink/expria/deep/semantic) + typo Plus Jakarta Sans définis dans `src/index.css` via `@theme {}` et `.dark {}`. shadcn/ui remappé sur ces tokens. Règle L ajoutée dans `DEVELOPMENT_PRINCIPLES.md` pour garantir l'usage exclusif des tokens. | | FTD-13 | Incompatibilité Vitest 3 / Vite 8 (conflit de types `Plugin` entre le Vite 8 top-level avec Rolldown et le Vite 7 pinné de Vitest 3.2.4 ; `npm run build` cassé) | 2026-04-17 | Résolu par upgrade Vitest `3.2.4 → 4.1.4` (et `@vitest/coverage-v8` idem) à l'étape 12-bis du Sprint 0. Vitest 4.x supporte nativement Vite 8 Rolldown. Correctif complémentaire : script `typecheck` passé de `tsc --noEmit -p tsconfig.app.json` à `tsc -b --noEmit` pour couvrir aussi `tsconfig.node.json` (d'où `vite.config.ts`) et éviter qu'un bug similaire échappe à la CI. | --- @@ -255,3 +267,4 @@ La palette brand Expria et la typographie ne sont pas encore décidées, donc `@ | 1.0 | 2026-04-17 | Création initiale avec 9 FTD identifiées depuis l'audit backend et les décisions d'architecture | | 1.1 | 2026-04-17 | Ajout FTD-10 (Semgrep CI), FTD-11 (`@theme` Tailwind 4), FTD-12 (tests `api-client`) suite à l'étape 11 du Sprint 0 | | 1.2 | 2026-04-17 | Ajout FTD-13 résolu (incompatibilité Vitest 3 / Vite 8) suite à l'étape 12-bis du Sprint 0 | +| 1.3 | 2026-04-18 | FTD-11 résolu (design system Sprint 0.5) ; ajout FTD-14 (anti-FOUC), FTD-15 (option 'system' thème) | diff --git a/src/shared/components/Logo.tsx b/src/shared/components/Logo.tsx new file mode 100644 index 0000000..f1573d5 --- /dev/null +++ b/src/shared/components/Logo.tsx @@ -0,0 +1,46 @@ +import { cn } from '@/shared/lib/utils' + +type LogoSize = 'sm' | 'md' +type LogoVariant = 'icon' | 'full' + +interface LogoProps { + size?: LogoSize + variant?: LogoVariant + className?: string +} + +const markStyles: Record = { + sm: 'size-6 text-[11px]', + md: 'size-8 text-[13px]', +} + +const wordmarkStyles: Record = { + sm: 'text-sm', + md: 'text-base', +} + +export function Logo({ size = 'md', variant = 'full', className }: LogoProps) { + return ( +
+ + {variant === 'full' && ( + Expria + )} +
+ ) +} diff --git a/src/shared/components/ThemeToggle.tsx b/src/shared/components/ThemeToggle.tsx new file mode 100644 index 0000000..5189302 --- /dev/null +++ b/src/shared/components/ThemeToggle.tsx @@ -0,0 +1,24 @@ +import { Moon, Sun } from 'lucide-react' +import { useTheme } from '@/shared/hooks/useTheme' +import { Button } from '@/shared/components/ui/button' + +interface ThemeToggleProps { + className?: string +} + +export function ThemeToggle({ className }: ThemeToggleProps) { + const { theme, setTheme } = useTheme() + const isDark = theme === 'dark' + + return ( + + ) +}