chore: initial DSMMG v0.2 — refonte architecturale complète
Mise en place du Design System ManageMate Group v0.2 — refonte du
système de tokens (préfixe --mmg-color-*), 9 presets accent
user-themable validés WCAG AA, overlays Radix UI + Floating UI,
Storybook 8 + Vitest + axe-core en CI, doc Astro Starlight,
DESIGN.md (format google-labs-code) et exports tokens DTCG/CSS/
TS/Figma/Tailwind v3 et v4.
- 4 packages monorepo pnpm : @managemate/{tokens,css,react,icons}
- 62 composants React headless-first (Sheet, HoverCard, ContextMenu,
Slider, ToggleGroup, AvatarGroup, UserCard, ProfileHeader,
MetricCard, PricingCard, FeatureCard, Text/Display/Eyebrow/Lead…)
- Lint contraste WCAG : 37/37 paires AA, branché CI
- Toast pile Sonner-style avec ResizeObserver
- Theming user (9 presets) sans casser sémantique fixe
- Identité Synapse (rose #D12B6A) préservée
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import { defineConfig } from "astro/config";
|
||||
import starlight from "@astrojs/starlight";
|
||||
|
||||
export default defineConfig({
|
||||
site: "https://design.managemate.fr",
|
||||
integrations: [
|
||||
starlight({
|
||||
title: "DSMMG",
|
||||
description: "Design System ManageMate Group — référence pour designers et développeurs",
|
||||
defaultLocale: "fr",
|
||||
locales: { fr: { label: "Français", lang: "fr" } },
|
||||
logo: { src: "./src/assets/logo.svg", replacesTitle: false },
|
||||
social: {
|
||||
github: "https://github.com/managemate/dsmmg",
|
||||
},
|
||||
customCss: ["./src/styles/custom.css", "@managemate/css", "@managemate/icons"],
|
||||
sidebar: [
|
||||
{
|
||||
label: "Démarrer",
|
||||
items: [
|
||||
{ label: "Introduction", slug: "intro" },
|
||||
{ label: "Installation", slug: "intro/installation" },
|
||||
{ label: "Migration v0.1 → v0.2", slug: "intro/migration" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Fondations",
|
||||
items: [
|
||||
{ label: "Tokens", slug: "fondations/tokens" },
|
||||
{ label: "Couleurs", slug: "fondations/colors" },
|
||||
{ label: "Typographie", slug: "fondations/typography" },
|
||||
{ label: "Espacement", slug: "fondations/spacing" },
|
||||
{ label: "Motion", slug: "fondations/motion" },
|
||||
{ label: "Densité", slug: "fondations/density" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Theming utilisateur",
|
||||
items: [
|
||||
{ label: "Architecture accent", slug: "theming/architecture" },
|
||||
{ label: "Presets", slug: "theming/presets" },
|
||||
{ label: "Mode sombre", slug: "theming/dark-mode" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Accessibilité",
|
||||
items: [
|
||||
{ label: "Engagement RGAA", slug: "a11y/engagement" },
|
||||
{ label: "Tests automatisés", slug: "a11y/tests" },
|
||||
{ label: "Patterns clavier", slug: "a11y/keyboard" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Composants",
|
||||
autogenerate: { directory: "components" },
|
||||
},
|
||||
{
|
||||
label: "Patterns",
|
||||
autogenerate: { directory: "patterns" },
|
||||
},
|
||||
{
|
||||
label: "Contribution",
|
||||
items: [
|
||||
{ label: "Comment contribuer", slug: "contrib/how" },
|
||||
{ label: "RFC process", slug: "contrib/rfc" },
|
||||
{ label: "Versioning", slug: "contrib/versioning" },
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "astro dev --port 4321",
|
||||
"start": "astro dev --port 4321",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/starlight": "^0.30.0",
|
||||
"@managemate/css": "workspace:*",
|
||||
"@managemate/icons": "workspace:*",
|
||||
"astro": "^5.0.0",
|
||||
"sharp": "^0.33.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="32" height="32" aria-hidden="true">
|
||||
<rect width="64" height="64" rx="14" fill="#D12B6A"/>
|
||||
<path d="M14 46V18h6.4l8.8 13.5L38.1 18h6.3v28h-6.3V28.6l-7.6 11.6h-1.7l-7.5-11.5V46H14z" fill="#fff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 272 B |
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: Engagement RGAA
|
||||
description: Accessibilité = priorité non-négociable du DSMMG.
|
||||
---
|
||||
|
||||
## Pourquoi
|
||||
|
||||
- **12M de Français** en situation de handicap (visuel, auditif, moteur, cognitif).
|
||||
- Plusieurs clients ManageMate sont des **collectivités, opérateurs publics ou entreprises >250M€ CA** → **soumis au RGAA par la loi**.
|
||||
- Sanctions jusqu'à **50 000 €** par service en ligne non conforme (LOI n° 2005-102 + décret 2019-768 + ordonnance 2018-1102).
|
||||
- Argument commercial fort sur les **appels d'offres publics**.
|
||||
|
||||
## Niveau cible
|
||||
|
||||
**RGAA 4.1 — équivalent WCAG 2.1 AA — couverture ≥ 95 %**, validé automatiquement en CI via `axe-core`.
|
||||
|
||||
## Couverture par composant
|
||||
|
||||
| Composant | axe-core | clavier | lecteur d'écran | Forced colors |
|
||||
|---|---|---|---|---|
|
||||
| Button | ✓ | ✓ Tab/Enter/Space | ✓ role + label | ✓ |
|
||||
| Input/Field | ✓ | ✓ | ✓ label, erreurs aria-describedby | ✓ |
|
||||
| Combobox | ✓ | ✓ flèches/Home/End/Enter/Esc | ✓ activedescendant | ✓ |
|
||||
| Tooltip (Radix) | ✓ | ✓ Esc | ✓ role=tooltip | ✓ |
|
||||
| Dialog (Radix) | ✓ | ✓ focus trap, Esc, restitution | ✓ aria-labelledby/describedby | ✓ |
|
||||
| Menu (Radix) | ✓ | ✓ flèches/type-ahead/Esc | ✓ menuitem | ✓ |
|
||||
| ThemePicker | ✓ | ✓ flèches/Home/End | ✓ radiogroup + radios labellés | ✓ |
|
||||
|
||||
## Refus absolus
|
||||
|
||||
- ❌ Couleur seule porteuse d'information
|
||||
- ❌ Placeholder en remplacement de label (RGAA 11.1)
|
||||
- ❌ Focus invisible ou supprimé sans alternative
|
||||
- ❌ `<div onClick>` au lieu de `<button>`
|
||||
- ❌ Animation sans `prefers-reduced-motion`
|
||||
- ❌ Contraste en-dessous de AA "pour le style"
|
||||
- ❌ Composant sans test axe-core
|
||||
- ❌ Composant sans navigation clavier complète
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
title: Patterns clavier
|
||||
description: Conventions clavier appliquées dans tous les composants DSMMG.
|
||||
---
|
||||
|
||||
## Patterns standard
|
||||
|
||||
| Composant | Touches |
|
||||
|---|---|
|
||||
| Button | `Enter` / `Space` |
|
||||
| Tab dans formulaire | `Tab` / `Shift+Tab` |
|
||||
| Modal / Dialog | `Esc` ferme, focus trap, restitution focus |
|
||||
| Tooltip | `Esc` ferme, focus trigger affiche |
|
||||
| Menu | `↓ ↑` navigue, `Enter` sélectionne, `type-ahead`, `Esc` ferme |
|
||||
| Combobox | `↓ ↑` navigue suggestions, `Home/End`, `Enter` sélectionne, `Esc` ferme |
|
||||
| Tabs | `← →` navigue (manual activation), `Enter` active |
|
||||
| ThemePicker (radiogroup) | `← → ↑ ↓ Home End` navigue + sélectionne |
|
||||
| Accordion | `Enter` / `Space` toggle |
|
||||
|
||||
## Raccourcis globaux
|
||||
|
||||
Le système de raccourcis (`ShortcutProvider`) propose :
|
||||
|
||||
- `Cmd/Ctrl + K` : ouvre `CommandMenu` (palette d'actions)
|
||||
- `?` : affiche la `ShortcutCheatsheet` contextuelle
|
||||
- Séquences (vim-style) supportées : `g i` = go to inbox, `g s` = go to settings
|
||||
|
||||
```tsx
|
||||
import { useShortcut } from "@managemate/react";
|
||||
|
||||
useShortcut(
|
||||
{ keys: "n", description: "Nouveau ticket", scope: "synapse" },
|
||||
() => createTicket(),
|
||||
);
|
||||
```
|
||||
|
||||
## Skip link
|
||||
|
||||
`<SkipLink />` à poser comme premier enfant de `<body>`. Sauts visuels Tab visibles. Cible : `<main id="main">` par défaut.
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: Tests automatisés
|
||||
description: Comment l'accessibilité est validée en CI.
|
||||
---
|
||||
|
||||
## Stack
|
||||
|
||||
- **Vitest** (runner)
|
||||
- **@testing-library/react** (rendu + interactions)
|
||||
- **@testing-library/user-event** (simulation clavier réaliste)
|
||||
- **vitest-axe** (axe-core 4.10 en assertions)
|
||||
- **jsdom** (environnement DOM)
|
||||
|
||||
## Exemple de test
|
||||
|
||||
```tsx
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { axe } from "vitest-axe";
|
||||
import { Button } from "./Button";
|
||||
|
||||
it("est focusable au clavier", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Button>OK</Button>);
|
||||
await user.tab();
|
||||
expect(screen.getByRole("button")).toHaveFocus();
|
||||
});
|
||||
|
||||
it("aucune violation axe-core", async () => {
|
||||
const { container } = render(<Button>OK</Button>);
|
||||
expect(await axe(container)).toHaveNoViolations();
|
||||
});
|
||||
```
|
||||
|
||||
## Politique CI
|
||||
|
||||
- Le job `test` du workflow CI échoue si :
|
||||
- une violation axe est détectée dans un test ;
|
||||
- un test clavier échoue ;
|
||||
- la couverture descend sous 60 % (threshold).
|
||||
|
||||
## Storybook a11y
|
||||
|
||||
Le panneau **Accessibility** (addon-a11y) s'affiche pour chaque story. Configuré pour `wcag2a + wcag2aa + wcag21a + wcag21aa + best-practice`.
|
||||
|
||||
## Tests manuels conseillés
|
||||
|
||||
axe-core couvre ~40 % des règles WCAG. Compléter par :
|
||||
|
||||
- **NVDA** (Windows) ou **VoiceOver** (macOS)
|
||||
- **Navigation 100 % clavier** (souris débranchée)
|
||||
- **Zoom 200 %** + reflow 320px de large
|
||||
- **`prefers-reduced-motion`** activé
|
||||
- **Forced colors / High Contrast Mode** (Windows)
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: Button
|
||||
description: Bouton DSMMG — variants Material 3 / Fluent, pill par défaut, tous états couverts.
|
||||
---
|
||||
|
||||
## Anatomie
|
||||
|
||||
```
|
||||
┌────────────────────────────────┐
|
||||
│ [icon] Label [trailing icon]│
|
||||
└────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Variants
|
||||
|
||||
| Variant | Quand l'utiliser |
|
||||
|---|---|
|
||||
| `primary` | Action principale d'une page/section. Un seul par bloc. |
|
||||
| `tonal` | Action importante mais pas la principale. |
|
||||
| `secondary` | Action neutre, outline accent. |
|
||||
| `tertiary` | Action discrète mais visible. |
|
||||
| `ghost` | Action très discrète, dans un toolbar. |
|
||||
| `elevated` | Quand le bouton flotte sur un fond chargé (image). |
|
||||
| `danger` | Suppression, action destructive. |
|
||||
| `success` | Validation positive (rare, généralement preferring primary). |
|
||||
|
||||
## Sizes
|
||||
|
||||
`xs` (28px), `sm` (34px), `md` (40px, défaut), `lg` (48px), `xl` (56px).
|
||||
|
||||
`md` et plus respectent la cible tactile WCAG 2.5.5 (≥ 44×44 effective). Pour `xs`/`sm` en `icon-only`, une zone tactile invisible 44×44 est ajoutée via `::after`.
|
||||
|
||||
## API
|
||||
|
||||
```tsx
|
||||
import { Button } from "@managemate/react";
|
||||
|
||||
<Button
|
||||
variant="primary"
|
||||
size="md"
|
||||
icon="arrow-right-line"
|
||||
iconPosition="right"
|
||||
loading={false}
|
||||
disabled={false}
|
||||
block={false}
|
||||
onClick={() => {}}
|
||||
>
|
||||
Continuer
|
||||
</Button>
|
||||
```
|
||||
|
||||
## Do / Don't
|
||||
|
||||
✅ **Do**
|
||||
|
||||
- Un seul `primary` par section logique.
|
||||
- Verbes d'action concrets : "Sauvegarder", "Continuer", "Supprimer".
|
||||
- `aria-label` sur les `icon-only`.
|
||||
|
||||
❌ **Don't**
|
||||
|
||||
- Pas de "Cliquez ici" / "Soumettre" / "OK" génériques.
|
||||
- Ne pas désactiver un bouton sans aria-explication ; préférer le rendre actif et afficher l'erreur après.
|
||||
- Ne pas remplacer un `<a>` (navigation) par un `<button>`. Sémantique avant tout.
|
||||
|
||||
## A11y
|
||||
|
||||
- `<button type="button">` natif. Sémantique correcte garantie.
|
||||
- `disabled` empêche `pointer-events` et le focus.
|
||||
- `loading` affiche un spinner et bloque les clicks ; pas d'`aria-busy` requis (le state est dans la classe).
|
||||
- Ratio de contraste : tous les variants respectent AA contre `--mmg-color-bg-surface` et `--mmg-color-bg-page`.
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Composants
|
||||
description: Catalogue des composants DSMMG.
|
||||
---
|
||||
|
||||
Les composants sont documentés en détail dans **Storybook** (live, props auto-générées). Cette section donne les guidelines (anatomie, do/don't, a11y).
|
||||
|
||||
→ [Storybook](https://design.managemate.fr/storybook)
|
||||
|
||||
## Catégories
|
||||
|
||||
| Catégorie | Composants |
|
||||
|---|---|
|
||||
| **Forms** | Button, Input, Textarea, Select, Combobox, Checkbox, Radio, Switch, Field, FileUpload, SearchBar |
|
||||
| **Layout** | Container, Section, Stack, Inline, Card, Tile, Hero |
|
||||
| **Feedback** | Alert, Notice, Banner, Badge, Spinner, Skeleton, Toast |
|
||||
| **Overlays** | Tooltip, Popover, Menu, Dialog, ConfirmDialog, Drawer |
|
||||
| **Navigation** | Header, Footer, Breadcrumb, Tabs, Pagination, AppShell, Sidebar, Topbar |
|
||||
| **Data display** | DataTable, Stat, Avatar, Tag, Progress, EmptyState |
|
||||
| **Article** | ArticlePage, ArticleHeader, ArticleAside, ArticleFooter, ArticleCallout, ArticleTOC |
|
||||
| **Theming** | ThemePicker |
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: Comment contribuer
|
||||
description: Workflow de contribution au DSMMG.
|
||||
---
|
||||
|
||||
## Setup local
|
||||
|
||||
```sh
|
||||
git clone <repo>
|
||||
cd managemate-ds
|
||||
pnpm install
|
||||
pnpm build # build tous les packages dans le bon ordre
|
||||
pnpm storybook # lance Storybook localement
|
||||
pnpm --filter @managemate/react test:watch
|
||||
```
|
||||
|
||||
## Workflow de PR
|
||||
|
||||
1. Branch depuis `main` : `feat/...`, `fix/...`, `chore/...`.
|
||||
2. Modifier le code.
|
||||
3. **Ajouter un changeset** : `pnpm changeset` (sélectionner les packages impactés et le bump).
|
||||
4. Tests + Storybook updates obligatoires.
|
||||
5. Push, ouvrir la PR.
|
||||
6. CI doit passer (lint + types + tests + axe + size-limit + Storybook build).
|
||||
7. 1 review minimum (CODEOWNERS).
|
||||
|
||||
## Conventions
|
||||
|
||||
- **Commits** : conventional commits (`feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `test:`).
|
||||
- **Branches** : `<type>/<short-description>`.
|
||||
- **Code** : Prettier + ESLint via la config workspace (à venir).
|
||||
|
||||
## Ajouter un nouveau composant
|
||||
|
||||
1. Créer `packages/react/src/<Component>.tsx` (un fichier, exports nommés).
|
||||
2. Si CSS dédié : ajouter `packages/css/src/components/<comp>.css` + l'importer dans `index.css` avec `layer(components)`.
|
||||
3. Story Storybook : `storybook/stories/<Component>.stories.tsx` avec au minimum default + variants + states.
|
||||
4. Tests : `packages/react/src/<Component>.test.tsx` (axe + clavier + interactions).
|
||||
5. Doc MDX : `docs/src/content/docs/components/<component>.md` (anatomie, props, do/don't, a11y).
|
||||
6. Export dans `packages/react/src/index.tsx`.
|
||||
7. Changeset minor.
|
||||
|
||||
> **Un composant non documenté n'est pas livré.**
|
||||
|
||||
## RFC pour les changements majeurs
|
||||
|
||||
Voir [RFC process](/contrib/rfc/).
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: RFC process
|
||||
description: Quand et comment proposer une RFC.
|
||||
---
|
||||
|
||||
Une **RFC (Request for Comments)** est requise pour :
|
||||
|
||||
- Nouveau composant non-trivial (DataTable, Calendar…)
|
||||
- Breaking change sur l'API publique d'un composant existant
|
||||
- Refonte d'un token ou d'un groupe de tokens
|
||||
- Nouvelle dépendance externe (ex: ajouter Floating UI)
|
||||
- Changement architectural (build, tree-shaking, distribution)
|
||||
|
||||
## Format
|
||||
|
||||
PR sur `docs/src/content/docs/rfcs/000X-<titre>.md` avec :
|
||||
|
||||
```md
|
||||
---
|
||||
title: RFC 0001 — Nom de la RFC
|
||||
status: draft | accepted | rejected | superseded
|
||||
author: <handle>
|
||||
date: YYYY-MM-DD
|
||||
---
|
||||
|
||||
## Contexte
|
||||
Pourquoi cette RFC ? Quel problème ?
|
||||
|
||||
## Proposition
|
||||
La solution. Code, schémas, exemples.
|
||||
|
||||
## Alternatives
|
||||
Ce qu'on a écarté et pourquoi.
|
||||
|
||||
## Coût migration
|
||||
Codemod possible ? Effort consommateur ?
|
||||
|
||||
## Risques
|
||||
A11y, perf, DX, lock-in.
|
||||
|
||||
## Décision
|
||||
À remplir après discussion.
|
||||
```
|
||||
|
||||
## Cycle
|
||||
|
||||
1. Auteur ouvre la PR `docs(rfc): 000X — title`.
|
||||
2. Au moins **2 reviewers** (un design, un code).
|
||||
3. Discussion ouverte ≥ 7 jours.
|
||||
4. Décision : `accepted` → implémentation dans une PR séparée. `rejected` → on garde la RFC en archive.
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: Versioning
|
||||
description: SemVer strict, packages liés, deprecation policy.
|
||||
---
|
||||
|
||||
## SemVer strict
|
||||
|
||||
- **major** : breaking change sur l'API publique
|
||||
- rename/suppression d'export
|
||||
- signature de prop modifiée
|
||||
- rename de token CSS
|
||||
- changement structurel du DOM rendu (peut casser des sélecteurs CSS consommateurs)
|
||||
- **minor** : addition non-breaking
|
||||
- nouveau composant
|
||||
- nouvelle prop optionnelle
|
||||
- nouveau token
|
||||
- nouvelle variante
|
||||
- **patch** : bugfix, doc, perf interne sans surface publique
|
||||
|
||||
## Fixed packages
|
||||
|
||||
`@managemate/css`, `@managemate/react`, `@managemate/icons`, `@managemate/tokens` sont **fixed** (même version), pour éviter les incompatibilités de tokens entre CSS et React.
|
||||
|
||||
## Deprecation policy
|
||||
|
||||
1. Ajouter `@deprecated` JSDoc sur l'API à supprimer + indiquer le remplacement.
|
||||
2. Émettre un warning console en dev (`process.env.NODE_ENV !== "production"`).
|
||||
3. **Au minimum un cycle minor** entre deprecation et suppression.
|
||||
4. Suppression dans un major, listée explicitement dans le CHANGELOG.
|
||||
|
||||
## Codemods
|
||||
|
||||
Tout breaking change qui peut être migré automatiquement **doit** fournir un codemod.
|
||||
Voir `scripts/migrate-tokens.mjs` comme référence.
|
||||
|
||||
## Workflow Changesets
|
||||
|
||||
```sh
|
||||
pnpm changeset # ajouter un changeset
|
||||
pnpm version-packages # consume les changesets, bump versions
|
||||
pnpm release # build + publish
|
||||
```
|
||||
|
||||
CI gère ça via GitHub Actions sur `main` (voir `.github/workflows/release.yml`).
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
title: Couleurs
|
||||
description: Palette neutre + presets accent + sémantique.
|
||||
---
|
||||
|
||||
import { Aside } from "@astrojs/starlight/components";
|
||||
|
||||
<Aside type="caution">
|
||||
Pour la **palette interactive** avec swatches en live, voir <a href="https://design.managemate.fr/storybook/?path=/docs/tokens-colors--docs">Storybook → Tokens → Colors</a>.
|
||||
</Aside>
|
||||
|
||||
## 3 catégories
|
||||
|
||||
1. **Neutres** — bg, text, border. Stables.
|
||||
2. **Sémantiques** — success/warning/danger/info. **Stables, pas affectées par l'accent user.**
|
||||
3. **Accent** — user-themable, 9 presets.
|
||||
|
||||
## Contrastes garantis
|
||||
|
||||
| Combinaison | Ratio | Niveau |
|
||||
|---|---|---|
|
||||
| `text-primary` sur `bg-page` | ≥ 12:1 | AAA |
|
||||
| `text-secondary` sur `bg-page` | ≥ 7:1 | AAA |
|
||||
| `text-tertiary` sur `bg-page` | ≥ 4.5:1 | AA |
|
||||
| `text-quaternary` sur `bg-page` | ≥ 4:1 | (limite, pour placeholder uniquement) |
|
||||
| `accent-on` sur `accent` | ≥ 4.5:1 | AA — sur tous les presets |
|
||||
| `accent` sur `bg-page` | ≥ 3:1 | AA non-texte |
|
||||
|
||||
## Daltonisme
|
||||
|
||||
8 % des hommes (1/12) ont un trouble de la perception des couleurs. Aucune information ne doit reposer **uniquement** sur la couleur :
|
||||
|
||||
- Status badges → icône + texte ("Résolu" + check, pas juste un point vert).
|
||||
- Sparkline / graphique → patterns + labels.
|
||||
- Validation form → message + bordure rouge + icône `alert`.
|
||||
|
||||
## OKLCH
|
||||
|
||||
Les ramps sont conçues en OKLCH (perception uniforme). Rendu en hex pour compat IE/Safari < 15.4. Migration `oklch()` envisagée quand support ≥ 95 %.
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
title: Densité
|
||||
description: 3 modes adaptables par préférence utilisateur.
|
||||
---
|
||||
|
||||
## Modes
|
||||
|
||||
| Mode | Scale | Row height | Padding | Pour qui |
|
||||
|---|---|---|---|---|
|
||||
| `comfortable` (défaut) | 1.0 | 44 | x:16, y:12 | Espace-Client, sites publics, mobile |
|
||||
| `cozy` | 0.85 | 36 | x:12, y:8 | Apps métier (Synapse, HRTime, Forge…) |
|
||||
| `compact` | 0.72 | 28 | x:8, y:4 | Power users, 6h+/jour, dashboards denses |
|
||||
|
||||
## Application
|
||||
|
||||
Sur un sous-arbre (généralement `<body>` ou un container) :
|
||||
|
||||
```html
|
||||
<body data-mmg-density="cozy">
|
||||
```
|
||||
|
||||
Les composants qui consomment `--mmg-density-*` héritent automatiquement.
|
||||
|
||||
## Persistance
|
||||
|
||||
Recommandation : exposer un toggle dans les préférences user, persister en localStorage + DB user, appliquer en SSR pour éviter le flash.
|
||||
|
||||
## Touch target minimum
|
||||
|
||||
Quel que soit le mode, la **cible tactile reste ≥ 44×44** (WCAG SC 2.5.5). En `compact`, la cible visible peut être plus petite mais une zone tactile invisible la complète (cf. `Button.tsx` icon-only).
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
title: Motion
|
||||
description: Animation = feedback fonctionnel, jamais décoratif.
|
||||
---
|
||||
|
||||
## Tokens
|
||||
|
||||
| Token | Valeur | Usage |
|
||||
|---|---|---|
|
||||
| `--mmg-duration-fast` | 120ms | micro-interactions (hover, focus, ripple) |
|
||||
| `--mmg-duration-base` | 200ms | transitions UI (panels, popovers) |
|
||||
| `--mmg-duration-slow` | 320ms | navigation (modals, drawers) |
|
||||
| `--mmg-ease-default` | cubic-bezier(0.4, 0, 0.2, 1) | matériel, doux |
|
||||
| `--mmg-ease-emphasis` | cubic-bezier(0.2, 0.8, 0.2, 1) | rebond / overshoot léger |
|
||||
|
||||
## Règles
|
||||
|
||||
- **Animation = feedback** — toujours expliquer ce qui se passe (apparition, disparition, état).
|
||||
- **Jamais décorative** — pas de "pour faire joli".
|
||||
- **Entry: ease-out**, **Exit: ease-in**, **Continuous: ease-in-out**.
|
||||
|
||||
## prefers-reduced-motion
|
||||
|
||||
Toutes les animations sont désactivées (durée 0.001ms) sous `@media (prefers-reduced-motion: reduce)` (WCAG SC 2.3.3 AAA + bonne pratique AA). Cf. utilisateurs sensibles vestibulaire, migraine, attention.
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: Espacement
|
||||
description: Grille 4pt — multiples de 4 ou 8 exclusivement.
|
||||
---
|
||||
|
||||
## Tokens
|
||||
|
||||
| Token | px |
|
||||
|---|---|
|
||||
| `--mmg-space-0` | 0 |
|
||||
| `--mmg-space-1` | 4 |
|
||||
| `--mmg-space-2` | 8 |
|
||||
| `--mmg-space-3` | 12 |
|
||||
| `--mmg-space-4` | 16 |
|
||||
| `--mmg-space-5` | 20 |
|
||||
| `--mmg-space-6` | 24 |
|
||||
| `--mmg-space-7` | 32 |
|
||||
| `--mmg-space-8` | 40 |
|
||||
| `--mmg-space-9` | 48 |
|
||||
| `--mmg-space-10` | 64 |
|
||||
| `--mmg-space-11` | 80 |
|
||||
| `--mmg-space-12` | 120 |
|
||||
|
||||
## Règles
|
||||
|
||||
- **Toujours utiliser un token.** Aucun `padding: 17px` en dur.
|
||||
- **Multiples de 4 ou 8** uniquement. Évite les valeurs intermédiaires (10, 14, 22) qui cassent l'alignement vertical.
|
||||
- **Densité adaptable** : `--mmg-density-padding-{x,y}` change avec `[data-mmg-density]`. Préférer ces tokens aux `--mmg-space-*` directs dans les composants soumis à la densité.
|
||||
|
||||
## Utilitaires
|
||||
|
||||
```html
|
||||
<div class="mmg-u-stack mmg-u-stack-4">
|
||||
<!-- gap: 16px -->
|
||||
</div>
|
||||
```
|
||||
|
||||
| Class | Effect |
|
||||
|---|---|
|
||||
| `mmg-u-gap-{1..6}` | gap: var(--mmg-space-N) |
|
||||
| `mmg-u-stack-{1..6}` | flex column + gap |
|
||||
| `mmg-u-mt-{1..6}` | margin-top |
|
||||
| `mmg-u-mb-{1..6}` | margin-bottom |
|
||||
| `mmg-u-p-{0,2,3,4,6}` | padding |
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: Tokens
|
||||
description: Architecture des tokens DSMMG.
|
||||
---
|
||||
|
||||
Les tokens sont organisés en **3 couches**, du bas vers le haut :
|
||||
|
||||
```
|
||||
primitives → semantic → accent (presets user)
|
||||
```
|
||||
|
||||
## 1. Primitives
|
||||
|
||||
Rampes de couleur brutes (`--mmg-color-{neutral,synapse,blue,…}-{50..900}`), non utilisées directement par les composants.
|
||||
|
||||
## 2. Semantic
|
||||
|
||||
Tokens de rôle qui mappent les primitives. **Les composants consomment ceci.**
|
||||
|
||||
- `--mmg-color-bg-{page,surface,raised,muted,subtle,overlay}` — surfaces
|
||||
- `--mmg-color-text-{primary,secondary,tertiary,quaternary,inverse}` — texte
|
||||
- `--mmg-color-border{,-soft,-strong}` — bordures
|
||||
- `--mmg-color-{success,warning,danger,info}{,-soft,-border,-strong,-on}` — sémantique fixe
|
||||
|
||||
## 3. Accent (user-themable)
|
||||
|
||||
`--mmg-color-accent{,-hover,-active,-soft,-border,-strong,-on}` — la SEULE couleur user-themable. Posée par `[data-mmg-accent="<preset>"]` sur `<html>`.
|
||||
|
||||
## Non-color
|
||||
|
||||
| Catégorie | Préfixe | Exemple |
|
||||
|---|---|---|
|
||||
| Espacement | `--mmg-space-{0..12}` | `var(--mmg-space-4)` = 16px |
|
||||
| Rayons | `--mmg-radius-{sm,md,card,panel,icon,pill}` | |
|
||||
| Font size | `--mmg-font-size-{xs,sm,base,lg,xl,2xl..5xl}` | |
|
||||
| Font weight | `--mmg-font-weight-{regular,medium,semi,bold,extra}` | |
|
||||
| Line height | `--mmg-line-height-{tight,snug,normal}` | |
|
||||
| Motion | `--mmg-duration-{fast,base,slow}`, `--mmg-ease-{default,emphasis}` | |
|
||||
| Z-index | `--mmg-z-{dropdown,sticky,modal,toast,tooltip}` | |
|
||||
| Density | `--mmg-density-{scale,row-height,input-height,padding-x,padding-y}` | |
|
||||
|
||||
## Source unique : DTCG
|
||||
|
||||
`packages/tokens/src/tokens.json` au format **W3C Design Tokens Community Group**. Style Dictionary génère :
|
||||
|
||||
- `dist/tokens.css` — les CSS custom properties
|
||||
- `dist/tokens.{js,cjs,d.ts}` — un objet JS/TS auto-completé pour le code
|
||||
- `dist/figma-tokens.json` — pour le plugin Figma Tokens Studio
|
||||
|
||||
## Règles
|
||||
|
||||
- **Aucun hex en dur** dans les composants. Toujours via tokens.
|
||||
- **Aucun `--mmg-color-synapse-*` direct** : utiliser `--mmg-color-accent-*`.
|
||||
- **Pas de nouveau token sans changeset** : les tokens sont une API publique.
|
||||
- **Renommage** = breaking change → bump major + codemod fourni.
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
title: Typographie
|
||||
description: Figtree + échelle modulaire + line-heights.
|
||||
---
|
||||
|
||||
## Famille
|
||||
|
||||
`Figtree` (Google Fonts) — sans-serif géométrique moderne. Fallback : `system-ui, -apple-system, "Segoe UI", Roboto, sans-serif`.
|
||||
|
||||
```css
|
||||
font-family: var(--mmg-font-sans);
|
||||
```
|
||||
|
||||
Mono : `ui-monospace, "JetBrains Mono", "SF Mono", Menlo, monospace`.
|
||||
|
||||
## Échelle
|
||||
|
||||
| Token | px | Usage |
|
||||
|---|---|---|
|
||||
| `--mmg-font-size-xs` | 11 | annotations, métadonnées |
|
||||
| `--mmg-font-size-sm` | 13 | UI dense (inputs, boutons sm), hint |
|
||||
| `--mmg-font-size-base` | 15 | corps de texte |
|
||||
| `--mmg-font-size-lg` | 17 | corps de texte plus aéré |
|
||||
| `--mmg-font-size-xl` | 20 | h4 / sous-titres |
|
||||
| `--mmg-font-size-2xl` | 24 | h3 |
|
||||
| `--mmg-font-size-3xl` | 30 | h2 |
|
||||
| `--mmg-font-size-4xl` | 36 | h1 |
|
||||
| `--mmg-font-size-5xl` | 48 | hero / display |
|
||||
|
||||
## Weights
|
||||
|
||||
| Token | Valeur |
|
||||
|---|---|
|
||||
| `regular` | 400 |
|
||||
| `medium` | 500 |
|
||||
| `semi` | 600 |
|
||||
| `bold` | 700 |
|
||||
| `extra` | 800 |
|
||||
|
||||
## Line heights
|
||||
|
||||
- `tight` (1.2) — titres, boutons
|
||||
- `snug` (1.4) — UI dense
|
||||
- `normal` (1.6) — corps de texte
|
||||
|
||||
## B1 du CECRL — pour les sites publics
|
||||
|
||||
Espace-Client et sites publics doivent viser le **niveau B1 du CECRL** :
|
||||
|
||||
- Phrases courtes (< 25 mots).
|
||||
- Vocabulaire courant.
|
||||
- Pas de jargon ni d'acronymes non explicités.
|
||||
- Voix active.
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: DSMMG — Design System ManageMate Group
|
||||
description: Référence design + code pour les produits ManageMate. RGAA 4.1, headless-first, tokens W3C DTCG.
|
||||
template: splash
|
||||
hero:
|
||||
tagline: La source de vérité visuelle, comportementale et accessible pour Synapse, HRTime, Forge, Orbit, MSLM et l'Espace-Client.
|
||||
actions:
|
||||
- text: Démarrer
|
||||
link: /intro/
|
||||
icon: right-arrow
|
||||
variant: primary
|
||||
- text: Storybook
|
||||
link: https://design.managemate.fr/storybook
|
||||
icon: external
|
||||
variant: minimal
|
||||
---
|
||||
|
||||
import { Card, CardGrid, LinkCard } from "@astrojs/starlight/components";
|
||||
|
||||
## Pourquoi un DS ?
|
||||
|
||||
Un design system n'est pas un dossier de composants. C'est **la garantie** que toute UI sortie sous la marque ManageMate :
|
||||
|
||||
- respecte le **RGAA 4.1** (= WCAG 2.2 AA) — non-négociable, validé en CI ;
|
||||
- est **cohérente cross-produit** — un bouton dans Synapse, HRTime, Forge ou Orbit a la même forme, le même contraste, le même comportement clavier ;
|
||||
- est **theming user-aware** — chaque utilisateur peut choisir son accent parmi 9 presets validés.
|
||||
|
||||
## Couverture
|
||||
|
||||
<CardGrid>
|
||||
<Card title="62 composants" icon="puzzle">React headless-first, sur primitives Radix UI + Floating UI.</Card>
|
||||
<Card title="9 presets accent" icon="seti:image">Synapse (défaut), rose, blue, violet, green, amber, red, cyan, slate.</Card>
|
||||
<Card title="3 densités" icon="setting">Comfortable / cozy / compact, adaptables par préférence user.</Card>
|
||||
<Card title="2 thèmes" icon="moon">Light + dark, sémantique cohérente, accent qui pop sans noyer le contenu.</Card>
|
||||
</CardGrid>
|
||||
|
||||
## Standards
|
||||
|
||||
| Niveau | Inspirations |
|
||||
|---|---|
|
||||
| Architecture & a11y | shadcn/ui, Radix UI, Ariakit, React Aria |
|
||||
| Patterns SaaS dense | Linear, Notion, Vercel, Atlassian DS |
|
||||
| Apps enterprise | IBM Carbon, Atlassian |
|
||||
| Méthodologie a11y | DSFR, DSFR.gouv.fr |
|
||||
| Mobile / mobile patterns | Apple HIG, Material Design 3 |
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
title: Introduction
|
||||
description: Bienvenue dans le DSMMG.
|
||||
---
|
||||
|
||||
Le **DSMMG** (Design System ManageMate Group) est la source de vérité unique pour toutes les interfaces des produits ManageMate.
|
||||
|
||||
## Architecture des packages
|
||||
|
||||
| Package | Rôle |
|
||||
|---|---|
|
||||
| `@managemate/tokens` | Source DTCG des tokens primitifs. Génère CSS, JS/TS, Figma. |
|
||||
| `@managemate/css` | CSS vanilla — tokens, base reset, composants, utilitaires `@layer`. |
|
||||
| `@managemate/icons` | 96 icônes (line + fill) Remix Icon, subset par icône possible. |
|
||||
| `@managemate/react` | Composants React typés, headless-first, tree-shakable. |
|
||||
|
||||
## Principes
|
||||
|
||||
1. **Accessibilité = première classe.** RGAA 4.1, validé axe-core en CI. Refus de toute solution qui exclut une catégorie d'utilisateurs.
|
||||
2. **Headless-first.** Les comportements (focus management, ARIA, keyboard nav) viennent de Radix UI. Le style vient des tokens DSMMG. Séparation stricte.
|
||||
3. **Tokens partout.** Aucun hex en dur dans un composant. Couleur d'accent toujours via `--mmg-color-accent`, jamais `--mmg-color-synapse` direct.
|
||||
4. **Tree-shakable.** Un fichier par composant. `sideEffects: false`. L'import d'un Button n'embarque pas le DataTable.
|
||||
5. **Theming user-aware.** L'utilisateur choisit son accent. La sémantique (success/danger…) reste fixe.
|
||||
6. **Pro-friendly.** Densité adaptable, raccourcis clavier first-class, bulk actions, optimistic UI, vues sauvegardées.
|
||||
|
||||
## Démarrer
|
||||
|
||||
→ [Installation](/intro/installation/)
|
||||
→ [Migration v0.1 → v0.2](/intro/migration/)
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
title: Installation
|
||||
description: Comment installer le DSMMG dans un projet ManageMate.
|
||||
---
|
||||
|
||||
## Pré-requis
|
||||
|
||||
- Node ≥ 20
|
||||
- pnpm ≥ 9 (ou npm/yarn équivalents)
|
||||
- React ≥ 18
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
pnpm add @managemate/css @managemate/icons @managemate/react
|
||||
```
|
||||
|
||||
## Setup minimal
|
||||
|
||||
### 1. Importer les CSS
|
||||
|
||||
```tsx
|
||||
// app/main.tsx — ou _app.tsx en Next
|
||||
import "@managemate/css";
|
||||
import "@managemate/icons";
|
||||
```
|
||||
|
||||
L'ordre n'a pas d'importance grâce à la cascade `@layer reset, tokens, base, components, utilities`.
|
||||
|
||||
### 2. (Optionnel) Mettre un thème initial
|
||||
|
||||
```tsx
|
||||
import { applyTheme, applyAccent } from "@managemate/react";
|
||||
|
||||
// Dès le mount du root, idéalement avant React render
|
||||
applyTheme("system"); // ou "light" / "dark"
|
||||
applyAccent("synapse"); // ou un autre preset
|
||||
```
|
||||
|
||||
Mieux : appliquer en SSR via un script inline pour éviter le flash :
|
||||
|
||||
```html
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem("mmg-theme");
|
||||
var a = localStorage.getItem("mmg-accent");
|
||||
if (t && t !== "system") document.documentElement.setAttribute("data-mmg-theme", t);
|
||||
if (a && a !== "synapse") document.documentElement.setAttribute("data-mmg-accent", a);
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
```
|
||||
|
||||
### 3. Wrapper Provider à la racine
|
||||
|
||||
```tsx
|
||||
import { TooltipProvider, ToastProvider } from "@managemate/react";
|
||||
|
||||
<TooltipProvider>
|
||||
<ToastProvider>
|
||||
<App />
|
||||
</ToastProvider>
|
||||
</TooltipProvider>
|
||||
```
|
||||
|
||||
### 4. Premier composant
|
||||
|
||||
```tsx
|
||||
import { Button } from "@managemate/react";
|
||||
|
||||
<Button variant="primary" icon="arrow-right-line" iconPosition="right">
|
||||
Continuer
|
||||
</Button>
|
||||
```
|
||||
|
||||
## Tree-shaking
|
||||
|
||||
Tous les exports sont nommés et `sideEffects: false`. L'import suivant ne tire que `Button` + `Icon` + `cx` :
|
||||
|
||||
```tsx
|
||||
import { Button } from "@managemate/react";
|
||||
```
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: Migration v0.1 → v0.2
|
||||
description: Guide de migration vers la nouvelle architecture DSMMG.
|
||||
---
|
||||
|
||||
La v0.2 est une **refonte architecturale** avec breaking changes. Elle prépare le DS à un usage réel cross-produit avec theming utilisateur, tree-shaking strict, primitives Radix.
|
||||
|
||||
## Codemod automatique
|
||||
|
||||
Un codemod est fourni pour renommer la majorité des tokens dans ton codebase consommateur :
|
||||
|
||||
```sh
|
||||
node scripts/migrate-tokens.mjs
|
||||
```
|
||||
|
||||
Il modifie en place les `.css` et `.tsx` selon une table de mapping idempotente.
|
||||
|
||||
## Token renames (mapping principal)
|
||||
|
||||
| Avant | Après |
|
||||
|---|---|
|
||||
| `--mmg-bg-page/surface/raised/muted/subtle/overlay` | `--mmg-color-bg-*` |
|
||||
| `--mmg-text-1/2/3/4` | `--mmg-color-text-{primary,secondary,tertiary,quaternary}` |
|
||||
| `--mmg-text-inverse` | `--mmg-color-text-inverse` |
|
||||
| `--mmg-text-{xs..5xl}` | `--mmg-font-size-*` |
|
||||
| `--mmg-leading-*` | `--mmg-line-height-*` |
|
||||
| `--mmg-weight-*` | `--mmg-font-weight-*` |
|
||||
| `--mmg-border/border-soft/border-strong` | `--mmg-color-border*` |
|
||||
| `--mmg-brand-*` | `--mmg-color-accent-*` |
|
||||
| `--mmg-success/warning/danger/info-*` | `--mmg-color-success/warning/danger/info-*` |
|
||||
| `--mmg-shadow-brand-*` | `--mmg-shadow-accent-*` |
|
||||
| `--mmg-art-*` | `--mmg-color-art-*` |
|
||||
| `--mmg-state-*` | `--mmg-color-state-*` |
|
||||
|
||||
## API React — changements
|
||||
|
||||
### `Tooltip`, `Popover`, `Menu`, `Dialog`, `Combobox`
|
||||
|
||||
Réécrits sur **Radix UI + Floating UI**. L'API publique est globalement préservée mais :
|
||||
|
||||
- `Menu` : la prop `items[i].onClick` devient `onSelect` (cohérent avec Radix). Les flèches, type-ahead et focus management sont gérés natif.
|
||||
- `Tooltip` : exige `<TooltipProvider>` à la racine. Les délais sont partagés entre tooltips voisins.
|
||||
- `Combobox` : nouvelle prop `emptyMessage`, navigation `Home`/`End`, `aria-activedescendant`.
|
||||
|
||||
### Suppression du switch produit
|
||||
|
||||
`[data-mmg-product]` est retiré au profit de `[data-mmg-accent]`. Chaque utilisateur choisit son accent (par défaut Synapse). Voir [Architecture accent](/theming/architecture/).
|
||||
|
||||
### Composants splittés
|
||||
|
||||
`Advanced.tsx`, `Chrome.tsx`, `Article.tsx` ont été éclatés en un fichier par composant. Imports inchangés via le barrel.
|
||||
|
||||
## Nouveautés
|
||||
|
||||
- 9 presets accent + ramps -50/-900 + `-on` validé AA
|
||||
- Composant `<ThemePicker />` + hooks `useAccent`, `useTheme`
|
||||
- Cascade `@layer reset, tokens, base, components, utilities`
|
||||
- Utilitaires CSS `mmg-u-*` (stack, flex, grid, text, bg, padding, margin)
|
||||
- Build packages — distribution via `dist/` (ESM + CJS + types)
|
||||
- Storybook + tests Vitest + axe-core en CI
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
title: Patterns
|
||||
description: Patterns d'interaction et de composition récurrents dans les apps ManageMate.
|
||||
---
|
||||
|
||||
## Power user patterns
|
||||
|
||||
- **Densité adaptable** — 3 modes (comfortable / cozy / compact).
|
||||
- **Raccourcis clavier first-class** — registry centralisé, cmd+K, séquences vim-style.
|
||||
- **Bulk actions** — toolbar contextuelle sticky sur sélection.
|
||||
- **Vues sauvegardées** — filtres + colonnes + tri + group sous un nom partageable.
|
||||
- **Optimistic UI** — actions appliquées instantanément, réconciliation serveur.
|
||||
- **Inline editing** — clic = édition, Enter valide, Esc annule.
|
||||
- **Recherche fuzzy partout** — typos tolérées, highlight des matches.
|
||||
- **Drag and drop avec alternative clavier** — toujours.
|
||||
- **Empty states contextuels** — pas de "no data" générique.
|
||||
|
||||
Détails et exemples → en cours, à compléter.
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
title: Architecture du theming user
|
||||
description: Comment l'accent personnalisable est structuré dans le DSMMG.
|
||||
---
|
||||
|
||||
## Le problème
|
||||
|
||||
Plusieurs apps ManageMate (Synapse, HRTime, Forge, Orbit, MSLM) doivent permettre à chaque utilisateur de **choisir sa couleur d'accent**, tout en garantissant :
|
||||
|
||||
- **WCAG AA** sur tous les fonds (light, dark, raised).
|
||||
- **Consistance cross-produit** : le bouton primary fait la même *forme*, juste une autre teinte.
|
||||
- **Pas de flash** au chargement (FOUC).
|
||||
- **Sémantique préservée** : un Alert danger reste rouge même si l'accent est rouge.
|
||||
|
||||
## La solution
|
||||
|
||||
Indirection systématique :
|
||||
|
||||
```
|
||||
[data-mmg-accent="<preset>"] ─┐
|
||||
├─→ --mmg-color-accent (et dérivés) ─→ Composants
|
||||
[data-mmg-theme="dark"] ─┘
|
||||
```
|
||||
|
||||
### 1. Les composants consomment `--mmg-color-accent-*`
|
||||
|
||||
```css
|
||||
.mmg-btn--primary {
|
||||
background: var(--mmg-color-accent);
|
||||
color: var(--mmg-color-accent-on);
|
||||
box-shadow: var(--mmg-shadow-accent);
|
||||
}
|
||||
```
|
||||
|
||||
**Jamais** :
|
||||
|
||||
```css
|
||||
.mmg-btn--primary {
|
||||
background: var(--mmg-color-synapse-500); /* ❌ casse le theming user */
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Les presets posent les valeurs
|
||||
|
||||
`packages/css/src/tokens/accent.css` définit pour chaque preset :
|
||||
|
||||
```css
|
||||
[data-mmg-accent="blue"] {
|
||||
--mmg-color-accent: var(--mmg-color-blue-500);
|
||||
--mmg-color-accent-hover: var(--mmg-color-blue-600);
|
||||
--mmg-color-accent-active: var(--mmg-color-blue-700);
|
||||
--mmg-color-accent-soft: var(--mmg-color-blue-50);
|
||||
--mmg-color-accent-border: var(--mmg-color-blue-200);
|
||||
--mmg-color-accent-strong: var(--mmg-color-blue-800);
|
||||
--mmg-color-accent-on: var(--mmg-color-neutral-0);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Le hook `useAccent` synchronise localStorage et `<html>`
|
||||
|
||||
```tsx
|
||||
import { useAccent } from "@managemate/react";
|
||||
|
||||
const { accent, setAccent, reset } = useAccent();
|
||||
```
|
||||
|
||||
Ou impératif :
|
||||
|
||||
```ts
|
||||
import { applyAccent } from "@managemate/react";
|
||||
applyAccent("blue", true); // persist=true par défaut
|
||||
```
|
||||
|
||||
### 4. Pour éviter le flash en SSR
|
||||
|
||||
Inclure ce script dans le `<head>` :
|
||||
|
||||
```html
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var v = localStorage.getItem("mmg-accent");
|
||||
if (v && v !== "synapse") document.documentElement.setAttribute("data-mmg-accent", v);
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
```
|
||||
|
||||
## Sémantique vs accent
|
||||
|
||||
> **L'accent est un accent, pas une dominante.** La sémantique prime sur la personnalisation.
|
||||
|
||||
| Token | Affecté par l'accent ? |
|
||||
|---|---|
|
||||
| `--mmg-color-accent-*` | ✅ Oui — c'est son rôle |
|
||||
| `--mmg-color-success-*` | ❌ Non — toujours vert |
|
||||
| `--mmg-color-danger-*` | ❌ Non — toujours rouge |
|
||||
| `--mmg-color-warning-*` | ❌ Non — toujours ambre |
|
||||
| `--mmg-color-info-*` | ❌ Non — toujours bleu |
|
||||
| `--mmg-color-bg-*`, `--mmg-color-text-*` | ❌ Non — neutres |
|
||||
|
||||
Cas particulier : l'utilisateur peut choisir un accent **rouge**. Il sera distinguable de `danger` car les deux ont des soft/border/strong propres.
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
title: Mode sombre
|
||||
description: Activation et personnalisation du dark mode.
|
||||
---
|
||||
|
||||
## Toggle simple
|
||||
|
||||
```tsx
|
||||
import { useTheme } from "@managemate/react";
|
||||
|
||||
const { theme, setTheme, toggle } = useTheme();
|
||||
// theme === "light" | "dark" | "system"
|
||||
```
|
||||
|
||||
## Tokens dark mode
|
||||
|
||||
Toutes les surfaces, textes, bordures et états ont leur version dark définie dans `tokens/semantic.css`. Les ombres deviennent **noires + halo blanc subtil** plutôt que noires pures (qui s'évaporent).
|
||||
|
||||
```css
|
||||
[data-mmg-theme="dark"] {
|
||||
--mmg-color-bg-page: #0B0D14;
|
||||
--mmg-color-bg-surface: #14171F;
|
||||
/* ... */
|
||||
--mmg-shadow-1: 0 1px 3px rgba(0,0,0,0.55), 0 0 0 1px rgba(255,255,255,0.04);
|
||||
}
|
||||
```
|
||||
|
||||
## Auto-system
|
||||
|
||||
Sans `[data-mmg-theme]`, le DS suit `prefers-color-scheme: dark`.
|
||||
|
||||
## Forced colors / High Contrast Mode (Windows)
|
||||
|
||||
`@media (forced-colors: active)` bascule sur les system colors :
|
||||
|
||||
- `Highlight` pour les états sélectionnés
|
||||
- `Canvas`/`CanvasText` pour les surfaces
|
||||
|
||||
Les composants overlays (Tooltip, Dialog, Menu) ont une bordure `1px solid CanvasText` en HCM pour rester lisibles.
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
title: Presets accent
|
||||
description: Les 9 couleurs d'accent disponibles dans le DSMMG.
|
||||
---
|
||||
|
||||
| Preset | Hex (light) | Usage suggéré |
|
||||
|---|---|---|
|
||||
| `synapse` (défaut) | `#D12B6A` | ManageMate corporate, défaut partout |
|
||||
| `rose` | `#E11D48` | Variante rose plus vif |
|
||||
| `blue` | `#2563EB` | Apps banking / fintech / lourd-data |
|
||||
| `violet` | `#7C3AED` | Forge, créatif, AI |
|
||||
| `green` | `#0E9F6E` | HRTime, environnemental |
|
||||
| `amber` | `#D97706` | Orbit, attention positive |
|
||||
| `red` | `#DC2626` | Sites événementiels — ne pas confondre avec sémantique danger |
|
||||
| `cyan` | `#0891B2` | SIRH analytics, dashboards |
|
||||
| `slate` | `#475569` | Neutre haut contraste, brutalist |
|
||||
|
||||
## Tests de contraste — chaque preset
|
||||
|
||||
Chaque preset est validé contre 6 règles avant inclusion :
|
||||
|
||||
1. **Accent vs fond light** ≥ 4.5:1 (texte) ou 3:1 (composant non-texte).
|
||||
2. **Accent vs fond dark** ≥ 4.5:1 / 3:1 (avec la version dark-tuned).
|
||||
3. **`-on` vs `accent`** ≥ 4.5:1 (texte sur le bouton).
|
||||
4. Focus ring distinguable sur tous les fonds (light, dark, raised).
|
||||
5. Tous les états (hover/active/disabled) restent distinguables.
|
||||
6. Pas de confusion avec les couleurs sémantiques (`accent === red` ≠ `danger`).
|
||||
|
||||
## Dark mode — adaptation
|
||||
|
||||
En `[data-mmg-theme="dark"]`, l'accent est **éclairci et désaturé** pour confort visuel.
|
||||
Référence : Linear, Stripe, Apple HIG. L'œil supporte mal les couleurs vives sur fond sombre.
|
||||
|
||||
Exemple Synapse :
|
||||
- Light : `#D12B6A` (HSL 335 65% 50%)
|
||||
- Dark : `#E83A7E` (HSL 335 78% 57%) — plus clair, légèrement plus saturé
|
||||
@@ -0,0 +1,8 @@
|
||||
/* Customisation Starlight pour matcher le DSMMG */
|
||||
:root {
|
||||
--sl-color-accent: var(--mmg-color-accent);
|
||||
--sl-color-accent-low: var(--mmg-color-accent-soft);
|
||||
--sl-color-accent-high: var(--mmg-color-accent-strong);
|
||||
--sl-font: var(--mmg-font-sans);
|
||||
--sl-font-mono: var(--mmg-font-mono);
|
||||
}
|
||||
Reference in New Issue
Block a user