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
|
|
@ -23,42 +23,173 @@ import {
|
|||
DialogTrigger,
|
||||
} from '@/shared/components/ui/dialog'
|
||||
|
||||
// ─── palette data ────────────────────────────────────────────────────────────
|
||||
// ─── palette data — DA Charcoal ──────────────────────────────────────────────
|
||||
|
||||
const PALETTE: { token: string; var: string; light: string; dark: string }[] = [
|
||||
{ token: 'canvas', var: '--color-canvas', light: '#EEF2F8', dark: '#0D1220' },
|
||||
{ token: 'canvas-2', var: '--color-canvas-2', light: '#E6EBF4', dark: '#121A2D' },
|
||||
{ token: 'surface', var: '--color-surface', light: '#FFFFFF', dark: '#182238' },
|
||||
{ token: 'surface-hover', var: '--color-surface-hover', light: '#F8FAFD', dark: '#1E2A42' },
|
||||
{ token: 'line', var: '--color-line', light: '#DDE3ED', dark: '#27324B' },
|
||||
{ token: 'line-strong', var: '--color-line-strong', light: '#C7D0E0', dark: '#364363' },
|
||||
{ token: 'ink-1', var: '--color-ink-1', light: '#0F172A', dark: '#F1F4FA' },
|
||||
{ token: 'ink-2', var: '--color-ink-2', light: '#1E293B', dark: '#DDE3EF' },
|
||||
{ token: 'ink-3', var: '--color-ink-3', light: '#475569', dark: '#A8B2C7' },
|
||||
{ token: 'ink-4', var: '--color-ink-4', light: '#64748B', dark: '#7A8499' },
|
||||
{ token: 'ink-5', var: '--color-ink-5', light: '#94A3B8', dark: '#525C73' },
|
||||
{ token: 'expria', var: '--color-expria', light: '#1B4FD8', dark: '#5B7FFF' },
|
||||
{ token: 'expria-hover', var: '--color-expria-hover', light: '#1741B8', dark: '#6F8EFF' },
|
||||
{ token: 'expria-50', var: '--color-expria-50', light: '#EEF3FF', dark: 'rgba(91,127,255,.12)' },
|
||||
{ token: 'expria-100', var: '--color-expria-100', light: '#DCE6FF', dark: '—' },
|
||||
{ token: 'expria-200', var: '--color-expria-200', light: '#B8CDFF', dark: '—' },
|
||||
{ token: 'deep', var: '--color-deep', light: '#0B1F5C', dark: '#060B1A' },
|
||||
{ token: 'success', var: '--color-success', light: '#0E9F6E', dark: '#3DD68C' },
|
||||
interface PaletteEntry {
|
||||
token: string
|
||||
cssVar: string
|
||||
dark: string
|
||||
light: string
|
||||
group: 'Invariants' | 'Dark default' | 'Light override'
|
||||
}
|
||||
|
||||
const PALETTE: PaletteEntry[] = [
|
||||
// Invariants
|
||||
{
|
||||
token: 'success-bg',
|
||||
var: '--color-success-bg',
|
||||
light: '#E6F6F0',
|
||||
dark: 'rgba(61,214,140,.12)',
|
||||
token: 'sidebar-bg',
|
||||
cssVar: '--color-sidebar-bg',
|
||||
dark: '#0C1528',
|
||||
light: '#0C1528',
|
||||
group: 'Invariants',
|
||||
},
|
||||
{ token: 'warning', var: '--color-warning', light: '#C77A00', dark: '#F5B849' },
|
||||
{
|
||||
token: 'warning-bg',
|
||||
var: '--color-warning-bg',
|
||||
light: '#FEF3E2',
|
||||
dark: 'rgba(245,184,73,.12)',
|
||||
token: 'brand',
|
||||
cssVar: '--color-brand',
|
||||
dark: '#1B4FD8',
|
||||
light: '#1B4FD8',
|
||||
group: 'Invariants',
|
||||
},
|
||||
{
|
||||
token: 'brand-hover',
|
||||
cssVar: '--color-brand-hover',
|
||||
dark: '#1744B8',
|
||||
light: '#1744B8',
|
||||
group: 'Invariants',
|
||||
},
|
||||
{
|
||||
token: 'brand-active',
|
||||
cssVar: '--color-brand-active',
|
||||
dark: '#13379C',
|
||||
light: '#13379C',
|
||||
group: 'Invariants',
|
||||
},
|
||||
{
|
||||
token: 'warning',
|
||||
cssVar: '--color-warning',
|
||||
dark: '#F59E0B',
|
||||
light: '#F59E0B',
|
||||
group: 'Invariants',
|
||||
},
|
||||
{
|
||||
token: 'danger',
|
||||
cssVar: '--color-danger',
|
||||
dark: '#EF4444',
|
||||
light: '#EF4444',
|
||||
group: 'Invariants',
|
||||
},
|
||||
// Dual-theme (valeurs différentes dark/light)
|
||||
{
|
||||
token: 'canvas',
|
||||
cssVar: '--color-canvas',
|
||||
dark: '#111111',
|
||||
light: '#F3F4F6',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'surface',
|
||||
cssVar: '--color-surface',
|
||||
dark: 'rgba(255,255,255,.035)',
|
||||
light: '#FFFFFF',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'surface-hover',
|
||||
cssVar: '--color-surface-hover',
|
||||
dark: 'rgba(255,255,255,.055)',
|
||||
light: '#F8F9FB',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'surface-solid',
|
||||
cssVar: '--color-surface-solid',
|
||||
dark: '#1E1E1E',
|
||||
light: '#FFFFFF',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'surface-raised',
|
||||
cssVar: '--color-surface-raised',
|
||||
dark: '#222222',
|
||||
light: '#FFFFFF',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'border',
|
||||
cssVar: '--color-border',
|
||||
dark: 'rgba(255,255,255,.06)',
|
||||
light: 'rgba(0,0,0,.07)',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'border-strong',
|
||||
cssVar: '--color-border-strong',
|
||||
dark: 'rgba(255,255,255,.12)',
|
||||
light: 'rgba(0,0,0,.14)',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'ink-primary',
|
||||
cssVar: '--color-ink-primary',
|
||||
dark: '#E5E5E5',
|
||||
light: '#0F0F1A',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'ink-secondary',
|
||||
cssVar: '--color-ink-secondary',
|
||||
dark: 'rgba(255,255,255,.55)',
|
||||
light: 'rgba(0,0,0,.55)',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'ink-tertiary',
|
||||
cssVar: '--color-ink-tertiary',
|
||||
dark: 'rgba(255,255,255,.3)',
|
||||
light: 'rgba(0,0,0,.3)',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'brand-soft',
|
||||
cssVar: '--color-brand-soft',
|
||||
dark: 'rgba(27,79,216,.1)',
|
||||
light: 'rgba(27,79,216,.06)',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'brand-text',
|
||||
cssVar: '--color-brand-text',
|
||||
dark: '#7DA4F0',
|
||||
light: '#1B4FD8',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'success',
|
||||
cssVar: '--color-success',
|
||||
dark: '#4ADE80',
|
||||
light: '#16A34A',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'success-soft',
|
||||
cssVar: '--color-success-soft',
|
||||
dark: 'rgba(74,222,128,.12)',
|
||||
light: 'rgba(22,163,74,.1)',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'warning-soft',
|
||||
cssVar: '--color-warning-soft',
|
||||
dark: 'rgba(245,158,11,.12)',
|
||||
light: 'rgba(245,158,11,.12)',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{
|
||||
token: 'danger-soft',
|
||||
cssVar: '--color-danger-soft',
|
||||
dark: 'rgba(239,68,68,.12)',
|
||||
light: 'rgba(239,68,68,.12)',
|
||||
group: 'Dark default',
|
||||
},
|
||||
{ token: 'danger', var: '--color-danger', light: '#C53030', dark: '#F06B6B' },
|
||||
{ token: 'danger-bg', var: '--color-danger-bg', light: '#FDECEC', dark: 'rgba(240,107,107,.12)' },
|
||||
]
|
||||
|
||||
// ─── section wrapper ─────────────────────────────────────────────────────────
|
||||
|
|
@ -66,7 +197,9 @@ const PALETTE: { token: string; var: string; light: string; dark: string }[] = [
|
|||
function Section({ title, children }: { title: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<section className="space-y-4">
|
||||
<h2 className="text-base font-semibold text-ink-3 uppercase tracking-wider">{title}</h2>
|
||||
<h2 className="text-base font-semibold uppercase tracking-wider text-ink-secondary">
|
||||
{title}
|
||||
</h2>
|
||||
<Separator />
|
||||
{children}
|
||||
</section>
|
||||
|
|
@ -80,12 +213,14 @@ export default function DesignSystemPage() {
|
|||
const [dialogOpen, setDialogOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-canvas px-6 py-10 space-y-14">
|
||||
<div className="min-h-screen space-y-14 bg-canvas px-6 py-10">
|
||||
{/* ── header ── */}
|
||||
<header className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-ink-1">Design System</h1>
|
||||
<p className="text-sm text-ink-4 mt-0.5">Expria — Direction H palette · Sprint 0.5</p>
|
||||
<h1 className="text-2xl font-bold text-ink-primary">Design System</h1>
|
||||
<p className="mt-0.5 text-sm text-ink-secondary">
|
||||
Expria — DA Charcoal · dark-default + light override
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
|
|
@ -98,17 +233,17 @@ export default function DesignSystemPage() {
|
|||
|
||||
{/* ── palette ── */}
|
||||
<Section title="Palette">
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3">
|
||||
{PALETTE.map(({ token, var: cssVar, light, dark }) => (
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-4">
|
||||
{PALETTE.map(({ token, cssVar, light, dark }) => (
|
||||
<div key={token} className="flex flex-col gap-1.5">
|
||||
<div
|
||||
className="h-12 w-full rounded-md border border-line shadow-sm"
|
||||
className="h-12 w-full rounded-md border border-border shadow-card"
|
||||
style={{ background: `var(${cssVar})` }}
|
||||
/>
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-xs font-mono font-medium text-ink-2">{token}</p>
|
||||
<p className="text-xs font-mono text-ink-4 leading-tight">☀ {light}</p>
|
||||
<p className="text-xs font-mono text-ink-4 leading-tight">☾ {dark}</p>
|
||||
<p className="font-mono text-xs font-medium text-ink-primary">{token}</p>
|
||||
<p className="font-mono text-xs leading-tight text-ink-secondary">☾ {dark}</p>
|
||||
<p className="font-mono text-xs leading-tight text-ink-secondary">☀ {light}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -117,22 +252,22 @@ export default function DesignSystemPage() {
|
|||
|
||||
{/* ── typography ── */}
|
||||
<Section title="Typography">
|
||||
<div className="space-y-3 bg-surface rounded-lg p-6 border border-line">
|
||||
<p className="text-4xl font-bold text-ink-1">Display / 36px Bold</p>
|
||||
<p className="text-2xl font-semibold text-ink-1">Heading 1 / 24px Semibold</p>
|
||||
<p className="text-xl font-semibold text-ink-1">Heading 2 / 20px Semibold</p>
|
||||
<p className="text-lg font-medium text-ink-2">Heading 3 / 18px Medium</p>
|
||||
<p className="text-base text-ink-2">Body / 16px Regular — Plus Jakarta Sans</p>
|
||||
<p className="text-sm text-ink-3">Small / 14px Regular — secondary copy</p>
|
||||
<p className="text-xs text-ink-4">Caption / 12px Regular — labels, metadata</p>
|
||||
<p className="text-xs font-mono text-ink-3">Mono / 12px — token names, code</p>
|
||||
<div className="space-y-3 rounded-lg border border-border bg-surface p-6">
|
||||
<p className="text-4xl font-bold text-ink-primary">Display / 40px Bold</p>
|
||||
<p className="text-2xl font-semibold text-ink-primary">Heading 1 / 24px Semibold</p>
|
||||
<p className="text-xl font-semibold text-ink-primary">Heading 2 / 20px Semibold</p>
|
||||
<p className="text-lg font-medium text-ink-primary">Heading 3 / 17px Medium</p>
|
||||
<p className="text-base text-ink-primary">Body / 14px Regular — Plus Jakarta Sans</p>
|
||||
<p className="text-sm text-ink-secondary">Small / 13px Regular — secondary copy</p>
|
||||
<p className="text-xs text-ink-tertiary">Caption / 11px Regular — labels, metadata</p>
|
||||
<p className="font-mono text-xs text-ink-secondary">Mono / 11px — token names, code</p>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* ── buttons ── */}
|
||||
<Section title="Button">
|
||||
<div className="space-y-4 bg-surface rounded-lg p-6 border border-line">
|
||||
<div className="flex flex-wrap gap-2 items-center">
|
||||
<div className="space-y-4 rounded-lg border border-border bg-surface p-6">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button>Default</Button>
|
||||
<Button variant="secondary">Secondary</Button>
|
||||
<Button variant="outline">Outline</Button>
|
||||
|
|
@ -140,13 +275,13 @@ export default function DesignSystemPage() {
|
|||
<Button variant="destructive">Destructive</Button>
|
||||
<Button variant="link">Link</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2 items-center">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="lg">Large</Button>
|
||||
<Button>Default</Button>
|
||||
<Button size="sm">Small</Button>
|
||||
<Button size="icon">+</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2 items-center">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button disabled>Disabled</Button>
|
||||
<Button variant="outline" disabled>
|
||||
Outline disabled
|
||||
|
|
@ -157,7 +292,7 @@ export default function DesignSystemPage() {
|
|||
|
||||
{/* ── badges ── */}
|
||||
<Section title="Badge">
|
||||
<div className="flex flex-wrap gap-2 bg-surface rounded-lg p-6 border border-line">
|
||||
<div className="flex flex-wrap gap-2 rounded-lg border border-border bg-surface p-6">
|
||||
<Badge>Default</Badge>
|
||||
<Badge variant="secondary">Secondary</Badge>
|
||||
<Badge variant="outline">Outline</Badge>
|
||||
|
|
@ -167,7 +302,7 @@ export default function DesignSystemPage() {
|
|||
|
||||
{/* ── inputs / forms ── */}
|
||||
<Section title="Input · Label · Progress · Separator">
|
||||
<div className="space-y-5 bg-surface rounded-lg p-6 border border-line max-w-md">
|
||||
<div className="max-w-md space-y-5 rounded-lg border border-border bg-surface p-6">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="ds-email">Email</Label>
|
||||
<Input id="ds-email" type="email" placeholder="you@expria.io" />
|
||||
|
|
@ -185,33 +320,33 @@ export default function DesignSystemPage() {
|
|||
<Progress value={65} />
|
||||
</div>
|
||||
<Separator />
|
||||
<p className="text-sm text-ink-4">Content below separator</p>
|
||||
<p className="text-sm text-ink-secondary">Content below separator</p>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* ── avatar ── */}
|
||||
<Section title="Avatar">
|
||||
<div className="flex flex-wrap items-end gap-6 bg-surface rounded-lg p-6 border border-line">
|
||||
<div className="flex flex-wrap items-end gap-6 rounded-lg border border-border bg-surface p-6">
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarImage src="" />
|
||||
<AvatarFallback>HK</AvatarFallback>
|
||||
</Avatar>
|
||||
<span className="text-xs text-ink-4">sm</span>
|
||||
<span className="text-xs text-ink-secondary">sm</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Avatar>
|
||||
<AvatarImage src="" />
|
||||
<AvatarFallback>HK</AvatarFallback>
|
||||
</Avatar>
|
||||
<span className="text-xs text-ink-4">default</span>
|
||||
<span className="text-xs text-ink-secondary">default</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Avatar size="lg">
|
||||
<AvatarImage src="" />
|
||||
<AvatarFallback>HK</AvatarFallback>
|
||||
</Avatar>
|
||||
<span className="text-xs text-ink-4">lg</span>
|
||||
<span className="text-xs text-ink-secondary">lg</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<AvatarGroup>
|
||||
|
|
@ -222,14 +357,14 @@ export default function DesignSystemPage() {
|
|||
))}
|
||||
<AvatarGroupCount>+5</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
<span className="text-xs text-ink-4">group</span>
|
||||
<span className="text-xs text-ink-secondary">group</span>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* ── dialog ── */}
|
||||
<Section title="Dialog">
|
||||
<div className="bg-surface rounded-lg p-6 border border-line">
|
||||
<div className="rounded-lg border border-border bg-surface p-6">
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Open dialog</Button>
|
||||
|
|
@ -238,8 +373,8 @@ export default function DesignSystemPage() {
|
|||
<DialogHeader>
|
||||
<DialogTitle>Example dialog</DialogTitle>
|
||||
<DialogDescription>
|
||||
This dialog uses Direction H tokens — bg-surface, border-line, text-ink-4. Toggle
|
||||
the theme to see it adapt.
|
||||
This dialog uses DA Charcoal tokens — bg-surface-solid, border-border,
|
||||
text-ink-secondary. Toggle the theme to see it adapt.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter showCloseButton>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue