mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-17 02:59:40 +02:00
refactor(theming): migrate 6 ListViews + ai-missions badges to theme tokens
Replace raw white-alpha Tailwind utilities (text-white/x, bg-white/x, border-white/x) with canonical theme tokens (text-foreground, bg-muted, border-border, etc.) in cards, context, food, moodlit, storage, music ListViews. Replace hardcoded hex badge/dot/phase colors in ai-missions with success/warning/error/primary tokens. Fix two transition-all bugs (food:160, moodlit:223) that prevented CSS custom property colors from resolving on first paint under theme switches. Add scripts/validate-theme-tokens.mjs to prevent regression; run via pnpm run validate:theme-tokens. Not yet in validate:all — 12 modules still use raw white utilities (citycorners, guides, inventory, memoro, picture, plants, playground, presi, questions, times, uload, who). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dc22240483
commit
a2a43b1d5a
9 changed files with 188 additions and 75 deletions
103
scripts/validate-theme-tokens.mjs
Normal file
103
scripts/validate-theme-tokens.mjs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* Validate that module ListView.svelte files use theme tokens instead of
|
||||
* raw white-alpha Tailwind utilities.
|
||||
*
|
||||
* Background: the unified Mana app supports multiple theme variants (Lume,
|
||||
* Nature, Stone, Ocean, plus dark). Utilities like `text-white/80`,
|
||||
* `bg-white/5`, `border-white/10` ignore the active theme and can render
|
||||
* white-on-white in light variants. The theme tokens (`text-foreground`,
|
||||
* `bg-muted`, `border-border`, etc.) are the canonical replacements —
|
||||
* they're generated by Tailwind v4 from `packages/shared-tailwind/src/themes.css`
|
||||
* and resolve per-theme automatically.
|
||||
*
|
||||
* Rule: `src/lib/modules/**\/ListView.svelte` must not contain
|
||||
* - `bg-white/` (e.g. bg-white/5, bg-white/10, hover:bg-white/5)
|
||||
* - `text-white/` (e.g. text-white/80, hover:text-white/90)
|
||||
* - `border-white/` (e.g. border-white/10, focus:border-white/20)
|
||||
*
|
||||
* Suggested replacements:
|
||||
* bg-white/N → bg-muted/N or bg-card
|
||||
* text-white → text-foreground
|
||||
* text-white/40-60 → text-muted-foreground
|
||||
* border-white/N → border-border
|
||||
*
|
||||
* `text-white` without an opacity modifier is allowed when it sits on a
|
||||
* guaranteed-dark surface (mood gradient overlays, photo viewer) — those
|
||||
* are brand literals per the themes.css policy.
|
||||
*
|
||||
* Zero deps — runs as plain Node ESM. Uses `git ls-files` to respect
|
||||
* .gitignore.
|
||||
*/
|
||||
|
||||
import { execSync } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const REPO_ROOT = join(__dirname, '..');
|
||||
|
||||
const LIST_VIEW_GLOB = 'apps/mana/apps/web/src/lib/modules/*/ListView.svelte';
|
||||
|
||||
// `\b` before ensures we catch `hover:bg-white/`, `focus:border-white/`,
|
||||
// etc., without matching unrelated class names like `off-white`.
|
||||
const FORBIDDEN = /(?:^|[\s:"'`])(bg|text|border)-white\//g;
|
||||
|
||||
function listListViews() {
|
||||
const out = execSync(`git ls-files "${LIST_VIEW_GLOB}"`, {
|
||||
cwd: REPO_ROOT,
|
||||
encoding: 'utf8',
|
||||
});
|
||||
return out
|
||||
.split('\n')
|
||||
.map((p) => p.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function validate() {
|
||||
const paths = listListViews();
|
||||
const violations = [];
|
||||
|
||||
for (const rel of paths) {
|
||||
const abs = join(REPO_ROOT, rel);
|
||||
const src = readFileSync(abs, 'utf8');
|
||||
const lines = src.split('\n');
|
||||
|
||||
lines.forEach((line, i) => {
|
||||
FORBIDDEN.lastIndex = 0;
|
||||
let match;
|
||||
while ((match = FORBIDDEN.exec(line)) !== null) {
|
||||
violations.push({
|
||||
file: rel,
|
||||
line: i + 1,
|
||||
token: `${match[1]}-white/`,
|
||||
snippet: line.trim().slice(0, 120),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (violations.length > 0) {
|
||||
console.error(`\n✗ Theme-token check FAILED (${violations.length} violation(s)):\n`);
|
||||
for (const v of violations) {
|
||||
console.error(` • ${v.file}:${v.line} [${v.token}]`);
|
||||
console.error(` ${v.snippet}`);
|
||||
}
|
||||
console.error(
|
||||
`\nReplace raw white-alpha utilities with theme tokens:\n` +
|
||||
` bg-white/N → bg-muted/N or bg-card\n` +
|
||||
` text-white → text-foreground\n` +
|
||||
` text-white/40-60 → text-muted-foreground\n` +
|
||||
` border-white/N → border-border\n\n` +
|
||||
`Rationale: raw white utilities ignore theme variants (Lume, Nature, ...)\n` +
|
||||
`and can render white-on-white under light themes. See\n` +
|
||||
`packages/shared-tailwind/src/themes.css for the full token set.\n`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`✓ Theme-token check: ${paths.length} ListView(s) use theme tokens correctly.`);
|
||||
}
|
||||
|
||||
validate();
|
||||
Loading…
Add table
Add a link
Reference in a new issue