feat: add Claude theme (#2267)

* feat: add Claude theme — warm navy & coral palette

Add a new theme aligned with Claude Code's product surface colors:
deep navy surfaces (#181715), cream-tinted text (#faf9f5),
coral accent (#cc785c), and teal secondary (#5db8a6).
Includes cell-level remap pipeline registration and full
WCAG contrast QA compliance.

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

* fix(theme): address review feedback on Claude theme

- Fix text_dim contrast: #615E58 → #72706A (2.77 → 3.62, passes WCAG AA)
- Fix error_fg/error_border contrast: #C64545 → #E06060 (3.70 → 5.13, passes AA)
- Use amber #E8A55A for accent_action (distinct from accent_primary coral)
- Fix theme_picker test expecting GruvboxDark as last theme
- Remove broken include_str!("../../../web-chat/index.html") reference
  left by incomplete web-chat revert

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

* fix: revert version bump, keep theme-only changes

---------

Co-authored-by: Hu Qiantao <huqiantao@HudeMacBook-Air.local>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Hunter B <hmbown@gmail.com>
This commit is contained in:
HUQIANTAO
2026-05-31 16:18:33 +08:00
committed by GitHub
parent b0e39b8588
commit 3aa0a33fe2
2 changed files with 66 additions and 4 deletions
+61
View File
@@ -1094,6 +1094,58 @@ pub const GRUVBOX_DARK_UI_THEME: UiTheme = UiTheme {
tool_failed: Color::Rgb(0xfb, 0x49, 0x34), // red
};
pub const CLAUDE_UI_THEME: UiTheme = UiTheme {
name: "claude",
mode: PaletteMode::Dark,
// Claude Code product surfaces — dark navy with warm undertones
surface_bg: Color::Rgb(0x18, 0x17, 0x15), // surface-dark
panel_bg: Color::Rgb(0x25, 0x23, 0x20), // surface-dark-elevated
elevated_bg: Color::Rgb(0x1f, 0x1e, 0x1b), // surface-dark-soft (code blocks)
composer_bg: Color::Rgb(0x25, 0x23, 0x20),
selection_bg: Color::Rgb(0x30, 0x2d, 0x28),
header_bg: Color::Rgb(0x18, 0x17, 0x15),
footer_bg: Color::Rgb(0x18, 0x17, 0x15),
// Cream-tinted text hierarchy on dark
text_dim: Color::Rgb(0x72, 0x70, 0x6a),
text_hint: Color::Rgb(0x7d, 0x7a, 0x73),
text_muted: Color::Rgb(0xa0, 0x9d, 0x96), // on-dark-soft
text_body: Color::Rgb(0xfa, 0xf9, 0xf5), // on-dark (cream white)
text_soft: Color::Rgb(0xd0, 0xcd, 0xc5),
border: Color::Rgb(0x30, 0x2d, 0x28),
// Coral primary (signature Anthropic accent), teal secondary
accent_primary: Color::Rgb(0xcc, 0x78, 0x5c), // coral
accent_secondary: Color::Rgb(0x5d, 0xb8, 0xa6), // accent-teal
accent_action: Color::Rgb(0xe8, 0xa5, 0x5a), // amber
// Error / destructive — warm red
error_fg: Color::Rgb(0xe0, 0x60, 0x60),
error_hover: Color::Rgb(0xd9, 0x66, 0x66),
error_surface: Color::Rgb(0x2a, 0x1c, 0x1c),
error_border: Color::Rgb(0xe0, 0x60, 0x60),
error_text: Color::Rgb(0xe8, 0xb8, 0xb8),
// Status
warning: Color::Rgb(0xd4, 0xa0, 0x17), // amber
success: Color::Rgb(0x5d, 0xb8, 0x72), // green
info: Color::Rgb(0x5d, 0xb8, 0xa6), // teal
// Mode badges
mode_agent: Color::Rgb(0xcc, 0x78, 0x5c), // coral
mode_yolo: Color::Rgb(0xc6, 0x45, 0x45), // red
mode_plan: Color::Rgb(0xe8, 0xa5, 0x5a), // amber
mode_goal: Color::Rgb(0x5d, 0xb8, 0x72), // green
// Footer statusline
status_ready: Color::Rgb(0xa0, 0x9d, 0x96),
status_working: Color::Rgb(0x5d, 0xb8, 0xa6),
status_warning: Color::Rgb(0xd4, 0xa0, 0x17),
// Diff
diff_added_fg: Color::Rgb(0x5d, 0xb8, 0x72),
diff_deleted_fg: Color::Rgb(0xc6, 0x45, 0x45),
diff_added_bg: Color::Rgb(0x1a, 0x24, 0x1d),
diff_deleted_bg: Color::Rgb(0x24, 0x1a, 0x1a),
// Tool cells
tool_running: Color::Rgb(0x5d, 0xb8, 0xa6),
tool_success: Color::Rgb(0xa0, 0x9d, 0x96),
tool_failed: Color::Rgb(0xc6, 0x45, 0x45),
};
pub const MATRIX_UI_THEME: UiTheme = UiTheme {
name: "matrix",
mode: PaletteMode::Dark,
@@ -1211,6 +1263,7 @@ pub enum ThemeId {
TokyoNight,
Dracula,
GruvboxDark,
Claude,
Matrix,
SolarizedLight,
}
@@ -1231,6 +1284,7 @@ impl ThemeId {
"tokyo-night" => Some(Self::TokyoNight),
"dracula" => Some(Self::Dracula),
"gruvbox-dark" => Some(Self::GruvboxDark),
"claude" => Some(Self::Claude),
"matrix" => Some(Self::Matrix),
"solarized-light" => Some(Self::SolarizedLight),
_ => None,
@@ -1251,6 +1305,7 @@ impl ThemeId {
Self::TokyoNight => "tokyo-night",
Self::Dracula => "dracula",
Self::GruvboxDark => "gruvbox-dark",
Self::Claude => "claude",
Self::Matrix => "matrix",
Self::SolarizedLight => "solarized-light",
}
@@ -1269,6 +1324,7 @@ impl ThemeId {
Self::TokyoNight => "Tokyo Night",
Self::Dracula => "Dracula",
Self::GruvboxDark => "Gruvbox Dark",
Self::Claude => "Claude",
Self::Matrix => "Matrix",
Self::SolarizedLight => "Solarized Light",
}
@@ -1287,6 +1343,7 @@ impl ThemeId {
Self::TokyoNight => "Deep blue/violet night palette",
Self::Dracula => "Classic high-contrast purple",
Self::GruvboxDark => "Vintage warm earth tones",
Self::Claude => "Warm navy & coral",
Self::Matrix => "The Matrix films inspired theme",
Self::SolarizedLight => {
"Solarized light — Light, calming palette on warm ivory — easy on the eyes"
@@ -1310,6 +1367,7 @@ impl ThemeId {
Self::TokyoNight => TOKYO_NIGHT_UI_THEME,
Self::Dracula => DRACULA_UI_THEME,
Self::GruvboxDark => GRUVBOX_DARK_UI_THEME,
Self::Claude => CLAUDE_UI_THEME,
Self::Matrix => MATRIX_UI_THEME,
Self::SolarizedLight => SOLARIZED_LIGHT_UI_THEME,
}
@@ -1327,6 +1385,7 @@ pub const SELECTABLE_THEMES: &[ThemeId] = &[
ThemeId::TokyoNight,
ThemeId::Dracula,
ThemeId::GruvboxDark,
ThemeId::Claude,
ThemeId::Matrix,
ThemeId::SolarizedLight,
];
@@ -1374,6 +1433,7 @@ pub fn normalize_theme_name(value: &str) -> Option<&'static str> {
"tokyo-night" | "tokyonight" | "tokyo" => Some("tokyo-night"),
"dracula" => Some("dracula"),
"gruvbox-dark" | "gruvbox" => Some("gruvbox-dark"),
"claude" => Some("claude"),
"matrix" | "hacker" => Some("matrix"),
"solarized-light" | "solarized" => Some("solarized-light"),
_ => None,
@@ -1606,6 +1666,7 @@ pub const fn theme_remap_active(theme: ThemeId) -> bool {
| ThemeId::TokyoNight
| ThemeId::Dracula
| ThemeId::GruvboxDark
| ThemeId::Claude
| ThemeId::Matrix
| ThemeId::SolarizedLight
)
+5 -4
View File
@@ -11,10 +11,10 @@
#[cfg(test)]
mod tests {
use crate::palette::{
CATPPUCCIN_MOCHA_UI_THEME, DRACULA_UI_THEME, GRAYSCALE_UI_THEME, GRUVBOX_DARK_UI_THEME,
LIGHT_UI_THEME, TOKYO_NIGHT_UI_THEME, UI_THEME, UiTheme, WHALE_ACCENT_ACTION_RGB,
WHALE_ACCENT_PRIMARY_RGB, WHALE_ACCENT_SECONDARY_RGB, WHALE_BG_RGB, WHALE_TEXT_BODY_RGB,
WHALE_TEXT_MUTED_RGB,
CATPPUCCIN_MOCHA_UI_THEME, CLAUDE_UI_THEME, DRACULA_UI_THEME, GRAYSCALE_UI_THEME,
GRUVBOX_DARK_UI_THEME, LIGHT_UI_THEME, TOKYO_NIGHT_UI_THEME, UI_THEME, UiTheme,
WHALE_ACCENT_ACTION_RGB, WHALE_ACCENT_PRIMARY_RGB, WHALE_ACCENT_SECONDARY_RGB,
WHALE_BG_RGB, WHALE_TEXT_BODY_RGB, WHALE_TEXT_MUTED_RGB,
};
use ratatui::style::Color;
@@ -27,6 +27,7 @@ mod tests {
TOKYO_NIGHT_UI_THEME,
DRACULA_UI_THEME,
GRUVBOX_DARK_UI_THEME,
CLAUDE_UI_THEME,
];
/// Extract (r, g, b) from a Color::Rgb. Returns None for non-RGB colors.