diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-03-29 20:44:34 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-03-29 20:44:34 +0300 |
| commit | 101de0ce453615c809d95175532bcb86f816163a (patch) | |
| tree | 1722c86a0d553b72bff1de08289564ad39ce5fa4 /src/app/mod.rs | |
| parent | bf6b6d779a63d8952d8db0a7de5daa3454984620 (diff) | |
refactor: two-section sidebar with agent detail panel, theme system with 9 built-in themes
sidebar layout:
- top section: workspace list with accent bar, git branch, state dots
- bottom section: agent detail panel sorted by urgency with braille spinners
- active workspace always highlighted (subtle bg in terminal mode, brighter in nav)
- palette-driven colors throughout (no hardcoded colors in ui.rs)
theme system:
- 9 built-in themes: catppuccin (default), tokyo-night, dracula, nord, gruvbox, one-dark, solarized, kanagawa, rose-pine
- config: theme.name selects base, theme.custom overrides individual tokens
- 15 color tokens: accent, surface0/1, overlay0/1, text, subtext0, mauve, green, yellow, red, blue, teal, peach
- legacy ui.accent still works for backward compatibility
infrastructure:
- Palette struct on AppState, ready for future theme system extensions
- git_branch() reads .git/HEAD for branch detection
- PaneDetail struct with urgency sorting for agent panel
- spinner_tick counter for braille animation (~8fps on 60fps render loop)
Diffstat (limited to 'src/app/mod.rs')
| -rw-r--r-- | src/app/mod.rs | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/src/app/mod.rs b/src/app/mod.rs index ef424ed8..6562c5d6 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -36,6 +36,38 @@ pub struct App { toast_deadline: Option<Instant>, } +/// Resolve the palette from config: base theme + optional custom overrides. +fn resolve_palette(config: &crate::config::Config) -> state::Palette { + // Start with the named theme (default: catppuccin) + let base_name = config.theme.name.as_deref().unwrap_or("catppuccin"); + let mut palette = state::Palette::from_name(base_name).unwrap_or_else(|| { + tracing::warn!( + theme = base_name, + "unknown theme, falling back to catppuccin" + ); + state::Palette::catppuccin() + }); + + // Apply custom overrides if present + if let Some(custom) = &config.theme.custom { + palette = palette.with_overrides(custom); + } + + // Legacy: if ui.accent is set and no theme.custom.accent, use it for compat + if config.ui.accent != "cyan" + && config + .theme + .custom + .as_ref() + .and_then(|c| c.accent.as_ref()) + .is_none() + { + palette.accent = crate::config::parse_color(&config.ui.accent); + } + + palette +} + impl App { pub fn new( config: &Config, @@ -106,6 +138,8 @@ impl App { sound: config.ui.sound.clone(), toast_config: config.ui.toast.clone(), keybinds: config.keybinds(), + spinner_tick: 0, + palette: resolve_palette(&config), }; // Background auto-update (skipped in --no-session / test mode) @@ -155,6 +189,8 @@ impl App { self.state.toast = None; } + self.state.spinner_tick = self.state.spinner_tick.wrapping_add(1); + terminal.draw(|frame| { crate::ui::compute_view(&mut self.state, frame.area()); crate::ui::render(&self.state, frame); |
