Design tokens + agent iteration hardening

- tokens.css: full token layer (type scale rem-based, palette, spacing, radii)
- App.css rebuilt token-driven; zero hardcoded colors/px font sizes
- readability preset: --root-font-size 112%; button matrix scrolls when narrow
- App.tsx split into real components (Hero, CodeSample, RightRail + reflow)
- light theme via [data-theme=light] overrides; topbar sun/moon toggle persisted
- scripts/check-tokens.mjs + npm run check (lint, token guard, tsc, build)
- AGENTS.md: token contract, check gate, preview workflow
This commit is contained in:
mats committed 2026-09-12 10:07:07 +00:00
1 parent b1049d5ded
commit 47127db84b
20 files changed
+874 -57

No files matched your search

+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env node
/* Token contract guard — runs as part of `npm run check`.
Bans hardcoded values in application CSS so every visual change
goes through src/tokens.css. */
import { readFileSync, readdirSync, statSync } from 'node:fs'
import { join } from 'node:path'
const CSS_ROOTS = ['src']
const EXEMPT = new Set(['tokens.css'])
// Neutral shine/shadow literals stay allowed (they are surfaces, not palette).
const RGB_ALLOW = [/rgba\(\s*0\s*,\s*0\s*,\s*0/, /rgba\(\s*255\s*,\s*255\s*,\s*255/]
const violations = []
function walk(dir) {
for (const entry of readdirSync(dir)) {
const full = join(dir, entry)
if (statSync(full).isDirectory()) {
walk(full)
} else if (full.endsWith('.css') && !EXEMPT.has(entry)) {
checkFile(full, readFileSync(full, 'utf8'))
}
}
}
function checkFile(file, css) {
css.split('\n').forEach((line, i) => {
const n = `${file}:${i + 1}`
const hex = line.match(/#[0-9a-fA-F]{3,8}\b/)
if (hex) violations.push(`${n} hex color ${hex[0]} — add a token in tokens.css instead`)
if (/font(-size)?\s*:[^;}]*\d+px/.test(line)) violations.push(`${n} px font size — use var(--text-*)`)
const rgb = line.match(/rgba?\(/)
if (rgb && !RGB_ALLOW.some(re => re.test(line))) {
violations.push(`${n} raw rgba() — use color-mix(in srgb, var(--token) N%, transparent)`)
}
})
}
CSS_ROOTS.forEach(walk)
if (violations.length) {
console.error(`\n✗ token contract violations:\n\n${violations.join('\n')}\n`)
process.exit(1)
} else {
console.log('✓ token contract OK — no hardcoded colors or font sizes found')
}