Skip to content

feat(web): add light mode with three-way theme toggle - #25

Merged
pufit merged 26 commits into
ClickHouse:mainfrom
kschlarman:feat/light-mode
Apr 3, 2026
Merged

pufit merged 26 commits into
ClickHouse:mainfrom
kschlarman:feat/light-mode

Conversation

@kschlarman

Copy link
Copy Markdown
Contributor

Summary

  • Adds a light mode to the Nerve frontend with a three-way toggle (System / Light / Dark) in the NavRail
  • Introduces 13 semantic color tokens as CSS custom properties, registered with Tailwind v4 via @theme inline, replacing ~321 hardcoded hex values across 66 files
  • Dark theme is pixel-identical — all tokens resolve to the original hex values by default
  • Theme preference persists to localStorage with an inline <script> in index.html to prevent flash of wrong theme on load

Architecture

  • CSS layer: @theme inline tokens in index.css with :root dark defaults, [data-theme="light"] overrides, and @media (prefers-color-scheme: light) for system preference
  • Zustand store: themeStore.ts manages preference, sets data-theme attribute on <html>
  • Toggle: ThemeToggle.tsx in NavRail — cycles Sun/Moon/Monitor icons
  • highlight.js: Light mode overrides for code syntax highlighting (GitHub Light theme)

New files

  • web/src/stores/themeStore.ts
  • web/src/components/Layout/ThemeToggle.tsx

Test plan

  • Verify dark mode looks identical to current production (no visual regressions)
  • Click theme toggle in NavRail — cycles System → Light → Dark → System
  • Light mode: backgrounds are light gray/white, text is dark, borders visible
  • Code blocks have correct syntax highlighting in both themes
  • Refresh page — theme preference persists, no flash of wrong theme
  • Set to System mode — verify it follows OS light/dark preference
  • Check colored badges/pills are readable in both themes
  • npx tsc -b --noEmit passes
  • npx vite build passes

🤖 Generated with Claude Code

kschlarman and others added 26 commits April 1, 2026 16:36
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ces, Diagnostics, Cron)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…errides

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The skill editor textarea had a hardcoded text-[#d0d0d0] that was
missed in the migration sweep. Replaced with text-text-secondary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
bg-[#1f1f2f] was an indigo-tinted dark background for selected items
that rendered as near-black in light mode. Replaced with bg-[#6366f1]/10
(semi-transparent indigo) which works on both light and dark backgrounds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Job name used hardcoded text-[#eee] (near-white), replaced with text-text
- Run/Rotate buttons used text-text-dim (#999 in light mode, poor contrast),
  bumped to text-text-muted (#666, passes WCAG AA)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Several components had hardcoded dark hover/background colors (ClickHouse#111,
#0c0c10, #141420, #1a1a22, #252530) that rendered as near-black in
light mode. Replaced with semantic tokens (surface-hover, bg-sunken, etc).

Affected: BashToolBlock, SidePanel, MemuPage, QuestionBlock

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shifted colored badges from dark-mode-only palette (text-COLOR-400 on
bg-COLOR-950/30) to universal mid-range palette (text-COLOR-600 on
bg-COLOR-500/15). The -600 text shades have good contrast on both light
and dark backgrounds, and -500/15 backgrounds create a visible tint
on any surface.

Affected: CronPage, SourcesPage, SkillDetailPage, DiagnosticsPage,
GitHubRenderer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changed from bg-surface (white) to bg-bg (page background) so the
sidebar blends with the page rather than standing out as bright white.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Line backgrounds: -950/25 → -500/15 (visible tint on both themes)
- Text: -300/90 → -600 (readable on both light and dark backgrounds)
- Gutters: -950/15 → -500/10, borders -900/30 → -500/20
- Hunk header: hardcoded dark indigo → semi-transparent #6366f1/10

Same fix applied to EditToolBlock inline diffs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These are local planning artifacts, not intended for upstream.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@pufit pufit left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, appreciate the work!

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.

2 participants