feat(design-system): reskin Charcoal — tokens dark-default + sidebar navy permanent
- Remplacement intégral index.css par palette Charcoal (DESIGN_SYSTEM.md v2.0)
- Dark = thème par défaut, .light = override via @custom-variant light
- Sidebar navy #0C1528 permanent (identique dark+light)
- Script anti-FOUC inline dans index.html
- Layout : radial-gradient sur <main>, sidebar 230px, max-w-[1100px]
- Renommage tokens Boréal→Charcoal sur ~45 composants
- Inversion dark: → baseline + light: sur primitives shadcn
- Fix logo blanc forcé dans sidebar
- ADR 006 mis à jour
Typecheck: OK · Tests: 122/122 ✅
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
407d1bd134
commit
b68f160bce
61 changed files with 1269 additions and 726 deletions
|
|
@ -107,85 +107,116 @@ Garder React 19, Vite 8, TypeScript 6 mais downgrader Tailwind 4 → 3 pour "com
|
|||
|
||||
Pas de `tailwind.config.ts`. La configuration se fait exclusivement dans `src/index.css`.
|
||||
|
||||
#### Dark mode
|
||||
#### Mode thème (mis à jour Sprint DA Charcoal — 2026-04-24)
|
||||
|
||||
Dark mode class-based (`.dark` sur `<html>`) — toggle manuel via ThemeProvider React (Sprint 0.5 étape 2). Configuré via :
|
||||
**Dark est le thème par défaut.** Les tokens de contenu (`--color-canvas`, `--color-ink-*`, etc.) sont déclarés en mode dark dans `@theme`. Une classe `.light` sur `<html>` active le mode clair en override. Configuré via :
|
||||
|
||||
```css
|
||||
@variant dark (&:where(.dark, .dark *));
|
||||
@custom-variant light (&:where(.light, .light *));
|
||||
```
|
||||
|
||||
Si cette syntaxe est rejetée par une future version de Tailwind 4, le fallback est `@custom-variant dark (...)`.
|
||||
Ce variant permet d'écrire `light:bg-surface` dans les composants quand un comportement spécifique au mode clair est requis (ex. primitives shadcn où l'opacité doit être adaptée).
|
||||
|
||||
#### Tokens @theme (palette Direction H — validée Sprint 0.5)
|
||||
#### Tokens @theme (DA Charcoal — validée Sprint DA Charcoal 2026-04-24)
|
||||
|
||||
```css
|
||||
@import 'tailwindcss';
|
||||
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');
|
||||
|
||||
@variant dark (&:where(.dark, .dark *));
|
||||
@custom-variant light (&:where(.light, .light *));
|
||||
|
||||
@theme {
|
||||
/* Typographie */
|
||||
--font-sans: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||
system-ui, sans-serif;
|
||||
/* ── Invariants (identiques dark + light) ── */
|
||||
|
||||
/* Fonds — bg-canvas = page, bg-surface = cards */
|
||||
--color-canvas: #EEF2F8;
|
||||
--color-canvas-2: #E6EBF4;
|
||||
--color-surface: #FFFFFF;
|
||||
--color-surface-hover: #F8FAFD;
|
||||
|
||||
/* Hairlines */
|
||||
--color-line: #DDE3ED;
|
||||
--color-line-strong: #C7D0E0;
|
||||
|
||||
/* Encres */
|
||||
--color-ink-1: #0F172A; /* titres */
|
||||
--color-ink-2: #1E293B; /* corps */
|
||||
--color-ink-3: #475569;
|
||||
--color-ink-4: #64748B;
|
||||
--color-ink-5: #94A3B8; /* désactivé, hints */
|
||||
/* Sidebar navy permanent */
|
||||
--color-sidebar-bg: #0C1528;
|
||||
--color-sidebar-border: rgba(255, 255, 255, 0.07);
|
||||
--color-sidebar-text: rgba(255, 255, 255, 0.6);
|
||||
--color-sidebar-text-hover: rgba(255, 255, 255, 0.9);
|
||||
--color-sidebar-text-active: #FFFFFF;
|
||||
--color-sidebar-nav-hover: rgba(255, 255, 255, 0.07);
|
||||
--color-sidebar-nav-active: rgba(255, 255, 255, 0.1);
|
||||
--color-sidebar-section-label: rgba(255, 255, 255, 0.3);
|
||||
|
||||
/* Brand */
|
||||
--color-expria: #1B4FD8;
|
||||
--color-expria-hover: #1741B8;
|
||||
--color-expria-50: #EEF3FF;
|
||||
--color-expria-100: #DCE6FF;
|
||||
--color-expria-200: #B8CDFF;
|
||||
--color-deep: #0B1F5C;
|
||||
--color-deep-2: #142B6E;
|
||||
--color-brand: #1B4FD8;
|
||||
--color-brand-hover: #1744B8;
|
||||
--color-brand-active: #13379C;
|
||||
--color-brand-dark: #1740B0;
|
||||
--color-brand-ink: #FFFFFF;
|
||||
|
||||
/* Sémantiques */
|
||||
--color-success: #0E9F6E; --color-success-bg: #E6F6F0;
|
||||
--color-warning: #C77A00; --color-warning-bg: #FEF3E2;
|
||||
--color-danger: #C53030; --color-danger-bg: #FDECEC;
|
||||
/* Semantic (invariants) */
|
||||
--color-warning: #F59E0B;
|
||||
--color-warning-soft: rgba(245, 158, 11, 0.12);
|
||||
--color-danger: #EF4444;
|
||||
--color-danger-soft: rgba(239, 68, 68, 0.12);
|
||||
|
||||
/* Rayons */
|
||||
--radius-sm: 6px; --radius-md: 10px;
|
||||
--radius-lg: 14px; --radius-xl: 18px; --radius-full: 999px;
|
||||
/* Typographie */
|
||||
--font-sans: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
|
||||
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace;
|
||||
|
||||
/* Ombres */
|
||||
--shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.04);
|
||||
--shadow-md: 0 4px 12px rgba(15, 23, 42, 0.06), 0 1px 3px rgba(15, 23, 42, 0.04);
|
||||
--shadow-lg: 0 12px 28px rgba(15, 23, 42, 0.08), 0 2px 6px rgba(15, 23, 42, 0.04);
|
||||
/* Rayons (override Tailwind) */
|
||||
--radius-xs: 6px; --radius-sm: 8px; --radius-md: 12px;
|
||||
--radius-lg: 16px; --radius-xl: 20px; --radius-pill: 999px;
|
||||
|
||||
/* Focus */
|
||||
--shadow-focus: 0 0 0 3px rgba(27, 79, 216, 0.18);
|
||||
|
||||
/* ── Dark mode (défaut) ── */
|
||||
--color-canvas: #111111;
|
||||
--color-surface: rgba(255, 255, 255, 0.035);
|
||||
--color-surface-hover: rgba(255, 255, 255, 0.055);
|
||||
--color-surface-solid: #1E1E1E;
|
||||
--color-surface-raised: #222222;
|
||||
--color-border: rgba(255, 255, 255, 0.06);
|
||||
--color-border-strong: rgba(255, 255, 255, 0.12);
|
||||
|
||||
--color-ink-primary: #E5E5E5;
|
||||
--color-ink-secondary: rgba(255, 255, 255, 0.55);
|
||||
--color-ink-tertiary: rgba(255, 255, 255, 0.3);
|
||||
--color-ink-inverse: #111111;
|
||||
|
||||
--color-brand-soft: rgba(27, 79, 216, 0.1);
|
||||
--color-brand-text: #7DA4F0;
|
||||
|
||||
--color-success: #4ADE80;
|
||||
--color-success-soft: rgba(74, 222, 128, 0.12);
|
||||
|
||||
--color-topbar-bg: rgba(17, 17, 17, 0.88);
|
||||
--color-gradient-a: rgba(27, 79, 216, 0.05);
|
||||
--color-gradient-b: rgba(27, 79, 216, 0.03);
|
||||
|
||||
--shadow-card: none;
|
||||
--shadow-raised: none;
|
||||
}
|
||||
|
||||
/* Dark mode overrides */
|
||||
.dark {
|
||||
--color-canvas: #0D1220; --color-canvas-2: #121A2D;
|
||||
--color-surface: #182238; --color-surface-hover: #1E2A42;
|
||||
--color-line: #27324B; --color-line-strong: #364363;
|
||||
--color-ink-1: #F1F4FA; --color-ink-2: #DDE3EF;
|
||||
--color-ink-3: #A8B2C7; --color-ink-4: #7A8499; --color-ink-5: #525C73;
|
||||
--color-expria: #5B7FFF; --color-expria-hover: #6F8EFF;
|
||||
--color-expria-50: rgba(91, 127, 255, 0.12);
|
||||
--color-deep: #060B1A;
|
||||
--color-success: #3DD68C; --color-success-bg: rgba(61, 214, 140, 0.12);
|
||||
--color-warning: #F5B849; --color-warning-bg: rgba(245, 184, 73, 0.12);
|
||||
--color-danger: #F06B6B; --color-danger-bg: rgba(240, 107, 107, 0.12);
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.4);
|
||||
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5);
|
||||
/* Light mode — override sur <html class="light"> */
|
||||
.light {
|
||||
--color-canvas: #F3F4F6;
|
||||
--color-surface: #FFFFFF;
|
||||
--color-surface-hover: #F8F9FB;
|
||||
--color-surface-solid: #FFFFFF;
|
||||
--color-surface-raised: #FFFFFF;
|
||||
--color-border: rgba(0, 0, 0, 0.07);
|
||||
--color-border-strong: rgba(0, 0, 0, 0.14);
|
||||
|
||||
--color-ink-primary: #0F0F1A;
|
||||
--color-ink-secondary: rgba(0, 0, 0, 0.55);
|
||||
--color-ink-tertiary: rgba(0, 0, 0, 0.3);
|
||||
--color-ink-inverse: #FFFFFF;
|
||||
|
||||
--color-brand-soft: rgba(27, 79, 216, 0.06);
|
||||
--color-brand-text: #1B4FD8;
|
||||
|
||||
--color-success: #16A34A;
|
||||
--color-success-soft: rgba(22, 163, 74, 0.1);
|
||||
|
||||
--color-topbar-bg: rgba(243, 244, 246, 0.88);
|
||||
--color-gradient-a: rgba(27, 79, 216, 0.025);
|
||||
--color-gradient-b: rgba(27, 79, 216, 0.01);
|
||||
|
||||
--shadow-card: 0 1px 2px rgba(15, 18, 32, 0.04), 0 1px 8px rgba(15, 18, 32, 0.03);
|
||||
--shadow-raised: 0 4px 16px rgba(15, 18, 32, 0.06), 0 1px 2px rgba(15, 18, 32, 0.04);
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -196,14 +227,23 @@ Les tokens `@theme` créent des classes utilitaires directement utilisables :
|
|||
| Token | Classes Tailwind |
|
||||
|---|---|
|
||||
| `--color-canvas` | `bg-canvas`, `text-canvas`, `border-canvas` |
|
||||
| `--color-surface` | `bg-surface`, `text-surface`, `border-surface` |
|
||||
| `--color-ink-1` | `text-ink-1`, `bg-ink-1` |
|
||||
| `--color-expria` | `bg-expria`, `text-expria`, `border-expria` |
|
||||
| `--color-success` | `text-success`, `bg-success` |
|
||||
| `--radius-md` | `rounded-md` (override : 10px au lieu de 6px Tailwind) |
|
||||
| `--shadow-sm` | `shadow-sm` (override valeurs Tailwind) |
|
||||
| `--color-surface` | `bg-surface`, `border-surface` |
|
||||
| `--color-surface-hover` | `bg-surface-hover` |
|
||||
| `--color-sidebar-bg` | `bg-sidebar-bg` (navy permanent, identique dark+light) |
|
||||
| `--color-ink-primary` | `text-ink-primary` |
|
||||
| `--color-ink-secondary` | `text-ink-secondary` |
|
||||
| `--color-ink-tertiary` | `text-ink-tertiary` |
|
||||
| `--color-brand` | `bg-brand`, `border-brand`, `ring-brand` |
|
||||
| `--color-brand-text` | `text-brand-text` (bleu adapté au fond — `#7DA4F0` dark, `#1B4FD8` light) |
|
||||
| `--color-brand-soft` | `bg-brand-soft` (teinte chip / highlight discret) |
|
||||
| `--color-success-soft`, `-warning-soft`, `-danger-soft` | `bg-success-soft`, etc. |
|
||||
| `--shadow-card`, `--shadow-raised` | `shadow-card`, `shadow-raised` (auto dual-theme : `none` en dark, ombre en light) |
|
||||
| `--shadow-focus` | `shadow-focus` (halo bleu 3px sur `:focus-visible`) |
|
||||
|
||||
**Convention critique** : `bg-surface` = cards / modals / panels. `bg-canvas` = fond de page. Ne jamais inverser.
|
||||
**Conventions critiques :**
|
||||
- `bg-surface` = cards / modals / panels. `bg-canvas` = fond de page. Ne jamais inverser.
|
||||
- `bg-sidebar-bg` = navy permanent — ne change jamais entre dark et light (ancre visuelle de marque).
|
||||
- Utiliser le préfixe `light:` uniquement quand un override spécifique au mode clair est strictement nécessaire (ex. primitives shadcn où l'opacité d'une couleur sémantique diffère).
|
||||
|
||||
#### Typographie
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue