aboutsummaryrefslogtreecommitdiff
path: root/src/config.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/config.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/config.rs')
-rw-r--r--src/config.rs76
1 files changed, 76 insertions, 0 deletions
diff --git a/src/config.rs b/src/config.rs
index 88092955..fc26b3a5 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -16,11 +16,52 @@ pub struct ToastConfig {
#[serde(default)]
pub struct Config {
pub onboarding: Option<bool>,
+ pub theme: ThemeConfig,
pub keys: KeysConfig,
pub ui: UiConfig,
pub advanced: AdvancedConfig,
}
+/// Theme configuration: pick a built-in or override individual tokens.
+///
+/// ```toml
+/// [theme]
+/// name = "tokyo-night" # built-in: catppuccin, tokyo-night, dracula, nord, etc.
+///
+/// [theme.custom] # override individual tokens on top of the base
+/// accent = "#f5c2e7"
+/// red = "#ff6188"
+/// ```
+#[derive(Debug, Default, Deserialize)]
+#[serde(default)]
+pub struct ThemeConfig {
+ /// Built-in theme name. Default: "catppuccin".
+ pub name: Option<String>,
+ /// Custom overrides — applied on top of the selected base theme.
+ pub custom: Option<CustomThemeColors>,
+}
+
+/// Per-token color overrides. All fields optional — only set what you want to change.
+#[derive(Debug, Default, Deserialize)]
+#[serde(default)]
+pub struct CustomThemeColors {
+ pub accent: Option<String>,
+ pub surface0: Option<String>,
+ pub surface1: Option<String>,
+ pub surface_dim: Option<String>,
+ pub overlay0: Option<String>,
+ pub overlay1: Option<String>,
+ pub text: Option<String>,
+ pub subtext0: Option<String>,
+ pub mauve: Option<String>,
+ pub green: Option<String>,
+ pub yellow: Option<String>,
+ pub red: Option<String>,
+ pub blue: Option<String>,
+ pub teal: Option<String>,
+ pub peach: Option<String>,
+}
+
#[derive(Debug)]
pub struct LoadedConfig {
pub config: Config,
@@ -939,4 +980,39 @@ allow_nested = true
let config: Config = toml::from_str(toml).unwrap();
assert!(config.advanced.allow_nested);
}
+
+ #[test]
+ fn theme_name_parses() {
+ let toml = r#"
+[theme]
+name = "dracula"
+"#;
+ let config: Config = toml::from_str(toml).unwrap();
+ assert_eq!(config.theme.name.as_deref(), Some("dracula"));
+ }
+
+ #[test]
+ fn theme_custom_overrides_parse() {
+ let toml = r##"
+[theme]
+name = "nord"
+
+[theme.custom]
+accent = "#ff79c6"
+red = "rgb(255, 85, 85)"
+"##;
+ let config: Config = toml::from_str(toml).unwrap();
+ assert_eq!(config.theme.name.as_deref(), Some("nord"));
+ let custom = config.theme.custom.as_ref().unwrap();
+ assert_eq!(custom.accent.as_deref(), Some("#ff79c6"));
+ assert_eq!(custom.red.as_deref(), Some("rgb(255, 85, 85)"));
+ assert!(custom.green.is_none());
+ }
+
+ #[test]
+ fn theme_defaults_when_missing() {
+ let config: Config = toml::from_str("").unwrap();
+ assert!(config.theme.name.is_none());
+ assert!(config.theme.custom.is_none());
+ }
}