Skip to content

feat: Customize TUI with brand colors and refined visual design#139

Closed
Icarus603 wants to merge 2 commits intoclaude-code-best:mainfrom
Icarus603:main
Closed

feat: Customize TUI with brand colors and refined visual design#139
Icarus603 wants to merge 2 commits intoclaude-code-best:mainfrom
Icarus603:main

Conversation

@Icarus603
Copy link
Copy Markdown

@Icarus603 Icarus603 commented Apr 5, 2026

Summary

Comprehensive TUI theme and UI refinements with a cohesive brand color palette.

Theme Colors

  • Replace Claude orange brand color with blue (rgb(88,190,255))
  • Add BRAND_COLOR, BRAND_COLOR_LIGHT, BRAND_RED, BRAND_GREEN constants
  • Update all 6 theme variants (light, dark, ansi, daltonized) with consistent palette
  • Change permission/suggestion/remember colors to cyan-blue (rgb(131,210,238))
  • Set dark theme userMessageBackground to #0f0f0f for better contrast
  • Update diff colors: burgundy red (rgb(162,0,67)) and forest green

Syntax Highlighting

  • Add new Royal Gold Dark theme with gold/blue palette (lower saturation)
  • Replace Monokai Extended as default dark syntax theme

UI Behavior

  • Remove spinner stalled-to-red warning for cleaner UX
  • Remove syntax highlighting toggle (Ctrl+T) from ThemePicker
  • Remove top padding from FullscreenLayout
  • Set inline code color to amber gold (#FEC84A) in dark themes

Keybindings

  • Remove theme:toggleSyntaxHighlighting action
  • Remove Ctrl+T binding from ThemePicker context

Test Plan

  • Verify theme colors render correctly in light/dark modes
  • Verify syntax highlighting uses Royal Gold Dark for dark themes
  • Verify spinner no longer turns red when stalled
  • Verify ThemePicker no longer responds to Ctrl+T

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Dark theme now defaults to "Royal Gold Dark"
    • Buddy command expanded: rehatch, mute, unmute; companion view now text-based
  • Bug Fixes

    • Syntax highlighting is consistently enabled
  • Chores

    • Removed theme toggle shortcut (Ctrl+T) and related toggle UI
  • Style

    • Refreshed diff highlight and brand colors across themes
    • Adjusted fullscreen spacing
    • Simplified spinner visuals (no stalled-red interpolation)
    • Clarified theme availability/status messaging

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 5, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fa75790e-040b-4113-8744-78b92a5bab8c

📥 Commits

Reviewing files that changed from the base of the PR and between 592c00e and 3214e58.

📒 Files selected for processing (14)
  • build.ts
  • packages/color-diff-napi/src/index.ts
  • src/commands/buddy/buddy.ts
  • src/commands/buddy/index.ts
  • src/components/FullscreenLayout.tsx
  • src/components/HighlightedCode.tsx
  • src/components/Spinner/GlimmerMessage.tsx
  • src/components/Spinner/SpinnerAnimationRow.tsx
  • src/components/Spinner/SpinnerGlyph.tsx
  • src/components/ThemePicker.tsx
  • src/keybindings/defaultBindings.ts
  • src/keybindings/schema.ts
  • src/utils/markdown.ts
  • src/utils/theme.ts

📝 Walkthrough

Walkthrough

Consolidates brand color usage and updates diff/dark-theme palettes; removes syntax-highlight toggle and its keybinding; removes stalled-intensity logic from spinner components; fixes fullscreen scroll padding; adjusts inline code color selection; extends build features; and converts buddy command UI to text with added rehatch/mute/unmute subcommands.

Changes

Cohort / File(s) Summary
Theme & color-diff
src/utils/theme.ts, packages/color-diff-napi/src/index.ts
Added shared brand color constants and swapped many hardcoded RGBs to those constants. Dark theme default mapping changed to "Royal Gold Dark" (ROYAL_GOLD_DARK_SCOPES) and diff color constants (BRAND_DIFF_*) introduced and applied.
Syntax highlighting toggle & keybindings
src/components/HighlightedCode.tsx, src/components/ThemePicker.tsx, src/keybindings/defaultBindings.ts, src/keybindings/schema.ts
Removed settings-driven syntax highlighting toggle and its UI/shortcut. Deleted theme:toggleSyntaxHighlighting binding (ctrl+t) and removed the action from keybinding schema; HighlightedCode always attempts coloring.
Spinner stalled-intensity removal
src/components/Spinner/GlimmerMessage.tsx, src/components/Spinner/SpinnerAnimationRow.tsx, src/components/Spinner/SpinnerGlyph.tsx
Eliminated stalledIntensity-based color interpolation and error-fallback rendering; removed related conditional prop passing and theme/color lookups in spinner components.
Buddy command: text output & new subcommands
src/commands/buddy/buddy.ts, src/commands/buddy/index.ts
Replaced JSX/CompanionCard rendering with text/ASCII output, added renderStats, introduced /buddy rehatch, renamed `/buddy on
Layout & markdown tweaks
src/components/FullscreenLayout.tsx, src/utils/markdown.ts
Set ScrollBox paddingTop to constant 0 (removed state-based padding). For inline code (codespan), choose color key based on dark-theme detection instead of always using 'permission'.
Build feature flag
build.ts
Added BUDDY to DEFAULT_BUILD_FEATURES, so BUDDY is included by default unless filtered via env overrides.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

v6

Suggested reviewers

  • KonghaYao

Poem

🐇 I hopped through palettes, swapped gold for night,
Removed a toggle, let colors shine bright.
Spinners lost their crimson fret,
Buddies rehatch with text reset.
A tidy hop — brand hues alight ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective of the PR: introducing brand colors and refined visual design across the TUI, which is the central theme of all changes.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Comprehensive theme and UI refinements:

Theme Colors:
- Replace Claude orange brand color with blue (rgb(88,190,255))
- Add BRAND_COLOR, BRAND_COLOR_LIGHT, BRAND_RED, BRAND_GREEN constants
- Update all 6 theme variants (light, dark, light-ansi, dark-ansi,
  light-daltonized, dark-daltonized) with consistent brand palette
- Change permission/suggestion/remember colors to cyan-blue (rgb(131,210,238))
- Set dark theme userMessageBackground to #0f0f0f for better contrast
- Update diff colors: burgundy red (rgb(162,0,67)) and forest green

Syntax Highlighting:
- Add new Royal Gold Dark theme with gold/blue palette and lower saturation
- Replace Monokai Extended as default dark syntax theme
- Fine-tune scope colors for refined code appearance on black backgrounds

UI Behavior Changes:
- Remove spinner stalled-to-red warning animation for cleaner UX
- Remove syntax highlighting toggle (Ctrl+T) from ThemePicker
- Remove top padding from FullscreenLayout ScrollBox
- Set inline code color to amber gold (#FEC84A) in dark themes

Keybindings:
- Remove 'theme:toggleSyntaxHighlighting' action from schema
- Remove Ctrl+T binding from ThemePicker context

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/components/Spinner/SpinnerGlyph.tsx (1)

16-22: Remove unused stalledIntensity from Props to avoid stale API surface

stalledIntensity is still part of Props (Line 19) but is no longer read by SpinnerGlyph. Removing it will let TypeScript catch stale callers and keep the component contract accurate.

Suggested patch
 type Props = {
   frame: number
   messageColor: keyof Theme
-  stalledIntensity?: number
   reducedMotion?: boolean
   time?: number
 }

Also applies to: 24-29

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Spinner/SpinnerGlyph.tsx` around lines 16 - 22, Remove the
now-unused stalledIntensity property from the SpinnerGlyph component props type:
update the Props type declaration to omit stalledIntensity and remove any
related optional param in SpinnerGlyph references so callers with stale usage
will be surfaced by TypeScript; ensure you update any exported types or prop
spreads that reference Props so the component contract matches actual usage.
src/utils/markdown.ts (1)

90-92: Consider using a theme constant instead of a hardcoded hex value.

The hardcoded '#FEC84A' bypasses the theme system, making future customization harder. Since the theme file now defines brand constants like BRAND_COLOR and diff colors, adding an inlineCode theme key (or reusing an existing constant) would maintain consistency with the rest of the theming approach.

-      return color(theme?.startsWith('dark') ? '#FEC84A' : 'permission', theme)(
+      // Consider: add `inlineCode` to Theme type and theme definitions
+      return color(theme?.startsWith('dark') ? 'inlineCode' : 'permission', theme)(
         token.text,
       )

Alternatively, if the value must remain hardcoded for now, consider extracting it as a constant for discoverability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/markdown.ts` around lines 90 - 92, The return in markdown.ts
currently uses a hardcoded '#FEC84A' inside color(...) — replace that literal
with a theme-driven constant (e.g., use theme.inlineCode or theme.BRAND_COLOR /
a new INLINE_CODE_COLOR constant) so the inline code color follows the theme; if
the theme object lacks an inlineCode key add one in the theme definition and
reference it here (keep the same ternary logic: use theme?.startsWith('dark') ?
theme.inlineCodeDark : theme.inlineCodeLight or reuse BRAND_COLOR as
appropriate), or extract the hex into a named constant (INLINE_CODE_COLOR) and
reference that instead for discoverability.
packages/color-diff-napi/src/index.ts (1)

369-371: Redundant ternary — both branches evaluate to the same value.

The tc (truecolor) conditional serves no purpose here since both branches return the identical constant. This appears to be a copy-paste artifact from a pattern where truecolor and 256-color modes had different values.

-      addLine: tc ? BRAND_DIFF_GREEN_DARK_LINE : BRAND_DIFF_GREEN_DARK_LINE,
-      addWord: tc ? BRAND_DIFF_GREEN_DARK_WORD : BRAND_DIFF_GREEN_DARK_WORD,
+      addLine: BRAND_DIFF_GREEN_DARK_LINE,
+      addWord: BRAND_DIFF_GREEN_DARK_WORD,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/color-diff-napi/src/index.ts` around lines 369 - 371, The ternary
condition using tc is redundant for addLine and addWord because both branches
return the same constants; update the object initializer (the properties addLine
and addWord) to use the constants directly (BRAND_DIFF_GREEN_DARK_LINE and
BRAND_DIFF_GREEN_DARK_WORD) instead of the tc ? ... : ... expressions, leaving
addDecoration as-is (BRAND_DIFF_GREEN); if the original intent was different
color values for truecolor vs 256-color modes, replace the identical branches
with the correct constants instead of removing the conditional.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/Spinner/SpinnerGlyph.tsx`:
- Around line 2-4: The imports in SpinnerGlyph.tsx use relative paths; change
them to the repo's src/* TypeScript path aliases. Replace import of Box and Text
from '../../ink.js' with import from 'src/ink.js', replace Theme import from
'../../utils/theme.js' with 'src/utils/theme.js', and replace
getDefaultCharacters from './utils.js' with 'src/components/Spinner/utils.js'
(retain the same named imports Box, Text, Theme, getDefaultCharacters and update
only the module specifiers).

In `@src/utils/theme.ts`:
- Line 343: darkAnsiTheme.briefLabelClaude is currently set to BRAND_COLOR but
needs an ANSI color value like the lightAnsiTheme counterpart; update the
darkAnsiTheme object so briefLabelClaude uses the correct ANSI color
constant/string (matching the pattern used for lightAnsiTheme.briefLabelClaude)
— locate the darkAnsiTheme definition and replace BRAND_COLOR with the
appropriate ANSI color value or constant used elsewhere in the file.
- Line 262: lightAnsiTheme.briefLabelClaude (and the corresponding
darkAnsiTheme.briefLabelClaude) currently reference BRAND_COLOR
('rgb(88,190,255)'), which breaks ANSI-only themes; change both properties to an
ANSI color string (e.g., 'ansi:cyan' or another appropriate 'ansi:*' value)
instead of the RGB constant so the themes remain ANSI-compatible and render
correctly on limited-color terminals.

---

Nitpick comments:
In `@packages/color-diff-napi/src/index.ts`:
- Around line 369-371: The ternary condition using tc is redundant for addLine
and addWord because both branches return the same constants; update the object
initializer (the properties addLine and addWord) to use the constants directly
(BRAND_DIFF_GREEN_DARK_LINE and BRAND_DIFF_GREEN_DARK_WORD) instead of the tc ?
... : ... expressions, leaving addDecoration as-is (BRAND_DIFF_GREEN); if the
original intent was different color values for truecolor vs 256-color modes,
replace the identical branches with the correct constants instead of removing
the conditional.

In `@src/components/Spinner/SpinnerGlyph.tsx`:
- Around line 16-22: Remove the now-unused stalledIntensity property from the
SpinnerGlyph component props type: update the Props type declaration to omit
stalledIntensity and remove any related optional param in SpinnerGlyph
references so callers with stale usage will be surfaced by TypeScript; ensure
you update any exported types or prop spreads that reference Props so the
component contract matches actual usage.

In `@src/utils/markdown.ts`:
- Around line 90-92: The return in markdown.ts currently uses a hardcoded
'#FEC84A' inside color(...) — replace that literal with a theme-driven constant
(e.g., use theme.inlineCode or theme.BRAND_COLOR / a new INLINE_CODE_COLOR
constant) so the inline code color follows the theme; if the theme object lacks
an inlineCode key add one in the theme definition and reference it here (keep
the same ternary logic: use theme?.startsWith('dark') ? theme.inlineCodeDark :
theme.inlineCodeLight or reuse BRAND_COLOR as appropriate), or extract the hex
into a named constant (INLINE_CODE_COLOR) and reference that instead for
discoverability.
🪄 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: cbbdb3fa-2aab-4f94-8d61-b493dd87efd6

📥 Commits

Reviewing files that changed from the base of the PR and between ba97889 and 592c00e.

📒 Files selected for processing (11)
  • packages/color-diff-napi/src/index.ts
  • src/components/FullscreenLayout.tsx
  • src/components/HighlightedCode.tsx
  • src/components/Spinner/GlimmerMessage.tsx
  • src/components/Spinner/SpinnerAnimationRow.tsx
  • src/components/Spinner/SpinnerGlyph.tsx
  • src/components/ThemePicker.tsx
  • src/keybindings/defaultBindings.ts
  • src/keybindings/schema.ts
  • src/utils/markdown.ts
  • src/utils/theme.ts
💤 Files with no reviewable changes (4)
  • src/keybindings/defaultBindings.ts
  • src/components/Spinner/SpinnerAnimationRow.tsx
  • src/components/Spinner/GlimmerMessage.tsx
  • src/keybindings/schema.ts

Comment on lines +2 to +4
import { Box, Text } from '../../ink.js'
import type { Theme } from '../../utils/theme.js'
import { getDefaultCharacters } from './utils.js'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use src/* path alias imports instead of relative paths

Lines 2-4 use relative imports, which violates the repo import convention for TypeScript files. Please switch these to src/* aliases.

Suggested patch
-import { Box, Text } from '../../ink.js'
-import type { Theme } from '../../utils/theme.js'
-import { getDefaultCharacters } from './utils.js'
+import { Box, Text } from 'src/ink.js'
+import type { Theme } from 'src/utils/theme.js'
+import { getDefaultCharacters } from 'src/components/Spinner/utils.js'

As per coding guidelines, "Use src/* path alias for imports in TypeScript files (e.g., import { ... } from 'src/utils/...')."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { Box, Text } from '../../ink.js'
import type { Theme } from '../../utils/theme.js'
import { getDefaultCharacters } from './utils.js'
import { Box, Text } from 'src/ink.js'
import type { Theme } from 'src/utils/theme.js'
import { getDefaultCharacters } from 'src/components/Spinner/utils.js'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Spinner/SpinnerGlyph.tsx` around lines 2 - 4, The imports in
SpinnerGlyph.tsx use relative paths; change them to the repo's src/* TypeScript
path aliases. Replace import of Box and Text from '../../ink.js' with import
from 'src/ink.js', replace Theme import from '../../utils/theme.js' with
'src/utils/theme.js', and replace getDefaultCharacters from './utils.js' with
'src/components/Spinner/utils.js' (retain the same named imports Box, Text,
Theme, getDefaultCharacters and update only the module specifiers).

Comment thread src/utils/theme.ts
fastModeShimmer: 'ansi:redBright',
briefLabelYou: 'ansi:blue',
briefLabelClaude: 'ansi:redBright',
briefLabelClaude: BRAND_COLOR,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

ANSI theme uses RGB value, breaking ANSI-only constraint.

lightAnsiTheme.briefLabelClaude is set to BRAND_COLOR which is 'rgb(88,190,255)'. ANSI themes are designed for terminals without true color support, where all values should use 'ansi:*' format. This RGB value won't render correctly on limited-color terminals.

-  briefLabelClaude: BRAND_COLOR,
+  briefLabelClaude: 'ansi:cyanBright', // or another appropriate ANSI color

The same issue exists in darkAnsiTheme at line 343.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/theme.ts` at line 262, lightAnsiTheme.briefLabelClaude (and the
corresponding darkAnsiTheme.briefLabelClaude) currently reference BRAND_COLOR
('rgb(88,190,255)'), which breaks ANSI-only themes; change both properties to an
ANSI color string (e.g., 'ansi:cyan' or another appropriate 'ansi:*' value)
instead of the RGB constant so the themes remain ANSI-compatible and render
correctly on limited-color terminals.

Comment thread src/utils/theme.ts
Add complete text-based buddy commands:
- /buddy pet - Trigger heart animation + companion reaction
- /buddy rehatch - Re-roll a new companion with stats
- /buddy mute - Hide companion
- /buddy unmute - Show companion

Features:
- 20-char stat bars (████████░░) for DEBUGGING, PATIENCE, CHAOS, WISDOM, SNARK
- Auto-hatch on first /buddy call (no need for explicit hatch)
- Display sprite, rarity, eye, hat, personality in text format
- Show available commands after companion info

Also enable BUDDY feature in production builds by default.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Icarus603 Icarus603 closed this Apr 5, 2026
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