Skip to content

Refactor web UI colors to shared theme tokens#21

Merged
Jay1 merged 4 commits into
mainfrom
jcode/improve-theme-color-penetration
May 31, 2026
Merged

Refactor web UI colors to shared theme tokens#21
Jay1 merged 4 commits into
mainfrom
jcode/improve-theme-color-penetration

Conversation

@Jay1

@Jay1 Jay1 commented May 31, 2026

Copy link
Copy Markdown
Owner

Summary

  • Migrates hardcoded component color classes to shared var(--app-*) theme tokens across web UI (sidebar, diff panel, plugin glyphs, terminal, chat, and PR/status visuals).
  • Introduces additional semantic token families for status, agent chips, search highlights, scrollbar, scroll buttons, plugin glyphs, wordmark, and terminal/search subagent accents.
  • Updates theme generation in apps/web/src/theme/theme.logic.ts to emit the new token set with resolved palette-driven values.
  • Expands theme token coverage tests in apps/web/src/theme/theme.logic.test.ts and updates existing component tests to validate token usage.
  • Removes random per-name plugin/skill hue derivation and standardizes those glyphs to tokenized gradients/borders.

Testing

  • Not run (no test commands executed in this PR write-up).
  • Not run: full web typecheck/build.
  • Not run: browser/visual regression checks.

Summary by CodeRabbit

Release Notes

  • Style
    • Implemented a themeable color system using CSS variables across status indicators, search highlights, sidebar elements, terminals, and UI components for improved visual consistency and easier theme customization.
    • Refactored color styling for buttons, badges, agent chips, and other interface elements to use centralized theme tokens.

- Replace hard-coded status, wordmark, chip, glyph, and terminal colors with semantic CSS variables in web components
- Add new app-level design tokens in `index.css` and compute them in `theme.logic.ts`
- Update theme tests to assert presence and values for newly introduced app tokens
- Keep behavior unchanged while improving theme penetration and consistency across light/dark themes
@coderabbitai

coderabbitai Bot commented May 31, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Jay1, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 26 minutes and 47 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c814eb49-46b6-4f8d-9414-2d40dd0646f5

📥 Commits

Reviewing files that changed from the base of the PR and between b37db68 and 94d2cdc.

📒 Files selected for processing (8)
  • README.md
  • apps/web/src/components/Sidebar.tsx
  • apps/web/src/components/SidebarHeaderNavigationControls.tsx
  • apps/web/src/components/TerminalSearch.tsx
  • apps/web/src/components/chat/MessagesTimeline.tsx
  • apps/web/src/components/terminal/terminalColorResolution.ts
  • apps/web/src/components/terminal/terminalRuntimeAppearance.ts
  • apps/web/src/theme/theme.logic.ts
📝 Walkthrough

Walkthrough

This PR consolidates hardcoded colors across the web application into a comprehensive CSS custom property system. The changes establish theme-driven variables for status indicators, UI components, and agent/subagent colors, refactor theme generation to use helper builders, and update all affected components plus tests to reference these variables.

Changes

Theme Variables & Component Styling Consolidation

Layer / File(s) Summary
CSS Custom Properties Foundation
apps/web/src/index.css, apps/web/src/theme/theme.logic.test.ts
Root :root scope adds --app-status-*, --app-scroll-button-*, --app-scrollbar-thumb*, --app-terminal-search-*, --app-wordmark-prefix, --app-agent-chip-*, and --app-subagent-accent-* CSS variables with light/dark theme values. Tests expanded to validate all required tokens are present across themes.
Theme CSS Variable Generation Helpers
apps/web/src/theme/theme.logic.ts
Introduces APP_STATUS_TOKEN_KINDS enum and helper functions (buildStatusVariables, buildAgentChipVariables, buildSubagentAccentVariables) that centralize CSS variable computation for both Catppuccin-specific and profile-based theme depth paths. Intermediate computed colors (activeSearchBackground, mutedAccent) are added to derived token logic.
Status Pill & Project Status Indicators
apps/web/src/components/Sidebar.logic.ts, apps/web/src/components/Sidebar.logic.test.ts
resolveThreadStatusPill switches all status labels (Pending Approval, Awaiting Input, Working, Connecting, Plan Ready, Completed) to use --app-status-*-fg and --app-status-*-dot CSS variable classes. Project status indicator tests updated to assert CSS variable–based classes.
PR Dialog & Status Badges
apps/web/src/components/PullRequestThreadDialog.tsx, apps/web/src/components/Sidebar.tsx, apps/web/src/components/Sidebar.structure.test.ts
PR dialog statusTone styling uses --app-status-plan-fg (merged) and --app-status-success-fg (open). Sidebar status badges and terminal indicators switch from hardcoded Tailwind colors to CSS variable equivalents. Wordmark prefix assertion updated to expect CSS variable styling.
Terminal Activity & Status Dots
apps/web/src/components/terminal/TerminalActivityIndicator.tsx, apps/web/src/components/TerminalWorkspaceTabs.tsx, apps/web/src/components/terminal/terminalRuntimeAppearance.ts
Activity indicator attention/review dots and workspace terminal status dots use --app-status-warning-dot/--app-status-success-dot instead of hardcoded colors. xterm scrollbar scrollbarSliderBackground now references --app-scrollbar-thumb.
Scroll & Search Component Styling
apps/web/src/components/TerminalScrollToBottom.tsx, apps/web/src/components/chat/ChatTranscriptPane.tsx, apps/web/src/components/TerminalSearch.tsx
Scroll-to-bottom buttons in terminal and chat use --app-scroll-button-* tokens for border/background/foreground and hover states. Terminal search match decorations (background, border, overview ruler) now use --app-terminal-search-* CSS variables.
Agent Chip & Subagent Color Styling
apps/web/src/components/chat/MessagesTimeline.tsx, apps/web/src/components/composer-nodes/index.tsx, apps/web/src/lib/subagentPresentation.ts
Agent chip colors (default and named variants) and subagent status badges switch to CSS variable–based --app-agent-chip-* and --app-status-* tokens. Subagent accent palette references --app-subagent-accent-0 through --app-subagent-accent-7, and status dot colors use --app-status-working-dot or --app-status-muted-dot.
Plugin Glyphs & Layout Elements
apps/web/src/components/PluginLibrary.tsx, apps/web/src/components/DiffPanel.tsx, apps/web/src/components/Sidebar.tsx, apps/web/src/components/SidebarHeaderNavigationControls.tsx
Plugin and skill glyphs use --app-plugin-glyph-gradient-* and --app-plugin-glyph-border instead of name-derived HSL. Diff panel title uses --app-diff-title. Wordmark prefix renders literal $$$ and uses --app-wordmark-prefix CSS variable for color.

🎯 4 (Complex) | ⏱️ ~60 minutes

vouch:trusted, size:XXL

🐰 With whiskers twitched and colors bright,
CSS variables now reign in light,
No hardcodes left to break the spell,
Just custom props that work so well!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Refactor web UI colors to shared theme tokens' accurately and concisely describes the main objective of the changeset—migrating hardcoded colors to CSS theme variables across the web UI.
Description check ✅ Passed The PR description includes a clear Summary and Testing section, adequately documenting the changes and acknowledging that specific test execution was not performed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jcode/improve-theme-color-penetration

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added size:L vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels May 31, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/theme/theme.logic.ts (1)

1-1: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix formatting issues before merge.

The pipeline reports formatting violations. Please run the formatter to resolve:

# Run the formatter to fix issues
npm run fmt
# or if using a different command:
pnpm fmt
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/theme/theme.logic.ts` at line 1, Run the project's formatter on
the changed file (apps/web/src/theme/theme.logic.ts) to resolve the pipeline
formatting violations; execute the project's formatting script (e.g., npm run
fmt or pnpm fmt) and re-stage the formatted file so the PR contains the
formatted version before merging.
🧹 Nitpick comments (4)
apps/web/src/components/PullRequestThreadDialog.tsx (1)

110-121: ⚡ Quick win

Consider swapping the status token mapping for PR states.

The current semantic mapping may be confusing:

  • "merged" → --app-status-plan-fg (info/violet color for planning)
  • "open" → --app-status-success-fg (green color for success)

Typically:

  • Merged PRs represent successful completion and would fit --app-status-success-*
  • Open PRs are in-progress and would fit --app-status-working-* or --app-status-plan-*

The current mapping shows open PRs in green (success color) even though they're incomplete, and merged PRs in violet/info (planning color) even though they're successfully complete.

💡 Suggested semantic token swap
   const statusTone = useMemo(() => {
     switch (resolvedPullRequest?.state) {
       case "merged":
-        return "text-[var(--app-status-plan-fg)]";
+        return "text-[var(--app-status-success-fg)]";
       case "closed":
         return "text-zinc-500 dark:text-zinc-400/80";
       case "open":
-        return "text-[var(--app-status-success-fg)]";
+        return "text-[var(--app-status-working-fg)]";
       default:
         return "text-muted-foreground";
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/PullRequestThreadDialog.tsx` around lines 110 - 121,
The statusTone mapping in the useMemo (variable statusTone, using
resolvedPullRequest?.state) uses semantically inverted tokens for "merged" and
"open"; update the switch so "merged" returns the success token
(--app-status-success-fg) and "open" returns the working/plan token
(--app-status-plan-fg or a working token if available), keeping "closed" and
default unchanged; ensure the dependency remains [resolvedPullRequest?.state] so
the tone updates correctly when state changes.
apps/web/src/components/Sidebar.tsx (2)

813-816: ⚡ Quick win

Keep the wordmark prefix sourced from branding constants

Line 815 hardcodes $$$ while aria-label still uses APP_WORDMARK_PREFIX. This can drift from configured branding and unintentionally alter the header text.

💡 Proposed fix
 function AppWordmarkPrefix() {
   return (
-    <span aria-label={APP_WORDMARK_PREFIX} className="shrink-0 text-[18px] font-semibold text-[var(--app-wordmark-prefix)]">$$$</span>
+    <span
+      aria-label={APP_WORDMARK_PREFIX}
+      className="shrink-0 text-[18px] font-semibold text-[var(--app-wordmark-prefix)]"
+    >
+      {APP_WORDMARK_PREFIX}
+    </span>
   );
 }

As per coding guidelines, apps/web/src/**/*.tsx: For UI changes in apps/web, preserve current visual language unless explicitly asked to redesign.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/Sidebar.tsx` around lines 813 - 816, The span in
AppWordmarkPrefix currently renders a hardcoded "$$$" while aria-label uses
APP_WORDMARK_PREFIX; replace the hardcoded visible text with the branding
constant so the displayed wordmark matches the aria-label and branding config
(update AppWordmarkPrefix to render APP_WORDMARK_PREFIX inside the span, keeping
the existing aria-label and className intact).

5633-5642: ⚡ Quick win

Tokenize the remaining workspace terminal status dots

This branch still mixes hardcoded amber/teal with tokenized success color. Using status dot tokens for all states keeps theme behavior consistent.

🎨 Proposed fix
                                     {workspace.terminalStatus && (
                                       <span
                                         className={cn(
                                           "inline-flex size-1.5 shrink-0 rounded-full",
                                           workspace.terminalStatus.label === "Terminal input needed"
-                                            ? "bg-amber-500 dark:bg-amber-300/90"
+                                            ? "bg-[var(--app-status-warning-dot)]"
                                             : workspace.terminalStatus.label ===
                                                 "Terminal process running"
-                                              ? "bg-teal-500 dark:bg-teal-300/90"
+                                              ? "bg-[var(--app-status-input-dot)]"
                                               : "bg-[var(--app-status-success-dot)]",
                                         )}
                                       />
                                     )}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/Sidebar.tsx` around lines 5633 - 5642, The span
rendering the workspace terminal status dot currently mixes hardcoded colors
with a tokenized success color; update the conditional inside the className (the
span that checks workspace.terminalStatus.label in Sidebar.tsx) to use CSS
tokens for all states instead of hardcoded amber/teal (e.g., replace
"bg-amber-500 dark:bg-amber-300/90" and "bg-teal-500 dark:bg-teal-300/90" with
tokenized classes like "bg-[var(--app-status-warning-dot)]" and
"bg-[var(--app-status-running-dot)]" or your project's equivalent token names),
keeping the same conditional branches and dark variants so theme behavior
remains consistent.
apps/web/src/components/TerminalScrollToBottom.tsx (1)

60-60: 💤 Low value

Consider consistent type-hint syntax for CSS variable arbitrary values.

The className mixes two styles:

  • border-[color:var(--app-scroll-button-border)] (with explicit color: type hint)
  • bg-[var(--app-scroll-button-bg)] (without type hint)

Both are valid in Tailwind v4, but for consistency and clarity you could add the type hint to all color-related arbitrary values or remove it from all. For example:

className="... border-[color:var(--app-scroll-button-border)] bg-[color:var(--app-scroll-button-bg)] text-[color:var(--app-scroll-button-fg)] ... hover:bg-[color:var(--app-scroll-button-hover-bg)] hover:text-[color:var(--app-scroll-button-hover-fg)]"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/TerminalScrollToBottom.tsx` at line 60, The Tailwind
class string in the TerminalScrollToBottom component mixes arbitrary-value type
hints (e.g., border-[color:var(--app-scroll-button-border)]) with unhinted
values (e.g., bg-[var(--app-scroll-button-bg)]); update the className on the
TerminalScrollToBottom component to use a consistent pattern for color arbitrary
values (either add the color: type hint to bg-, text-, and hover- variants or
remove the color: hint from the border- variant) so all color-related arbitrary
values follow the same syntax.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/components/terminal/terminalRuntimeAppearance.ts`:
- Line 52: The theme currently sets scrollbarSliderBackground to the CSS
variable string "var(--app-scrollbar-thumb)"; xterm v6 expects a concrete color
string. Change the code that builds the theme in
apps/web/src/components/terminal/terminalRuntimeAppearance.ts to resolve the CSS
custom property to a computed value (e.g. use
getComputedStyle(document.documentElement).getPropertyValue('--app-scrollbar-thumb')
with trim() and a sensible fallback like "`#000000`" or existing theme color) and
assign that resolved value to scrollbarSliderBackground (update both occurrences
referenced by the symbol scrollbarSliderBackground); ensure the resolution runs
in a browser context before creating the ITheme object so xterm receives a real
color string.

In `@apps/web/src/components/TerminalSearch.tsx`:
- Around line 13-18: SEARCH_DECORATIONS currently holds CSS var strings which
`@xterm/addon-search` v0.16 won't resolve; change it from a static constant to a
function or regenerated object that reads computed styles (e.g. via
getComputedStyle on the terminal container or documentElement) to resolve
--app-terminal-search-* to concrete color strings (like `#RRGGBB`) and use that
concrete decorations object when calling findNext/findPrevious; also subscribe
to theme/style changes (or recompute before each search) so the resolved colors
are refreshed when the theme updates. Ensure you update references to
SEARCH_DECORATIONS in TerminalSearch.tsx (where findNext/findPrevious are
invoked) to call the new resolver and pass the computed decoration object
instead of the raw CSS variable strings.

---

Outside diff comments:
In `@apps/web/src/theme/theme.logic.ts`:
- Line 1: Run the project's formatter on the changed file
(apps/web/src/theme/theme.logic.ts) to resolve the pipeline formatting
violations; execute the project's formatting script (e.g., npm run fmt or pnpm
fmt) and re-stage the formatted file so the PR contains the formatted version
before merging.

---

Nitpick comments:
In `@apps/web/src/components/PullRequestThreadDialog.tsx`:
- Around line 110-121: The statusTone mapping in the useMemo (variable
statusTone, using resolvedPullRequest?.state) uses semantically inverted tokens
for "merged" and "open"; update the switch so "merged" returns the success token
(--app-status-success-fg) and "open" returns the working/plan token
(--app-status-plan-fg or a working token if available), keeping "closed" and
default unchanged; ensure the dependency remains [resolvedPullRequest?.state] so
the tone updates correctly when state changes.

In `@apps/web/src/components/Sidebar.tsx`:
- Around line 813-816: The span in AppWordmarkPrefix currently renders a
hardcoded "$$$" while aria-label uses APP_WORDMARK_PREFIX; replace the hardcoded
visible text with the branding constant so the displayed wordmark matches the
aria-label and branding config (update AppWordmarkPrefix to render
APP_WORDMARK_PREFIX inside the span, keeping the existing aria-label and
className intact).
- Around line 5633-5642: The span rendering the workspace terminal status dot
currently mixes hardcoded colors with a tokenized success color; update the
conditional inside the className (the span that checks
workspace.terminalStatus.label in Sidebar.tsx) to use CSS tokens for all states
instead of hardcoded amber/teal (e.g., replace "bg-amber-500
dark:bg-amber-300/90" and "bg-teal-500 dark:bg-teal-300/90" with tokenized
classes like "bg-[var(--app-status-warning-dot)]" and
"bg-[var(--app-status-running-dot)]" or your project's equivalent token names),
keeping the same conditional branches and dark variants so theme behavior
remains consistent.

In `@apps/web/src/components/TerminalScrollToBottom.tsx`:
- Line 60: The Tailwind class string in the TerminalScrollToBottom component
mixes arbitrary-value type hints (e.g.,
border-[color:var(--app-scroll-button-border)]) with unhinted values (e.g.,
bg-[var(--app-scroll-button-bg)]); update the className on the
TerminalScrollToBottom component to use a consistent pattern for color arbitrary
values (either add the color: type hint to bg-, text-, and hover- variants or
remove the color: hint from the border- variant) so all color-related arbitrary
values follow the same syntax.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: abceeb3b-9584-4dd2-8499-6cbfd37492af

📥 Commits

Reviewing files that changed from the base of the PR and between 7286c8d and b37db68.

📒 Files selected for processing (20)
  • apps/web/src/components/DiffPanel.tsx
  • apps/web/src/components/PluginLibrary.tsx
  • apps/web/src/components/PullRequestThreadDialog.tsx
  • apps/web/src/components/Sidebar.logic.test.ts
  • apps/web/src/components/Sidebar.logic.ts
  • apps/web/src/components/Sidebar.structure.test.ts
  • apps/web/src/components/Sidebar.tsx
  • apps/web/src/components/SidebarHeaderNavigationControls.tsx
  • apps/web/src/components/TerminalScrollToBottom.tsx
  • apps/web/src/components/TerminalSearch.tsx
  • apps/web/src/components/TerminalWorkspaceTabs.tsx
  • apps/web/src/components/chat/ChatTranscriptPane.tsx
  • apps/web/src/components/chat/MessagesTimeline.tsx
  • apps/web/src/components/composer-nodes/index.tsx
  • apps/web/src/components/terminal/TerminalActivityIndicator.tsx
  • apps/web/src/components/terminal/terminalRuntimeAppearance.ts
  • apps/web/src/index.css
  • apps/web/src/lib/subagentPresentation.ts
  • apps/web/src/theme/theme.logic.test.ts
  • apps/web/src/theme/theme.logic.ts

Comment thread apps/web/src/components/terminal/terminalRuntimeAppearance.ts Outdated
Comment thread apps/web/src/components/TerminalSearch.tsx Outdated
@github-actions github-actions Bot added size:XL and removed size:L labels May 31, 2026
@Jay1 Jay1 merged commit e2f4775 into main May 31, 2026
8 checks passed
@Jay1 Jay1 deleted the jcode/improve-theme-color-penetration branch June 3, 2026 00:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant