Skip to content

[Fix] Centralize theme ownership and sync meta[theme-color] on switch#192

Merged
samzong merged 1 commit intomainfrom
fix/theme-color-meta
Mar 27, 2026
Merged

[Fix] Centralize theme ownership and sync meta[theme-color] on switch#192
samzong merged 1 commit intomainfrom
fix/theme-color-meta

Conversation

@samzong
Copy link
Copy Markdown
Collaborator

@samzong samzong commented Mar 27, 2026

Summary

Consolidate scattered theme state management (App.tsx local state + SettingsSheet DOM manipulation + duplicated constants) into a single useThemeInit hook that owns all theme side effects. Fixes stale <meta name="theme-color"> that never updated on theme switch.

Type of change

  • [Fix] bug fix
  • [Refactor] internal cleanup

Why is this needed?

  1. <meta name="theme-color"> was hardcoded to #1c1c1c (wrong value — --bg-tertiary, not --bg-primary) and never updated when the user switched themes. On mobile PWA, the status bar stayed dark regardless of theme.
  2. Theme state was split between React useState in App.tsx and Zustand store in SettingsSheet — completely disconnected. <Toaster> received stale theme.
  3. THEME_STORAGE_KEY was independently declared in two files.
  4. DOM manipulation (data-theme, localStorage) was scattered across App.tsx and SettingsSheet with no single owner.

What changed?

  • New useThemeInit hook — single owner for all theme side effects: applies data-theme, colorScheme, syncs meta[theme-color] by reading --bg-primary from computed CSS (no hardcoded color mapping), persists to localStorage, and listens for system preference changes
  • New lib/constants.ts — single definition of THEME_STORAGE_KEY
  • stores/index.ts — synchronous theme hydration from localStorage at store creation (eliminates FOUC)
  • App.tsx — removed ~30 lines of local theme state, resolveTheme(), applyTheme(), system preference listener; replaced with useThemeInit() call
  • SettingsSheet.tsxtoggleTheme reduced to setTheme(isDark ? 'light' : 'dark') — no DOM/localStorage manipulation
  • index.html — meta tag corrected from #1c1c1c to #000000

Architecture impact

  • Owning layer: renderer (PWA)
  • Cross-layer impact: none
  • Invariants touched from docs/architecture-invariants.md: none
  • Why those invariants remain protected: changes are entirely within the PWA renderer layer; no shared/core/main process changes

Linked issues

N/A

Validation

  • pnpm lint
  • pnpm test
  • pnpm check:ui-contract
  • pnpm check (full gate: lint + architecture + ui-contract + renderer-copy + i18n + dead-code + format + typecheck + test)
  • Manual smoke test

Commands, screenshots, or notes:

pnpm check — all passed (92 desktop tests, 59 pwa tests, 6 shared tests)

Screenshots or recordings

No visual change. The meta tag update is only observable via DOM inspector or on mobile PWA status bar.

Release note

  • User-facing change. Release note is included below.
Fixed PWA status bar color not updating when switching between dark and light themes.

Checklist

  • The PR title uses at least one approved prefix: [Fix]
  • The summary explains both what changed and why
  • Validation reflects the commands actually run for this PR
  • Architecture impact is described and references any touched invariants
  • Cross-layer changes are explicitly justified
  • The release note block is accurate

@github-actions
Copy link
Copy Markdown
Contributor

Hi @samzong,
Thanks for your pull request!
If the PR is ready, use the /auto-cc command to assign Reviewer to Review.
We will review it shortly.

Details

Instructions for interacting with me using comments are available here.
If you have questions or suggestions related to my behavior, please file an issue against the gh-ci-bot repository.

@samzong samzong merged commit 09a2ec1 into main Mar 27, 2026
7 checks passed
@samzong samzong deleted the fix/theme-color-meta branch March 29, 2026 14:10
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