refactor(web): extract design tokens to tokens.json source of truth

The Flutter client (#356) needs to consume the same FabledSword tokens
the web SPA uses. Move the data into a structured tokens.json file and
generate tokens.generated.css from it on every Vite build. The Flutter
side gets its own generator pointed at the same JSON.

No visual change — generated CSS matches the previous hand-written file.

Also installs @types/node devDependency: tsconfig already declared
"types": ["node"] but no Node builtins were referenced in TS until now,
so the missing types were latent. The new vite.config.ts plugin imports
node:child_process, surfacing the gap.
This commit is contained in:
2026-05-02 14:55:46 -04:00
parent 261c2c4301
commit ea22807a3f
8 changed files with 94 additions and 55 deletions
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env node
// Reads ../src/lib/styles/tokens.json and emits tokens.generated.css.
// Single source of truth for FabledSword tokens shared with the Flutter
// client. Keep output deterministic — Tailwind reads tokens.json directly,
// the .css emission is for raw CSS consumers.
import { readFileSync, writeFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';
const here = dirname(fileURLToPath(import.meta.url));
const tokensPath = resolve(here, '../src/lib/styles/tokens.json');
const outPath = resolve(here, '../src/lib/styles/tokens.generated.css');
const tokens = JSON.parse(readFileSync(tokensPath, 'utf8'));
const lines = ['/* GENERATED — do not edit. Source: tokens.json */', ':root {'];
for (const [name, value] of Object.entries(tokens.colors)) {
lines.push(` --fs-${name}: ${value};`);
}
for (const [name, value] of Object.entries(tokens.radii)) {
lines.push(` --fs-radius-${name}: ${value};`);
}
lines.push(` --fs-font-display: ${tokens.fontStacks.display};`);
lines.push(` --fs-font-body: ${tokens.fontStacks.body};`);
lines.push(` --fs-font-mono: ${tokens.fontStacks.mono};`);
lines.push('}', '[data-fs-app="minstrel"] {', ` --fs-accent: ${tokens.colors.accent};`, '}', '');
writeFileSync(outPath, lines.join('\n'));
console.log(`wrote ${outPath}`);