62317f2ad7
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>
192 lines
6.0 KiB
JavaScript
192 lines
6.0 KiB
JavaScript
// DSMMG icon builder
|
||
// - Émet un bundle complet (icons.css) avec base + toutes les classes
|
||
// - Émet aussi des modules par icône (each/<name>.css) pour permettre le
|
||
// tree-shaking côté consommateur (import "@managemate/icons/each/check-line").
|
||
// - Émet le module base.css (la classe .mmg-icon + sizes) en stand-alone,
|
||
// utile quand on n'importe que des icônes individuelles.
|
||
import { readFile, writeFile, mkdir, rm } 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 REMIX_DIR = join(__dirname, "node_modules", "remixicon", "icons");
|
||
const DIST_DIR = join(__dirname, "dist");
|
||
const EACH_DIR = join(DIST_DIR, "each");
|
||
|
||
if (existsSync(DIST_DIR)) await rm(DIST_DIR, { recursive: true });
|
||
await mkdir(EACH_DIR, { recursive: true });
|
||
|
||
const ICONS = [
|
||
["Arrows", "arrow-right"],
|
||
["Arrows", "arrow-left"],
|
||
["Arrows", "arrow-up"],
|
||
["Arrows", "arrow-down"],
|
||
["Arrows", "arrow-right-up"],
|
||
["Arrows", "arrow-go-back"],
|
||
["Arrows", "expand-up-down"],
|
||
["System", "external-link"],
|
||
["System", "check"],
|
||
["System", "close"],
|
||
["System", "add"],
|
||
["System", "subtract"],
|
||
["System", "search-2"],
|
||
["System", "filter-3"],
|
||
["System", "more"],
|
||
["System", "more-2"],
|
||
["System", "menu"],
|
||
["System", "settings-3"],
|
||
["System", "refresh"],
|
||
["System", "delete-bin"],
|
||
["Design", "edit"],
|
||
["System", "share"],
|
||
["System", "download"],
|
||
["System", "upload"],
|
||
["System", "information"],
|
||
["System", "alert"],
|
||
["System", "error-warning"],
|
||
["System", "checkbox-circle"],
|
||
["System", "close-circle"],
|
||
["System", "question"],
|
||
["System", "spam"],
|
||
["System", "shield-check"],
|
||
["User & Faces", "user"],
|
||
["User & Faces", "user-add"],
|
||
["User & Faces", "team"],
|
||
["User & Faces", "account-circle"],
|
||
["System", "logout-box-r"],
|
||
["System", "login-box"],
|
||
["System", "lock"],
|
||
["System", "lock-unlock"],
|
||
["System", "eye"],
|
||
["System", "eye-off"],
|
||
["Business", "mail"],
|
||
["Business", "mail-send"],
|
||
["Communication", "message-2"],
|
||
["Device", "phone"],
|
||
["Media", "notification-3"],
|
||
["Communication", "chat-3"],
|
||
["Business", "global"],
|
||
["Business", "calendar"],
|
||
["Business", "calendar-check"],
|
||
["System", "time"],
|
||
["System", "history"],
|
||
["Document", "file-text"],
|
||
["Document", "file"],
|
||
["Document", "folder"],
|
||
["Document", "folder-open"],
|
||
["Document", "file-pdf"],
|
||
["Document", "file-copy"],
|
||
["Editor", "attachment"],
|
||
["Document", "draft"],
|
||
["Business", "inbox"],
|
||
["Map", "rocket-2"],
|
||
["Buildings", "home-4"],
|
||
["Buildings", "building"],
|
||
["Buildings", "store-2"],
|
||
["Buildings", "community"],
|
||
["Map", "map-pin-2"],
|
||
["Map", "map-2"],
|
||
["Finance", "money-euro-circle"],
|
||
["Finance", "bank-card"],
|
||
["Finance", "shopping-cart-2"],
|
||
["Finance", "shopping-bag-3"],
|
||
["Finance", "price-tag-3"],
|
||
["Finance", "coins"],
|
||
["Business", "briefcase-4"],
|
||
["Business", "line-chart"],
|
||
["Business", "bar-chart"],
|
||
["Business", "pie-chart"],
|
||
["Business", "stack"],
|
||
["System", "dashboard"],
|
||
["System", "apps-2"],
|
||
["System", "function"],
|
||
["Business", "presentation"],
|
||
["Document", "newspaper"],
|
||
["Document", "article"],
|
||
["Document", "book-open"],
|
||
["Business", "bookmark-3"],
|
||
["Health & Medical", "heart-3"],
|
||
["System", "star"],
|
||
["System", "thumb-up"],
|
||
["Design", "palette"],
|
||
["Design", "magic"],
|
||
["Weather", "flashlight"],
|
||
["Weather", "sun"],
|
||
["Weather", "moon"],
|
||
];
|
||
|
||
const BASE_CSS = `/* DSMMG icons — base (auto-generated). */
|
||
.mmg-icon {
|
||
display: inline-block;
|
||
width: 1.25em;
|
||
height: 1.25em;
|
||
vertical-align: -0.225em;
|
||
background: currentColor;
|
||
mask-repeat: no-repeat;
|
||
mask-position: center;
|
||
mask-size: contain;
|
||
-webkit-mask-repeat: no-repeat;
|
||
-webkit-mask-position: center;
|
||
-webkit-mask-size: contain;
|
||
flex-shrink: 0;
|
||
}
|
||
.mmg-icon--xs { width: 12px; height: 12px; }
|
||
.mmg-icon--sm { width: 14px; height: 14px; }
|
||
.mmg-icon--md { width: 18px; height: 18px; }
|
||
.mmg-icon--lg { width: 24px; height: 24px; }
|
||
.mmg-icon--xl { width: 32px; height: 32px; }
|
||
.mmg-icon--2xl { width: 48px; height: 48px; }
|
||
`;
|
||
|
||
const rules = [];
|
||
const names = [];
|
||
const missing = [];
|
||
|
||
for (const [category, base, alias] of ICONS) {
|
||
for (const variant of ["line", "fill"]) {
|
||
const file = join(REMIX_DIR, category, `${base}-${variant}.svg`);
|
||
if (!existsSync(file)) {
|
||
missing.push(`${category}/${base}-${variant}`);
|
||
continue;
|
||
}
|
||
const svg = (await readFile(file, "utf8"))
|
||
.replace(/[\r\n]+/g, "")
|
||
.replace(/"/g, "'")
|
||
.replace(/\s+/g, " ")
|
||
.trim();
|
||
const url = `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
||
const className = `${alias ?? base}-${variant}`;
|
||
const rule = `.mmg-icon-${className} { mask-image: url("${url}"); -webkit-mask-image: url("${url}"); }`;
|
||
rules.push(rule);
|
||
names.push(className);
|
||
|
||
// Module subset par icône — n'inclut PAS la base, à charger séparément ou
|
||
// implicitement via @managemate/icons/base.
|
||
await writeFile(join(EACH_DIR, `${className}.css`), rule + "\n");
|
||
}
|
||
}
|
||
|
||
// Bundle complet — base + toutes les classes
|
||
await writeFile(join(DIST_DIR, "icons.css"), BASE_CSS + "\n" + rules.join("\n") + "\n");
|
||
// Base seule — utile pour ceux qui font du subset
|
||
await writeFile(join(DIST_DIR, "base.css"), BASE_CSS);
|
||
|
||
await writeFile(join(DIST_DIR, "icons.json"), JSON.stringify(names, null, 2));
|
||
await writeFile(
|
||
join(DIST_DIR, "names.js"),
|
||
`export default ${JSON.stringify(names, null, 2)};\n`,
|
||
);
|
||
await writeFile(
|
||
join(DIST_DIR, "names.d.ts"),
|
||
`declare const names: string[];\nexport default names;\n`,
|
||
);
|
||
|
||
console.log(`Built ${names.length} icon classes (${ICONS.length} icons × 2 variants)`);
|
||
console.log(` - dist/icons.css (bundle, ${BASE_CSS.length + rules.join("\n").length} bytes)`);
|
||
console.log(` - dist/base.css (base only)`);
|
||
console.log(` - dist/each/<name>.css (${names.length} per-icon modules)`);
|
||
if (missing.length) {
|
||
console.warn(`Missing ${missing.length} files:`, missing.slice(0, 5));
|
||
}
|