chore: initial DSMMG v0.2 — refonte architecturale complète
Release / Release / open changeset PR (push) Has been cancelled
CI / Build, typecheck, test, a11y (push) Has been cancelled

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:
Dinawo
2026-05-04 22:07:57 +02:00
parent 5e019857fc
commit 62317f2ad7
172 changed files with 31397 additions and 1 deletions
+55
View File
@@ -0,0 +1,55 @@
# @managemate/tokens
Source unique des tokens DSMMG au format **W3C Design Tokens Community Group (DTCG)**.
## Usage
```sh
pnpm --filter @managemate/tokens build
```
Génère dans `dist/` :
| Fichier | Format | Pour qui |
|---|---|---|
| `tokens.css` | CSS custom properties `--mmg-*` | Le navigateur, importé par `@managemate/css` |
| `tokens.js` | ESM | Code Node/Bundler — JS/TS apps |
| `tokens.cjs` | CommonJS | Code Node legacy |
| `tokens.d.ts` | TypeScript declarations | Auto-complete dans les IDEs |
| `figma-tokens.json` | [Tokens Studio](https://tokens.studio/) | Plugin Figma → sync designer↔code |
## Workflow Figma
1. Le designer modifie les variables dans Figma via [Tokens Studio](https://tokens.studio/).
2. Export → push vers `packages/tokens/src/tokens.json` (PR avec changeset minor).
3. CI valide les contrastes et regen les sorties.
4. Ou inversement : modifier `tokens.json` → CI regen Figma JSON → designer pull dans Figma.
## DTCG schema
Chaque token a une forme :
```json
{
"$value": "#D12B6A",
"$type": "color",
"$description": "(optionnel)"
}
```
Types supportés : `color`, `dimension`, `fontWeight`, `duration`.
## Conventions de naming
- `color.<palette>.<shade>` : `color.synapse.500`
- `spacing.<index>` : `spacing.4` (= 16px)
- `radius.<scale>` : `radius.md`
- `fontSize.<scale>` : `fontSize.base`
- `fontWeight.<scale>` : `fontWeight.semi`
- `duration.<scale>` : `duration.fast`
Le préfixe CSS `--mmg-` est ajouté automatiquement par Style Dictionary.
## Présets accent (cross-pkg)
Les tokens primitifs sont publiés ici. Les presets accent (`[data-mmg-accent="…"]`) restent définis dans `@managemate/css` (`tokens/accent.css`) car ils dépendent du contexte (light/dark, sélection user).
+196
View File
@@ -0,0 +1,196 @@
#!/usr/bin/env node
/**
* @managemate/tokens — build pipeline
*
* Source de vérité unique : src/tokens.json (format W3C DTCG).
* Génère :
* - dist/tokens.css : CSS custom properties --mmg-color-*
* - dist/tokens.js / .d.ts: objet JS/TS pour consommation programmatique
* - dist/tokens.cjs : CommonJS
* - dist/figma-tokens.json: format Tokens Studio pour sync Figma
*/
import StyleDictionary from "style-dictionary";
import { mkdir, writeFile, readFile } from "node:fs/promises";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { existsSync } from "node:fs";
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = __dirname;
const DIST = join(ROOT, "dist");
const SOURCE = join(ROOT, "src", "tokens.json");
if (!existsSync(DIST)) await mkdir(DIST, { recursive: true });
// — Style Dictionary config ————————————————————————————————————
const sd = new StyleDictionary({
source: [SOURCE],
log: { warnings: "warn", verbosity: "default" },
platforms: {
css: {
transformGroup: "css",
buildPath: "dist/",
files: [
{
destination: "tokens.css",
format: "css/variables",
options: {
outputReferences: false,
selector: ":root",
},
},
],
prefix: "mmg",
},
js: {
transformGroup: "js",
buildPath: "dist/",
files: [
{
destination: "tokens.js",
format: "javascript/esm",
},
{
destination: "tokens.cjs",
format: "javascript/module",
},
{
destination: "tokens.d.ts",
format: "typescript/es6-declarations",
},
],
prefix: "mmg",
},
},
});
await sd.cleanAllPlatforms();
await sd.buildAllPlatforms();
// — Figma Tokens Studio export ————————————————————————————————————
// Plugin Tokens Studio attend un format proche de DTCG mais avec une
// structure aplatie : { "color/neutral/50": { "value": "...", "type": "color" } }
const dtcg = JSON.parse(await readFile(SOURCE, "utf8"));
function flatten(obj, prefix = "") {
const out = {};
for (const [k, v] of Object.entries(obj)) {
if (k.startsWith("$")) continue;
const path = prefix ? `${prefix}/${k}` : k;
if (v && typeof v === "object" && "$value" in v) {
out[path] = { value: v.$value, type: v.$type };
} else if (v && typeof v === "object") {
Object.assign(out, flatten(v, path));
}
}
return out;
}
const figmaTokens = {
global: flatten(dtcg),
$themes: [],
$metadata: {
tokenSetOrder: ["global"],
generatedAt: new Date().toISOString(),
generatedBy: "@managemate/tokens build.mjs",
},
};
await writeFile(join(DIST, "figma-tokens.json"), JSON.stringify(figmaTokens, null, 2));
// — Tailwind v3 export (theme.extend JSON) ————————————————————————
function buildTailwindV3() {
const colors = {};
for (const [name, ramp] of Object.entries(dtcg.color ?? {})) {
if (!ramp || typeof ramp !== "object") continue;
const shades = {};
for (const [shade, val] of Object.entries(ramp)) {
if (val && typeof val === "object" && "$value" in val) {
shades[shade] = val.$value;
}
}
if (Object.keys(shades).length > 0) colors[name] = shades;
}
const spacing = {};
for (const [k, v] of Object.entries(dtcg.spacing ?? {})) {
if (v && typeof v === "object" && "$value" in v) {
spacing[`mmg-${k}`] = v.$value;
}
}
const radius = {};
for (const [k, v] of Object.entries(dtcg.radius ?? {})) {
if (v && typeof v === "object" && "$value" in v) {
radius[`mmg-${k}`] = v.$value;
}
}
const fontSize = {};
for (const [k, v] of Object.entries(dtcg.fontSize ?? {})) {
if (v && typeof v === "object" && "$value" in v) {
fontSize[`mmg-${k}`] = v.$value;
}
}
return {
theme: {
extend: {
colors: { mmg: colors },
spacing,
borderRadius: radius,
fontSize,
},
},
};
}
await writeFile(
join(DIST, "tailwind.config.json"),
JSON.stringify(buildTailwindV3(), null, 2),
);
// — Tailwind v4 export (@theme CSS block) ————————————————————————
function buildTailwindV4() {
const lines = ["/* DSMMG tokens — Tailwind v4 @theme block. */", "@theme {"];
// Colors
for (const [name, ramp] of Object.entries(dtcg.color ?? {})) {
if (!ramp || typeof ramp !== "object") continue;
for (const [shade, val] of Object.entries(ramp)) {
if (val && typeof val === "object" && "$value" in val) {
lines.push(` --color-mmg-${name}-${shade}: ${val.$value};`);
}
}
}
// Spacing
for (const [k, v] of Object.entries(dtcg.spacing ?? {})) {
if (v && typeof v === "object" && "$value" in v) {
lines.push(` --spacing-mmg-${k}: ${v.$value};`);
}
}
// Radius
for (const [k, v] of Object.entries(dtcg.radius ?? {})) {
if (v && typeof v === "object" && "$value" in v) {
lines.push(` --radius-mmg-${k}: ${v.$value};`);
}
}
// Font sizes
for (const [k, v] of Object.entries(dtcg.fontSize ?? {})) {
if (v && typeof v === "object" && "$value" in v) {
lines.push(` --text-mmg-${k}: ${v.$value};`);
}
}
// Durations
for (const [k, v] of Object.entries(dtcg.duration ?? {})) {
if (v && typeof v === "object" && "$value" in v) {
lines.push(` --animate-duration-mmg-${k}: ${v.$value};`);
}
}
lines.push("}");
return lines.join("\n") + "\n";
}
await writeFile(join(DIST, "tailwind.css"), buildTailwindV4());
console.log(`✓ Tokens built → ${DIST}`);
console.log(` - tokens.css (CSS custom properties)`);
console.log(` - tokens.{js,cjs,d.ts} (ESM / CJS / TypeScript)`);
console.log(` - figma-tokens.json (Tokens Studio for Figma sync)`);
console.log(` - tailwind.config.json (Tailwind v3 theme.extend)`);
console.log(` - tailwind.css (Tailwind v4 @theme block)`);
+36
View File
@@ -0,0 +1,36 @@
{
"name": "@managemate/tokens",
"version": "0.1.0",
"description": "DSMMG design tokens — DTCG source + Style Dictionary build (CSS, TS, Figma)",
"type": "module",
"license": "UNLICENSED",
"private": true,
"sideEffects": false,
"main": "./dist/tokens.cjs",
"module": "./dist/tokens.js",
"types": "./dist/tokens.d.ts",
"exports": {
".": {
"types": "./dist/tokens.d.ts",
"import": "./dist/tokens.js",
"require": "./dist/tokens.cjs"
},
"./css": "./dist/tokens.css",
"./figma": "./dist/figma-tokens.json",
"./tailwind": "./dist/tailwind.config.json",
"./tailwind.css": "./dist/tailwind.css",
"./source": "./src/tokens.json",
"./package.json": "./package.json"
},
"files": [
"dist",
"src"
],
"scripts": {
"build": "node build.mjs",
"watch": "node build.mjs --watch"
},
"devDependencies": {
"style-dictionary": "^4.3.3"
}
}
+173
View File
@@ -0,0 +1,173 @@
{
"$schema": "https://schemas.tr.designtokens.org/format/",
"color": {
"neutral": {
"0": { "$value": "#FFFFFF", "$type": "color" },
"50": { "$value": "#F7F6FB", "$type": "color" },
"100": { "$value": "#F0EFF9", "$type": "color" },
"150": { "$value": "#EDEDFA", "$type": "color" },
"200": { "$value": "#E4E3F4", "$type": "color" },
"300": { "$value": "#C9C7E0", "$type": "color" },
"400": { "$value": "#AAA8C9", "$type": "color" },
"500": { "$value": "#7875A1", "$type": "color" },
"600": { "$value": "#56557A", "$type": "color" },
"700": { "$value": "#3B3A56", "$type": "color" },
"800": { "$value": "#1F1E32", "$type": "color" },
"900": { "$value": "#111120", "$type": "color" }
},
"synapse": {
"50": { "$value": "#FEF0F4", "$type": "color" },
"100": { "$value": "#FCE0EA", "$type": "color" },
"200": { "$value": "#FAD0DF", "$type": "color" },
"300": { "$value": "#F4A0BD", "$type": "color" },
"400": { "$value": "#ED608E", "$type": "color" },
"500": { "$value": "#D12B6A", "$type": "color" },
"600": { "$value": "#BA245F", "$type": "color" },
"700": { "$value": "#A82257", "$type": "color" },
"800": { "$value": "#831B45", "$type": "color" },
"900": { "$value": "#5A132F", "$type": "color" }
},
"rose": {
"50": { "$value": "#FFF1F2", "$type": "color" },
"100": { "$value": "#FFE4E6", "$type": "color" },
"200": { "$value": "#FECDD3", "$type": "color" },
"300": { "$value": "#FDA4AF", "$type": "color" },
"400": { "$value": "#FB7185", "$type": "color" },
"500": { "$value": "#E11D48", "$type": "color" },
"600": { "$value": "#BE123C", "$type": "color" },
"700": { "$value": "#9F1239", "$type": "color" },
"800": { "$value": "#881337", "$type": "color" },
"900": { "$value": "#4C0519", "$type": "color" }
},
"blue": {
"50": { "$value": "#EFF6FF", "$type": "color" },
"100": { "$value": "#DBEAFE", "$type": "color" },
"200": { "$value": "#BFDBFE", "$type": "color" },
"300": { "$value": "#93C5FD", "$type": "color" },
"400": { "$value": "#60A5FA", "$type": "color" },
"500": { "$value": "#2563EB", "$type": "color" },
"600": { "$value": "#1D4ED8", "$type": "color" },
"700": { "$value": "#1E40AF", "$type": "color" },
"800": { "$value": "#1E3A8A", "$type": "color" },
"900": { "$value": "#172554", "$type": "color" }
},
"violet": {
"50": { "$value": "#F5F3FF", "$type": "color" },
"100": { "$value": "#EDE9FE", "$type": "color" },
"200": { "$value": "#DDD6FE", "$type": "color" },
"300": { "$value": "#C4B5FD", "$type": "color" },
"400": { "$value": "#A78BFA", "$type": "color" },
"500": { "$value": "#7C3AED", "$type": "color" },
"600": { "$value": "#6D28D9", "$type": "color" },
"700": { "$value": "#5B21B6", "$type": "color" },
"800": { "$value": "#4C1D95", "$type": "color" },
"900": { "$value": "#2E1065", "$type": "color" }
},
"green": {
"50": { "$value": "#ECFDF5", "$type": "color" },
"100": { "$value": "#D1FAE5", "$type": "color" },
"200": { "$value": "#BAEFD3", "$type": "color" },
"300": { "$value": "#6EE7B7", "$type": "color" },
"400": { "$value": "#34D399", "$type": "color" },
"500": { "$value": "#0E9F6E", "$type": "color" },
"600": { "$value": "#0B8861", "$type": "color" },
"700": { "$value": "#086B4D", "$type": "color" },
"800": { "$value": "#064E3B", "$type": "color" },
"900": { "$value": "#022C22", "$type": "color" }
},
"amber": {
"50": { "$value": "#FFFBEB", "$type": "color" },
"100": { "$value": "#FEF3C7", "$type": "color" },
"200": { "$value": "#FDE68A", "$type": "color" },
"300": { "$value": "#FCD34D", "$type": "color" },
"400": { "$value": "#FBBF24", "$type": "color" },
"500": { "$value": "#D97706", "$type": "color" },
"600": { "$value": "#B45309", "$type": "color" },
"700": { "$value": "#92400E", "$type": "color" },
"800": { "$value": "#78350F", "$type": "color" },
"900": { "$value": "#451A03", "$type": "color" }
},
"red": {
"50": { "$value": "#FEF2F2", "$type": "color" },
"100": { "$value": "#FEE2E2", "$type": "color" },
"200": { "$value": "#FECACA", "$type": "color" },
"300": { "$value": "#FCA5A5", "$type": "color" },
"400": { "$value": "#F87171", "$type": "color" },
"500": { "$value": "#DC2626", "$type": "color" },
"600": { "$value": "#B91C1C", "$type": "color" },
"700": { "$value": "#991B1B", "$type": "color" },
"800": { "$value": "#7F1D1D", "$type": "color" },
"900": { "$value": "#450A0A", "$type": "color" }
},
"cyan": {
"50": { "$value": "#ECFEFF", "$type": "color" },
"100": { "$value": "#CFFAFE", "$type": "color" },
"200": { "$value": "#A5F3FC", "$type": "color" },
"300": { "$value": "#67E8F9", "$type": "color" },
"400": { "$value": "#22D3EE", "$type": "color" },
"500": { "$value": "#0891B2", "$type": "color" },
"600": { "$value": "#0E7490", "$type": "color" },
"700": { "$value": "#155E75", "$type": "color" },
"800": { "$value": "#164E63", "$type": "color" },
"900": { "$value": "#083344", "$type": "color" }
},
"slate": {
"50": { "$value": "#F8FAFC", "$type": "color" },
"100": { "$value": "#F1F5F9", "$type": "color" },
"200": { "$value": "#E2E8F0", "$type": "color" },
"300": { "$value": "#CBD5E1", "$type": "color" },
"400": { "$value": "#94A3B8", "$type": "color" },
"500": { "$value": "#475569", "$type": "color" },
"600": { "$value": "#334155", "$type": "color" },
"700": { "$value": "#1E293B", "$type": "color" },
"800": { "$value": "#0F172A", "$type": "color" },
"900": { "$value": "#020617", "$type": "color" }
}
},
"spacing": {
"0": { "$value": "0px", "$type": "dimension" },
"1": { "$value": "4px", "$type": "dimension" },
"2": { "$value": "8px", "$type": "dimension" },
"3": { "$value": "12px", "$type": "dimension" },
"4": { "$value": "16px", "$type": "dimension" },
"5": { "$value": "20px", "$type": "dimension" },
"6": { "$value": "24px", "$type": "dimension" },
"7": { "$value": "32px", "$type": "dimension" },
"8": { "$value": "40px", "$type": "dimension" },
"9": { "$value": "48px", "$type": "dimension" },
"10": { "$value": "64px", "$type": "dimension" },
"11": { "$value": "80px", "$type": "dimension" },
"12": { "$value": "120px", "$type": "dimension" }
},
"radius": {
"sm": { "$value": "8px", "$type": "dimension" },
"md": { "$value": "12px", "$type": "dimension" },
"card": { "$value": "20px", "$type": "dimension" },
"panel": { "$value": "24px", "$type": "dimension" },
"icon": { "$value": "12px", "$type": "dimension" },
"pill": { "$value": "9999px", "$type": "dimension" }
},
"fontSize": {
"xs": { "$value": "11px", "$type": "dimension" },
"sm": { "$value": "13px", "$type": "dimension" },
"base": { "$value": "15px", "$type": "dimension" },
"lg": { "$value": "17px", "$type": "dimension" },
"xl": { "$value": "20px", "$type": "dimension" },
"2xl": { "$value": "24px", "$type": "dimension" },
"3xl": { "$value": "30px", "$type": "dimension" },
"4xl": { "$value": "36px", "$type": "dimension" },
"5xl": { "$value": "48px", "$type": "dimension" }
},
"fontWeight": {
"regular": { "$value": 400, "$type": "fontWeight" },
"medium": { "$value": 500, "$type": "fontWeight" },
"semi": { "$value": 600, "$type": "fontWeight" },
"bold": { "$value": 700, "$type": "fontWeight" },
"extra": { "$value": 800, "$type": "fontWeight" }
},
"duration": {
"fast": { "$value": "120ms", "$type": "duration" },
"base": { "$value": "200ms", "$type": "duration" },
"slow": { "$value": "320ms", "$type": "duration" }
}
}