aboutsummaryrefslogtreecommitdiff
path: root/src/app/mod.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-03-29 20:44:34 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-03-29 20:44:34 +0300
commit101de0ce453615c809d95175532bcb86f816163a (patch)
tree1722c86a0d553b72bff1de08289564ad39ce5fa4 /src/app/mod.rs
parentbf6b6d779a63d8952d8db0a7de5daa3454984620 (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.rs36
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);