mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
The Material theme setup in apps/web/src/m3-theme.scss uses the older M3 API (mat.define-theme + mat.all-component-themes), which emits component tokens but never emits the --mat-sys-* system tokens. As a result ~540 var(--mat-sys-*) references across the app were silent no-ops: the declarations were invalid at computed-value time and fell back to inherited/initial values, so many backgrounds, borders and dividers never rendered and several text/icon colors sat at the wrong contrast. Rather than migrate to mat.theme() (which would flip every no-op at once with M3 azure-palette values foreign to the hand-tuned design), remap the high-visibility usages to the existing --app-* design tokens defined for both themes in m3-theme.scss, verified screenshot-driven in light and dark via Electron CDP. Changes: - Add --app-error-color and --app-accent-color tokens (light + dark). - Fix high-visibility surfaces: settings area, workspace shell header, playlist switcher, downloads, channel-details dialog, account-info, group/category management dialogs, sources context/filters panels, nav-list, and the .dark-theme app background. - Point the Tailwind color palette at --app-* tokens instead of --mat-sys-*. - Strip ~150 dead var(--app-x, var(--mat-sys-y)) fallbacks repo-wide (the fallback can never be taken). - UI polish surfaced by the remap: suppress Material's circular icon-button state layer in the header (keep the rounded-rectangle hover), remove the orphan divider before the download button, remove the redundant right-edge accent bar on active rail items (the filled chip is enough), and raise the header/switcher control icons from the muted tier to --app-body-color so they no longer read as disabled. Guard against regressions: - tools/styles/check-mat-sys-usage.mjs fails on any new var(--mat-sys-*) reference; legacy usages are grandfathered in a shrink-only baseline (tools/styles/mat-sys-baseline.mjs). Wired into the CI Lint job and exposed as `pnpm run lint:styles`. Docs: - docs/architecture/theme-design-tokens.md documents why the tokens are no-ops, the --app-* mapping table, and the screenshot-driven migration protocol. CLAUDE.md updated with the token policy and the new lint check. Scrollbar-related --mat-sys-* usages are intentionally left untouched here; they belong to the separate branch claude/iptvnator-dark-scrollbar-2600aa. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
49 lines
1.9 KiB
JavaScript
49 lines
1.9 KiB
JavaScript
// Shared scanner for the --mat-sys-* usage guard.
|
|
//
|
|
// The Angular Material theme in apps/web/src/m3-theme.scss uses the older M3
|
|
// API (mat.define-theme + mat.all-component-themes), which emits component
|
|
// tokens but NEVER emits `--mat-sys-*` system tokens. Every
|
|
// `var(--mat-sys-*)` reference therefore fails at computed-value time and
|
|
// silently falls back to inherited/initial values. New styles must use the
|
|
// `--app-*` design tokens defined in m3-theme.scss instead.
|
|
//
|
|
// See docs/architecture/theme-design-tokens.md for the token mapping.
|
|
|
|
import { readdirSync, readFileSync } from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
export const SCAN_ROOTS = ['apps', 'libs'];
|
|
export const SCAN_EXTENSIONS = ['.scss', '.css', '.ts', '.html', '.js'];
|
|
const SKIP_DIRS = new Set(['node_modules', 'dist', '.nx', 'coverage']);
|
|
const USAGE_PATTERN = /var\(--mat-sys-/g;
|
|
|
|
function collectFiles(dir, results) {
|
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
if (entry.isDirectory()) {
|
|
if (!SKIP_DIRS.has(entry.name)) {
|
|
collectFiles(path.join(dir, entry.name), results);
|
|
}
|
|
} else if (SCAN_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) {
|
|
results.push(path.join(dir, entry.name));
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
/** Returns a sorted array of { file, count } for files with usages. */
|
|
export function scanMatSysUsages(workspaceRoot) {
|
|
return SCAN_ROOTS.flatMap((root) =>
|
|
collectFiles(path.join(workspaceRoot, root), [])
|
|
)
|
|
.map((filePath) => ({
|
|
file: path
|
|
.relative(workspaceRoot, filePath)
|
|
.split(path.sep)
|
|
.join('/'),
|
|
count: (readFileSync(filePath, 'utf8').match(USAGE_PATTERN) || [])
|
|
.length,
|
|
}))
|
|
.filter(({ count }) => count > 0)
|
|
.sort((a, b) => a.file.localeCompare(b.file));
|
|
}
|