Skip to content

fix(theme): replace no-op --mat-sys-* tokens with --app-* design tokens#1181

Open
4gray wants to merge 1 commit into
masterfrom
claude/objective-driscoll-aa134a
Open

fix(theme): replace no-op --mat-sys-* tokens with --app-* design tokens#1181
4gray wants to merge 1 commit into
masterfrom
claude/objective-driscoll-aa134a

Conversation

@4gray

@4gray 4gray commented Jul 12, 2026

Copy link
Copy Markdown
Owner

What & why

apps/web/src/m3-theme.scss uses Angular Material's older M3 API (mat.define-theme + mat.all-component-themes), which emits component tokens but never emits the --mat-sys-* system tokens. So ~540 var(--mat-sys-*) references across the app were silent no-ops — invalid at computed-value time, falling back to inherited/initial values. Many backgrounds, borders and dividers never rendered, and several text/icon colors sat at the wrong contrast (verified empirically via CDP: no stylesheet rule defines any --mat-sys-* variable).

Strategy: rather than migrate to mat.theme() (v19+) — which would flip every no-op at once with M3 azure-palette values foreign to the hand-tuned design — this remaps the high-visibility usages to the existing --app-* design tokens defined for both themes in m3-theme.scss. Every change was screenshot-verified in light and dark via Electron CDP. See docs/architecture/theme-design-tokens.md for the full rationale and mapping table.

Changes

  • New tokens: --app-error-color, --app-accent-color (light + dark).
  • High-visibility surfaces remapped: 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.
  • Tailwind palette now points at --app-* tokens instead of --mat-sys-*.
  • ~150 dead fallbacks removed repo-wide (var(--app-x, var(--mat-sys-y))var(--app-x) — the fallback can never be taken).
  • UI polish surfaced by the remap (each was a previously-invisible no-op that started rendering):
    • Header icon buttons: suppress Material's circular state layer, keep the rounded-rectangle hover (consistent with rail/nav and the .is-active chip).
    • Remove the orphan divider before the download button.
    • Remove the redundant right-edge accent bar on active rail items — the filled chip is enough (applied across all rails for consistency).
    • Raise header/switcher control icons from the muted tier to --app-body-color so they no longer read as disabled.

Regression guard

  • tools/styles/check-mat-sys-usage.mjs fails on any new var(--mat-sys-*) reference; the ~180 remaining 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 — why the tokens are no-ops, the --app-* mapping table, and the screenshot-driven migration protocol.
  • CLAUDE.md — token policy + the new lint check.

Notes for reviewers

  • No behavior/logic changes — style values only. Validation was runtime CDP verification in both themes plus the CI guard; no unit/E2E impact.
  • Scrollbar-related --mat-sys-* usages are intentionally left untouched — they belong to the separate branch claude/iptvnator-dark-scrollbar-2600aa.
  • Remaining ~180 baselined usages are mostly playback surfaces (embedded-mpv/audio players, external-playback dock, season container, command palette) to be migrated incrementally per the doc.

🤖 Generated with Claude Code

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>
@greptile-apps

greptile-apps Bot commented Jul 12, 2026

Copy link
Copy Markdown

Greptile Summary

This PR moves high-visibility theme styling from unavailable Material system tokens to app design tokens. The main changes are:

  • New app-level error and accent color tokens for light and dark themes.
  • Remapped SCSS and Tailwind colors to --app-* tokens.
  • Removed dead --mat-sys-* fallbacks from migrated styles.
  • Added documentation for the token policy and migration workflow.
  • Added a CI guard and baseline tooling for remaining legacy token usages.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
tools/styles/check-mat-sys-usage.mjs Adds the CI check that rejects new var(--mat-sys-*) references above the baseline.
tools/styles/mat-sys-usage.shared.mjs Adds the shared scanner for app and library style/template/source files.
tools/styles/mat-sys-baseline.mjs Adds the generated baseline for remaining legacy Material system token usages.
apps/web/src/m3-theme.scss Adds canonical --app-error-color and --app-accent-color values for both themes.
apps/web/tailwind.config.js Remaps Tailwind semantic colors from Material system tokens to app design tokens.
docs/architecture/theme-design-tokens.md Documents why --mat-sys-* tokens are unavailable and how to migrate usages safely.
.github/workflows/ci.yml Runs the new style-token guard in the lint job.

Reviews (1): Last reviewed commit: "fix(theme): replace no-op --mat-sys-* to..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eac1dfa09e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +25 to +27
const violations = usages.filter(
({ file, count }) => count > (matSysBaseline.get(file) ?? 0)
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require the style baseline to shrink exactly

When a file already has a baseline entry, this only compares the total usage count. If a migration deletes one old var(--mat-sys-*) reference and adds a new one in the same file, the count stays at or below the baseline, so CI accepts the new no-op token as grandfathered; leaving a shrunk baseline stale creates the same headroom. Since this guard is meant to fail any new usages, track exact occurrences or fail until reduced counts are regenerated into the baseline.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant