Skip to content

feat(website/design): semantic design-token system, collapse legacy color tokens - #714

Merged
ajitpratap0 merged 2 commits into
mainfrom
feat/design-tokens
Oct 14, 2026
Merged

ajitpratap0 merged 2 commits into
mainfrom
feat/design-tokens

Conversation

@ajitpratap0

Copy link
Copy Markdown
Owner

Summary

Implements the semantic design-token system from plan section 7 (issue #659).

  • One token set, two themes. website/src/app/globals.css now defines --bg, --bg-raised, --bg-overlay, --fg, --fg-muted, --fg-subtle, --border, --brand, --brand-fg, --accent, --accent-fg, --accent-warm, --danger and --ok on :root (dark) and html.light (light). color-scheme is set per theme.
  • Tailwind mapping. @theme inline maps each token to --color-* as var(--token), so utilities (bg-bg, bg-bg-raised, text-fg-subtle, bg-brand, text-accent, bg-accent/10, text-danger, ...) follow the theme at runtime. The old @theme inline hex values never reached utilities in light mode, which is why light mode needed the per-class override layer.
  • Legacy tokens collapsed (no orphaned references). Removed --color-primary/surface/elevated, --color-accent-indigo/orange/green/purple, --color-bg-*, --color-text-*, --color-link, --color-border-*, --color-brand-hover. All usages were grepped and migrated first:
    • text-text-muted -> text-fg-subtle (49 uses)
    • *-accent-indigo / *-accent-purple -> *-accent
    • *-accent-green -> *-brand
    • *-accent-orange -> *-accent-warm
    • bg-primary / bg-[#09090b] -> bg-bg, bg-surface -> bg-bg-raised
    • solid accent buttons now use text-accent-fg (white on #818CF8 was about 2.9:1)
    • rg 'accent-(indigo|green|orange|purple)|text-text-|bg-primary|bg-surface\b|--color-(primary|surface|elevated|bg-|text-|link)' returns nothing under website/src.
  • html.light overrides deleted for everything that now runs on tokens: the token override block, the text-text-muted patch, body colours, .bg-primary/.bg-surface, version badge, all text-accent-* / bg-accent-*/10 rules, the pre .text-accent-* rules, prose colour overrides, the light focus-ring override and the light inline-code override. Code blocks that stay dark in light mode get the dark token values on html.light pre, so they need no per-class rules. The remaining overrides only cover raw zinc/slate/white palette classes; they are marked to be deleted as those components move to tokens.
  • Light-mode contrast bugs fixed while auditing:
    • Navbar background stayed dark in light mode (the useTransform closure captured a stale isLight). It now uses color-mix(var(--bg) ...), and the MutationObserver is gone.
    • Prose <strong> was white on white (about 1.04:1) on every docs page because prose-invert bold/counters/bullets/quotes/borders were never themed. They are now token-driven.
    • The playground <h1> (text-slate-100, about 1.01:1), the VS Code settings <pre>, the dialect showcase avatars and status badges, the benchmarks "GoSQLX" pill, MiniPlayground links and the playground status text (green-400/red-400 -> text-ok/text-danger) were moved to tokens.
  • Deviations from the plan palette (made to pass AA on tinted surfaces): light --fg-subtle is #5B6472 (#6B7280 is below 4.5:1 on --bg-overlay), light --ok is #166534 and light --accent-warm is #9A3412 (the plan values drop below 4.5:1 on 10% tinted badges).

CHANGELOG.md is intentionally not edited (the release is being prepared in another session). Suggested entry under Unreleased / Website: "Semantic design-token system; legacy colour tokens and most light-mode override CSS removed; light-mode contrast fixes (navbar, docs bold text, playground header)."

Token contrast (WCAG 2.x, computed)

Text pairs need 4.5:1. The accent focus ring and UI need 3:1. --border hairlines are decorative separators (WCAG 1.4.11 does not apply to them), so they are not listed.

Theme Foreground Background Ratio Result
dark --fg --bg 17.39 AA
dark --fg --bg-raised 16.40 AA
dark --fg --bg-overlay 15.19 AA
dark --fg-muted --bg 7.79 AA
dark --fg-muted --bg-raised 7.35 AA
dark --fg-muted --bg-overlay 6.80 AA
dark --fg-subtle --bg 5.92 AA
dark --fg-subtle --bg-raised 5.59 AA
dark --fg-subtle --bg-overlay 5.17 AA
dark --brand --bg 8.67 AA
dark --brand --bg-raised 8.18 AA
dark --brand --bg-overlay 7.57 AA
dark --accent --bg 6.62 AA
dark --accent --bg-raised 6.25 AA
dark --accent --bg-overlay 5.78 AA
dark --accent-warm --bg 8.73 AA
dark --accent-warm --bg-raised 8.23 AA
dark --accent-warm --bg-overlay 7.62 AA
dark --danger --bg 7.14 AA
dark --danger --bg-raised 6.74 AA
dark --danger --bg-overlay 6.24 AA
dark --ok --bg 11.33 AA
dark --ok --bg-raised 10.69 AA
dark --ok --bg-overlay 9.90 AA
dark --brand-fg --brand 6.54 AA
dark --accent-fg --accent 6.62 AA
dark --accent --bg 6.62 AA (UI 3:1)
light --fg --bg 17.12 AA
light --fg --bg-raised 17.74 AA
light --fg --bg-overlay 15.96 AA
light --fg-muted --bg 7.29 AA
light --fg-muted --bg-raised 7.56 AA
light --fg-muted --bg-overlay 6.80 AA
light --fg-subtle --bg 5.77 AA
light --fg-subtle --bg-raised 5.98 AA
light --fg-subtle --bg-overlay 5.38 AA
light --brand --bg 4.84 AA
light --brand --bg-raised 5.02 AA
light --brand --bg-overlay 4.51 AA
light --accent --bg 6.07 AA
light --accent --bg-raised 6.29 AA
light --accent --bg-overlay 5.66 AA
light --accent-warm --bg 7.05 AA
light --accent-warm --bg-raised 7.31 AA
light --accent-warm --bg-overlay 6.57 AA
light --danger --bg 6.24 AA
light --danger --bg-raised 6.47 AA
light --danger --bg-overlay 5.82 AA
light --ok --bg 6.88 AA
light --ok --bg-raised 7.13 AA
light --ok --bg-overlay 6.41 AA
light --brand-fg --brand 5.02 AA
light --accent-fg --accent 6.29 AA
light --accent --bg 6.07 AA (UI 3:1)

Test Plan

  • cd website && npm ci && npm run typecheck && npm run lint && npm run build: typecheck clean, lint 0 errors (7 existing warnings), build OK (105 static pages). The build was run clean (rm -rf .next) because a stale Turbopack cache had served old CSS.
  • Built CSS checked: utilities resolve to runtime variables (for example .text-fg-subtle{color:var(--fg-subtle)} and .bg-accent\/10{background-color:color-mix(in oklab,var(--accent) 10%,transparent)}).
  • Contrast audit in Chrome against next start for the 8 routes (/, /docs/, /docs/getting-started/, /playground/, /blog/, /benchmarks/, /compare/, /vscode/), in light and dark (16 runs).
    • The script walks every visible text node, composites its colour over the stacked ancestor backgrounds, and flags anything below 4.5:1, or 3:1 for large text. Animations were disabled so below-the-fold content counts.
    • In the first pass (after the token migration, before the follow-up fixes), light mode had 26 failing groups, all from raw palette classes or pre-existing bugs, including the navbar (3.25), docs <strong> (1.04), the playground title (1.01) and dialect avatars (1.76).
    • Final result: 0 failures in both themes.
  • Light and dark screenshots of the home page (hero, dialect grid), /docs/getting-started/ and /playground/ reviewed: the navbar is light in light mode, badges are readable and code blocks stay dark.
  • Lighthouse CI (.github/workflows/lighthouse.yml) on this PR.
  • Vercel preview: toggle the theme on the 8 routes.

Breaking Changes

None for the Go library or public site URLs. For website contributors only: the legacy Tailwind colour utilities (text-accent-indigo, text-text-muted, bg-primary, bg-surface, ...) no longer exist. Use the semantic ones (text-accent, text-fg-subtle, bg-bg, bg-bg-raised, ...). Open PRs that add legacy classes will need a rebase and rename.

Closes #659
Part of #634

🤖 Generated with Claude Code

https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

…olor tokens

Replace the duplicated legacy tokens (--color-primary/surface/elevated,
--color-accent-*, --color-bg-*, --color-text-*, --color-link) with one
semantic set defined on :root (dark) and html.light (light): --bg,
--bg-raised, --bg-overlay, --fg, --fg-muted, --fg-subtle, --border,
--brand, --brand-fg, --accent, --accent-fg, --accent-warm, --danger, --ok.

@theme inline maps them to Tailwind utilities that reference the runtime
variables, so light mode now switches through the variables instead of
per-class !important overrides. Every legacy class usage is migrated and
the html.light overrides that targeted them are deleted.

Also fixes light-mode contrast failures found while auditing the 8 key
routes: navbar background stuck dark, invisible prose <strong>, playground
title, VS Code settings block, dialect/status badges and playground status
text now use tokens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
@vercel

vercel Bot commented Oct 14, 2026

Copy link
Copy Markdown

Deployment failed for project gosqlx-website with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/coolajitpratapsingh0-9932s-projects?upgradeToPro=build-rate-limit

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 24s —— View job


Review of PR #714: semantic design-token system

  • Read the diff for globals.css and Navbar.tsx
  • Grepped for leftover legacy tokens
  • Not run: build, typecheck, lint, and a Lighthouse or browser check. This was a read-only review.

Summary

This is a good refactor. Moving to @theme inline with var(--token) is the right fix for the root cause, since the old baked-in hex values never followed html.light. The grep for legacy tokens under website/src returns nothing, so there are no orphaned references. The contrast table and the documented deviations from the plan palette (--fg-subtle, --ok and --accent-warm in light mode) are thorough.

Findings

1. Remaining raw white/… borders and backgrounds. (low)
Navbar.tsx still has border-white/[0.08] and bg-white/[0.03] on the <kbd>, plus border-white/[0.06] on the mobile menu. These rely on the html.light [class*="bg-white\/…"] override layer. That works for now and the PR says it's intentional. I'd convert them to border-border and bg-bg-overlay soon, so the override layer can be deleted. --border is already defined for exactly this.

2. Mobile menu uses bg-bg backdrop-blur-xl. (nit)
bg-bg is fully opaque, so backdrop-blur-xl does nothing. This is harmless, and the old bg-primary behaved the same. If a translucent menu was intended, use bg-bg/90.

3. color-mix(in srgb, var(--bg) N%, transparent) in Navbar.tsx. (low)
This syntax is supported by evergreen browsers (roughly Chrome 111+, Safari 16.2+, Firefox 113+). On older browsers the navbar background would be invalid and fall back to transparent. If the support policy needs it, add a solid fallback. The same applies to the .prose-dark color-mix usages, where --tw-prose-body would be invalid on older browsers.

4. Code-block token restoration is incomplete. (low)
html.light pre, html.light textarea[class*="font-mono"] restores --fg, --fg-muted, --fg-subtle, --brand, --accent, --accent-warm, --danger and --ok. It does not restore --border, --bg-* or --accent-fg/--brand-fg. Any border-border, bg-bg-overlay or bg-accent + text-accent-fg element placed inside a <pre> would get light-theme values on a dark block. Nothing in this diff does that, but it's a trap for later. Restoring the full set, or adding a comment saying which tokens are supported, would help. Also note --tw-prose-pre-bg stays hardcoded (#12121A/#1E1E2E) rather than using a token.

5. Hardcoded values remain in the override layer. (nit)
html.light .text-white { color: #111827 !important } and similar rules duplicate --fg. That's fine as a temporary shim, since the comment says to delete them as components migrate. Consider tracking the migration in a follow-up issue so the rules don't linger.

6. Tests. (info)
There are no automated checks that guard the token contrast. A small script, or a CI step that asserts the WCAG ratios in the PR table against globals.css, would stop future palette edits from regressing silently. The Lighthouse and Vercel preview boxes in the test plan are still unchecked.

Verdict

No blocking issues. The main follow-ups are items 1 and 4. The Go library is untouched, so there is no performance or security impact. The only runtime change is a lighter Navbar, because the MutationObserver and extra state are gone.
· branch feat/design-tokens

Fenced code blocks in light mode got a white code background behind
forced light text (~1.4:1). Restrict bg-bg-raised to inline code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
@ajitpratap0

Copy link
Copy Markdown
Owner Author

Fixed the light-mode fenced code regression in website/src/app/blog/[slug]/page.tsx. prose-code:bg-bg-raised is now [&_:not(pre)>code]:bg-bg-raised, so the background applies to inline code only. Verified with next start and Chrome on /blog/v1-9-2/ in both themes. Code inside the pre is transparent over the pre background. In light, text rgb(212,212,216) on rgb(30,30,46) is about 11:1, and inline code keeps its tinted bg. typecheck, lint (0 errors) and build pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

@vercel

vercel Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
gosqlx-website Ready Ready Preview Oct 14, 2026 7:25pm UTC

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 37s —— View job


Review of PR #714: semantic design-token system

I read the diff for globals.css, Navbar.tsx and the blog page, and re-ran the legacy-token grep. I did not run the build, typecheck, lint, Lighthouse or a browser check.

Overall: the approach is sound. @theme inline with var(--token) fixes the root cause, which is that the old baked-in hex values never followed html.light. The legacy-token grep is clean. The only hits are --color-bg-raised and --color-bg-overlay in globals.css:77-78. Those are the new tokens, and the --color-bg- pattern in the PR's regex matches them. The contrast table and the stated palette deviations are thorough. No blocking issues.

Findings

  1. Blog code background is redundant (low). [&_:not(pre)>code]:bg-bg-raised in blog/[slug]/page.tsx sets the same property as the unlayered .prose-dark :not(pre) > code rule in globals.css. That rule uses color-mix(var(--fg) 8%, transparent) and wins over layered utilities. Light --bg-raised is #FFF on a #FAFBFC page, so it would be nearly invisible anyway. Your Chrome check of inline code is consistent with the CSS rule doing the work. I'd drop the utility so there is one source of truth.

  2. Code-block token restoration is incomplete (low). html.light pre, html.light textarea[class*="font-mono"] restores only the fg, brand, accent, accent-warm, danger and ok tokens. It leaves --border, --bg-*, --accent-fg and --brand-fg at light values. That is fine today. It will bite the first time someone puts border-border or bg-accent text-accent-fg inside a <pre>. Restore the full set, or add a comment listing the supported tokens. --tw-prose-pre-bg (#12121A / #1E1E2E) is also still hardcoded.

  3. Remaining white/… utilities in Navbar.tsx (low). The <kbd> (border-white/[0.08] bg-white/[0.03]) and the mobile menu (border-white/[0.06]) still depend on the html.light [class*="bg-white\/…"] override layer. border-border and bg-bg-overlay fit here and would let you delete that layer. Similarly, hover:text-zinc-300 on the blog back link and text-zinc-300 group-hover:text-white on the prev/next links still rely on the zinc overrides.

  4. Mobile menu bg-bg backdrop-blur-xl (nit). bg-bg is opaque, so the blur does nothing. The old bg-primary behaved the same. If you want a translucent menu, use bg-bg/90.

  5. color-mix() has no fallback (low). Navbar.tsx and the .prose-dark rules use color-mix(in srgb, …). Browsers older than roughly Chrome 111, Safari 16.2 or Firefox 113 treat it as invalid. The navbar would be transparent, and --tw-prose-body would fall back to inherited. This is acceptable for an evergreen-only policy. If you need older browsers, add a solid fallback declaration.

  6. No guard on contrast (info). The AA table is computed by hand, so a later palette edit can regress it silently. A small script that parses the token hexes from globals.css and asserts the ratios would be cheap. It could run in CI next to Lighthouse. The Lighthouse and Vercel preview checkboxes are still unchecked. The Vercel deploy also failed on the free-tier rate limit, not on a build error.

  7. Override-layer cleanup (nit). html.light .text-white { color: #111827 !important } duplicates --fg. Consider a follow-up issue to track migrating the remaining raw zinc/slate/white classes, so the shim doesn't linger.

No Go library, performance or security impact. The Navbar is slightly lighter now that the MutationObserver is gone.
· branch feat/design-tokens

@ajitpratap0
ajitpratap0 merged commit a22990f into main Oct 14, 2026
30 checks passed
@ajitpratap0
ajitpratap0 deleted the feat/design-tokens branch October 14, 2026 19:31

This branch was successfully deployed

1 active deployment
Preview — 1a222177 Deployed Oct 14, 2026 by vercel[bot]
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.

feat(website/design): semantic design-token system, collapse legacy color tokens [2.1]

1 participant