feat(tui): add /theme slash command and fix Plan panel dark theme colors#992
feat(tui): add /theme slash command and fix Plan panel dark theme colors#992MengZ-super wants to merge 3 commits intoHmbown:mainfrom
Conversation
- Add /theme command to toggle between light/dark themes at runtime - Add --theme CLI flag for startup theme selection - Fix Plan panel displaying white background in dark theme by setting explicit section_bg instead of Color::Reset - Fix plan_progress_color and plan_completed_color to use deeper DEEPSEEK_BLUE instead of bright SKY blue in dark theme - Restore Ctrl+T → Live Transcript Overlay (revert accidental toggle_theme binding) - Add theme field to TuiOptions and update all test initializers - Add KbLiveTranscript localization for Ctrl+T keybinding Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Accept origin/main palette.rs restructuring (PaletteMode, LIGHT_UI_THEME) and fix theme-related references to use new UITheme names. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…nd-plan-panel-fix feat(tui): add /theme slash command and fix Plan panel dark theme colors
There was a problem hiding this comment.
Code Review
This pull request introduces a theme system to the TUI, enabling users to switch between light and dark modes via a new /theme command or a --theme CLI flag. The implementation includes a light theme definition, global theme state management with persistence to user preferences, and updated localizations. Review feedback identifies critical issues including a naming inconsistency that will cause compilation errors, logic duplication between the command handler and the App struct, and an incomplete UI state update when initializing via the CLI flag. Additionally, concerns were raised regarding the efficiency and safety of the thread-based persistence mechanism and the presence of unused localization keys.
| pub fn theme(app: &mut App) -> CommandResult { | ||
| let current = crate::deepseek_theme::active_theme().variant; | ||
| let (new_variant, label) = match current { | ||
| crate::deepseek_theme::Variant::Dark => (crate::deepseek_theme::Variant::Light, "light"), | ||
| crate::deepseek_theme::Variant::Light => (crate::deepseek_theme::Variant::Dark, "dark"), | ||
| }; | ||
| let new_theme = if new_variant == crate::deepseek_theme::Variant::Light { | ||
| crate::deepseek_theme::Theme::light() | ||
| } else { | ||
| crate::deepseek_theme::Theme::dark() | ||
| }; | ||
| crate::deepseek_theme::set_active_theme(new_theme); | ||
| app.ui_theme = if new_variant == crate::deepseek_theme::Variant::Light { | ||
| crate::palette::UI_THEME_LIGHT | ||
| } else { | ||
| crate::palette::UI_THEME | ||
| }; | ||
| CommandResult::message(format!("Theme switched to {label}.")) | ||
| } |
There was a problem hiding this comment.
The logic for toggling the theme is duplicated here and in App::toggle_theme. Additionally, there is a naming discrepancy for the palette constant: this file uses UI_THEME_LIGHT (line 522), while crates/tui/src/tui/app.rs uses LIGHT_UI_THEME (line 3706). This inconsistency will likely cause a compilation error. It is better to delegate the toggle logic to the App method to ensure consistency and maintainability.
pub fn theme(app: &mut App) -> CommandResult {
app.toggle_theme();
let label = if crate::deepseek_theme::active_theme().variant == crate::deepseek_theme::Variant::Light {
"light"
} else {
"dark"
};
CommandResult::message(format!("Theme switched to {label}."))
}| if let Some(theme_arg) = options.theme.as_ref() { | ||
| let theme = match theme_arg { | ||
| crate::deepseek_theme::ThemeArg::Dark => crate::deepseek_theme::Theme::dark(), | ||
| crate::deepseek_theme::ThemeArg::Light => crate::deepseek_theme::Theme::light(), | ||
| }; | ||
| crate::deepseek_theme::set_active_theme(theme); | ||
| } |
There was a problem hiding this comment.
When the --theme CLI flag is provided, app.ui_theme is not updated to match the requested theme. This will result in an inconsistent UI state where some components use the new theme (via the global active_theme()) while others remain in the default theme (via app.ui_theme). Ensure app.ui_theme is updated here as well.
if let Some(theme_arg) = options.theme.as_ref() {
let theme = match theme_arg {
crate::deepseek_theme::ThemeArg::Dark => crate::deepseek_theme::Theme::dark(),
crate::deepseek_theme::ThemeArg::Light => crate::deepseek_theme::Theme::light(),
};
crate::deepseek_theme::set_active_theme(theme);
app.ui_theme = if theme.variant == crate::deepseek_theme::Variant::Light {
crate::palette::LIGHT_UI_THEME
} else {
crate::palette::UI_THEME
};
}| std::thread::spawn(move || { | ||
| if let Ok(mut prefs) = crate::settings::TuiPrefs::load() { | ||
| prefs.theme = variant_str.to_string(); | ||
| let _ = prefs.save(); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Spawning a new thread for every theme change to persist preferences is inefficient and potentially prone to race conditions if TuiPrefs::load() and save() are called concurrently (e.g., if a user toggles the theme rapidly). Since this is a TUI application, consider using a more robust persistence mechanism, such as a background worker or an async task if the runtime is available.
| KbToolDetailsPager, | ||
| KbThinkingPager, | ||
| KbLiveTranscript, | ||
| KbToggleTheme, |
There was a problem hiding this comment.
The KbToggleTheme message ID is added and translated across multiple languages, but it is not used in crates/tui/src/tui/keybindings.rs or elsewhere in the current changes. If a keybinding for toggling the theme was intended, it should be added to the keybindings list; otherwise, this appears to be dead code.
Fixes two review comments from PR Hmbown#992: 1. config::theme() now delegates to App::toggle_theme() instead of duplicating the toggle logic 2. --theme CLI flag now updates app.ui_theme to maintain consistent UI state between the active theme and the UI_THEME palette Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
/themecommand to toggle between light/dark themes at runtime--themeCLI flag (--theme dark/--theme light) for startup theme selectionsection_bg: DEEPSEEK_INKinstead ofColor::Resetplan_progress_colorandplan_completed_colorto use deeperDEEPSEEK_BLUEinstead of brightDEEPSEEK_SKYblue in dark themeCtrl+T→ Live Transcript Overlay (revert accidental toggle_theme binding)themefield toTuiOptionsand update all test initializersKbLiveTranscriptlocalization forCtrl+Tkeybinding descriptionTest plan
cargo buildsuccessfully/themecommand toggles theme correctlyCtrl+Topens live transcript overlaycargo test -p deepseek-tuiand confirm all tests pass🤖 Generated with Claude Code