feat(web): add modular theme library - #5226
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
e0f79e4 to
607dd6b
Compare
ApprovabilityVerdict: Needs human review Diff is too large for automated approval analysis. A human reviewer should evaluate this PR. You can customize Macroscope's approvability policy. Learn more. |
|
I did not have time to go through this PR thoroughly. But the general direction taken is exactly what I had in mind when I started #418. From what I see, it should be easy to create a custom theme based on the tokens created. |
Adds semantic theme roles, persisted light and dark variants, personal theme import and creation, contrast-safe surfaces, and themed message actions. Includes the T3 Chat palette, follow-system behavior, splash handling, and the theme library UI.
The edit-and-merge path persisted the merged palette before removing the edited theme. A transient storage failure on that removal left the target holding the edited palette while the original still existed, so every retry collided. The target is restored to its pre-merge palettes before the failure surfaces. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e-system # Conflicts: # apps/web/src/components/ChatView.tsx # apps/web/src/components/SidebarV2.tsx # apps/web/src/components/chat/ChatComposer.tsx # apps/web/src/components/chat/MessagesTimeline.tsx
Restoring defaults re-reads the theme and the mix after the confirmation dialog closes, because either can change while it is open. The appearance mode was still taken from the render-time value, so a flip to light or dark during the dialog left the reset skipped and reported as complete while the non-system mode stayed in storage. The reader that already backs this value is exported and named like its siblings, and the dirty check now calls it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e-system # Conflicts: # apps/web/src/components/settings/SettingsPanels.tsx
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit c580679. Configure here.
| lastAppliedTheme = null; | ||
| applyTheme(getStored(), true); | ||
| emitChange(); | ||
| } |
There was a problem hiding this comment.
Editor draft clobbered live
Medium Severity
handleSystemAppearanceChange and handleStorageChange always call applyTheme, which replaces the live CSS variables with the stored palette. While ThemeEditorPanel is open, that overwrites the draft preview, and the editor only re-applies when its own draft state changes, so an OS theme flip or cross-tab storage event can erase the in-progress colors from the UI.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit c580679. Configure here.


Summary
Adds a token-based theme system to the web client and desktop app: 57 semantic color roles, applied before React mounts so there is no flash of the wrong theme.
color()values, and pairs a family's light and dark files into one dual-mode theme. Re-importing an installed theme asks whether to update it or keep both.Closes #418
Closes #233
Closes #4302
Supersedes #5258
Screenshots
Both shots show the same mix — T3 Chat in light, Grove in dark — from either side of the System toggle.
The editor floats above the app and paints its draft on the live interface, so a color is judged by browsing the app rather than a miniature; it drags anywhere and survives navigation. Advanced mode lists one role per row behind a filter.
Built with GPT-5.6-Luna and Claude Fable 5 in T3 Code.
Note
Medium Risk
Large UI and boot-time localStorage theming surface with many touchpoints; failures generally degrade to fallbacks rather than affecting auth or data, but bad stored theme shapes or boot/runtime drift could cause flash or inconsistent colors on load.
Overview
Introduces a modular theme system that replaces the simple system/light/dark dropdown with a ThemeLibrary in appearance settings: built-in palettes, per-appearance theme halves (mix light and dark from different themes), custom themes in storage, and restore-defaults logic that resets theme preference, follow-system mode, and mix independently.
A floating theme editor (
ThemeEditorHost/ThemeEditorPanel,ThemeColorPicker) applies drafts on the live app; it opens frommod+alt+shift+tand a new command-palette action. Desktop gainspickThemeFilesIPC (multi JSON picker, defaulting to~/.vscode/extensions, 256 KB read cap) wired through preload.index.htmlboot script is expanded to mirror runtime theme resolution—custom themes, legacy IDs, halves, and splash CSS variables—so the first paint matches the selected palette before React mounts.Across the web UI, styling shifts from ad-hoc
muted-foregroundopacity classes to semantic tokens (secondary-label,icon-muted,placeholder,message/message-action,error/warning/update,--code-backgroundfor diffs). Diffs, terminals, font previews, and composer primary actions are updated to follow those tokens; stage artwork is removed from the send button in favor ofmessage-actioncolors.Smaller fixes bundled in the same pass: workspace titlebar control inset so toggling the right panel does not jump controls, and sidebar header z-index so stage backdrop does not bleed over search outlines.
Reviewed by Cursor Bugbot for commit 71db00e. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add modular theme library with editor, import, and per-appearance theme halves support
themePalette.tsas the core theme module, defining built-in themes (T3 Chat, Grove, Ocean, Ember, Iris), storage keys, color role types, and custom theme CRUD with subscriptions.ThemeEditorPanel.tsx,ThemeEditorHost.tsx) supporting live preview, managed/advanced color editing, and save/update/remove of custom themes; toggled viamod+alt+shift+t.ThemeImportDialog.tsx) with drag-and-drop, syntax-highlighted JSON editor, 256 KB file size guard, and collision resolution; also supports importing VS Code color themes viavscodeThemeImport.ts.ThemeLibraryUI for browsing, activating, mixing light/dark halves, editing, duplicating, exporting, and deleting themes.useThemeto exposeappearanceMode,followSystem, andthemeHalves, and updates boot-time theming inindex.htmlto resolve custom/built-in themes and mixed halves before app mount.pickThemeFilesIPC channel on desktop that opens a multi-file JSON picker defaulting to the VS Code extensions directory.muted-foregroundtokens to semantic tokens (secondary-label,icon-muted,placeholder,message-action,error,warning,update).index.htmlis substantially more complex and reads multiple localStorage keys; failures fall back gracefully but the script is harder to audit.Macroscope summarized 71db00e.