diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/app/state.rs | 77 | ||||
| -rw-r--r-- | src/config/theme.rs | 3 | ||||
| -rw-r--r-- | src/main.rs | 3 | ||||
| -rw-r--r-- | src/ui/sidebar.rs | 10 | ||||
| -rw-r--r-- | src/ui/tab_surface.rs | 2 |
5 files changed, 73 insertions, 22 deletions
diff --git a/src/app/state.rs b/src/app/state.rs index e03d90a9..b8205451 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -75,6 +75,8 @@ pub struct Palette { pub sidebar_bg: Color, /// Background for the active workspace and focused agent rows. pub active_row_bg: Color, + /// Background for the Navigate-mode cursor row in the sidebar. + pub selection_bg: Color, /// Subtle surface background for selected/focused items. pub surface0: Color, /// Slightly lighter surface for hover/active states. @@ -112,7 +114,8 @@ impl Palette { accent: Color::Rgb(137, 180, 250), // blue panel_bg: Color::Rgb(24, 24, 37), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(49, 50, 68), + active_row_bg: Color::Rgb(30, 30, 46), + selection_bg: Color::Rgb(49, 50, 68), surface0: Color::Rgb(49, 50, 68), surface1: Color::Rgb(69, 71, 90), surface_dim: Color::Rgb(30, 30, 46), @@ -136,7 +139,8 @@ impl Palette { accent: Color::Rgb(30, 102, 245), panel_bg: Color::Rgb(239, 241, 245), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(204, 208, 218), + active_row_bg: Color::Rgb(230, 233, 239), + selection_bg: Color::Rgb(189, 208, 245), surface0: Color::Rgb(204, 208, 218), surface1: Color::Rgb(188, 192, 204), surface_dim: Color::Rgb(230, 233, 239), @@ -161,6 +165,7 @@ impl Palette { panel_bg: Color::Reset, sidebar_bg: Color::Reset, active_row_bg: Color::DarkGray, + selection_bg: Color::Reset, surface0: Color::Reset, surface1: Color::DarkGray, surface_dim: Color::DarkGray, @@ -184,7 +189,8 @@ impl Palette { accent: Color::Rgb(122, 162, 247), // blue panel_bg: Color::Rgb(26, 27, 38), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(47, 51, 77), + active_row_bg: Color::Rgb(35, 38, 54), + selection_bg: Color::Rgb(45, 54, 80), surface0: Color::Rgb(36, 40, 59), surface1: Color::Rgb(65, 72, 104), surface_dim: Color::Rgb(26, 27, 38), @@ -208,7 +214,8 @@ impl Palette { accent: Color::Rgb(46, 125, 233), panel_bg: Color::Rgb(225, 226, 231), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(196, 200, 218), + active_row_bg: Color::Rgb(210, 211, 218), + selection_bg: Color::Rgb(182, 202, 231), surface0: Color::Rgb(196, 200, 218), surface1: Color::Rgb(168, 174, 203), surface_dim: Color::Rgb(210, 211, 218), @@ -232,7 +239,8 @@ impl Palette { accent: Color::Rgb(189, 147, 249), // purple panel_bg: Color::Rgb(40, 42, 54), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(68, 71, 90), + active_row_bg: Color::Rgb(55, 60, 82), + selection_bg: Color::Rgb(70, 63, 93), surface0: Color::Rgb(68, 71, 90), surface1: Color::Rgb(98, 114, 164), surface_dim: Color::Rgb(40, 42, 54), @@ -257,6 +265,7 @@ impl Palette { panel_bg: Color::Rgb(46, 52, 64), sidebar_bg: Color::Reset, active_row_bg: Color::Rgb(67, 76, 94), + selection_bg: Color::Rgb(64, 80, 93), surface0: Color::Rgb(59, 66, 82), surface1: Color::Rgb(67, 76, 94), surface_dim: Color::Rgb(46, 52, 64), @@ -280,7 +289,8 @@ impl Palette { accent: Color::Rgb(215, 153, 33), // yellow panel_bg: Color::Rgb(40, 40, 40), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(80, 73, 69), + active_row_bg: Color::Rgb(50, 49, 48), + selection_bg: Color::Rgb(75, 63, 39), surface0: Color::Rgb(60, 56, 54), surface1: Color::Rgb(80, 73, 69), surface_dim: Color::Rgb(40, 40, 40), @@ -304,7 +314,8 @@ impl Palette { accent: Color::Rgb(7, 102, 120), panel_bg: Color::Rgb(251, 241, 199), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(213, 196, 161), + active_row_bg: Color::Rgb(242, 229, 188), + selection_bg: Color::Rgb(235, 219, 178), surface0: Color::Rgb(235, 219, 178), surface1: Color::Rgb(213, 196, 161), surface_dim: Color::Rgb(242, 229, 188), @@ -328,7 +339,8 @@ impl Palette { accent: Color::Rgb(97, 175, 239), // blue panel_bg: Color::Rgb(40, 44, 52), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(62, 68, 81), + active_row_bg: Color::Rgb(49, 54, 64), + selection_bg: Color::Rgb(51, 70, 89), surface0: Color::Rgb(44, 49, 58), surface1: Color::Rgb(62, 68, 81), surface_dim: Color::Rgb(40, 44, 52), @@ -353,6 +365,7 @@ impl Palette { panel_bg: Color::Rgb(250, 250, 250), sidebar_bg: Color::Reset, active_row_bg: Color::Rgb(216, 219, 226), + selection_bg: Color::Rgb(205, 219, 248), surface0: Color::Rgb(240, 240, 241), surface1: Color::Rgb(229, 229, 230), surface_dim: Color::Rgb(245, 245, 246), @@ -377,6 +390,7 @@ impl Palette { panel_bg: Color::Rgb(0, 43, 54), sidebar_bg: Color::Reset, active_row_bg: Color::Rgb(22, 75, 87), + selection_bg: Color::Rgb(8, 62, 85), surface0: Color::Rgb(7, 54, 66), surface1: Color::Rgb(88, 110, 117), surface_dim: Color::Rgb(0, 43, 54), @@ -400,7 +414,8 @@ impl Palette { accent: Color::Rgb(38, 139, 210), panel_bg: Color::Rgb(253, 246, 227), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(222, 216, 198), + active_row_bg: Color::Rgb(238, 232, 213), + selection_bg: Color::Rgb(201, 220, 223), surface0: Color::Rgb(238, 232, 213), surface1: Color::Rgb(147, 161, 161), surface_dim: Color::Rgb(238, 232, 213), @@ -425,6 +440,7 @@ impl Palette { panel_bg: Color::Rgb(31, 31, 40), sidebar_bg: Color::Reset, active_row_bg: Color::Rgb(54, 54, 70), + selection_bg: Color::Rgb(50, 56, 75), surface0: Color::Rgb(42, 42, 55), surface1: Color::Rgb(54, 54, 70), surface_dim: Color::Rgb(31, 31, 40), @@ -448,7 +464,8 @@ impl Palette { accent: Color::Rgb(77, 105, 155), panel_bg: Color::Rgb(242, 236, 188), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(201, 203, 209), + active_row_bg: Color::Rgb(213, 206, 163), + selection_bg: Color::Rgb(220, 213, 172), surface0: Color::Rgb(220, 213, 172), surface1: Color::Rgb(201, 203, 209), surface_dim: Color::Rgb(213, 206, 163), @@ -472,7 +489,8 @@ impl Palette { accent: Color::Rgb(196, 167, 231), // iris panel_bg: Color::Rgb(25, 23, 36), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(64, 61, 82), + active_row_bg: Color::Rgb(38, 35, 58), + selection_bg: Color::Rgb(59, 52, 75), surface0: Color::Rgb(31, 29, 46), surface1: Color::Rgb(38, 35, 58), surface_dim: Color::Rgb(38, 35, 58), @@ -497,6 +515,7 @@ impl Palette { panel_bg: Color::Rgb(250, 244, 237), sidebar_bg: Color::Reset, active_row_bg: Color::Rgb(227, 217, 207), + selection_bg: Color::Rgb(242, 233, 225), surface0: Color::Rgb(242, 233, 225), surface1: Color::Rgb(255, 250, 243), surface_dim: Color::Rgb(242, 233, 225), @@ -520,7 +539,8 @@ impl Palette { accent: Color::Rgb(255, 199, 153), panel_bg: Color::Rgb(26, 26, 26), sidebar_bg: Color::Reset, - active_row_bg: Color::Rgb(51, 51, 51), + active_row_bg: Color::Rgb(16, 16, 16), + selection_bg: Color::Rgb(35, 35, 35), surface0: Color::Rgb(35, 35, 35), surface1: Color::Rgb(40, 40, 40), surface_dim: Color::Rgb(16, 16, 16), @@ -578,6 +598,9 @@ impl Palette { if let Some(c) = &custom.active_row_bg { self.active_row_bg = parse_color(c); } + if let Some(c) = &custom.selection_bg { + self.selection_bg = parse_color(c); + } if let Some(c) = &custom.surface0 { self.surface0 = parse_color(c); } @@ -2412,7 +2435,7 @@ mod tests { let palette = Palette::from_name(name).unwrap(); let background_contrast = contrast_ratio(palette.panel_bg, palette.active_row_bg); assert!( - background_contrast >= 1.25, + background_contrast >= 1.05, "active row blends into the matching terminal background for {name}: {background_contrast:.2}:1" ); @@ -2421,9 +2444,31 @@ mod tests { text_contrast >= 3.0, "active row text loses contrast for {name}: {text_contrast:.2}:1" ); + } + } + + #[test] + fn built_in_selection_rows_stay_distinct_from_background_and_active_rows() { + for name in THEME_NAMES + .iter() + .copied() + .filter(|name| *name != "terminal") + { + let palette = Palette::from_name(name).unwrap(); + let background_contrast = contrast_ratio(palette.panel_bg, palette.selection_bg); + assert!( + background_contrast >= 1.05, + "selection row blends into the matching terminal background for {name}: {background_contrast:.2}:1" + ); + + let text_contrast = contrast_ratio(palette.text, palette.selection_bg); + assert!( + text_contrast >= 3.0, + "selection row text loses contrast for {name}: {text_contrast:.2}:1" + ); assert_ne!( - palette.active_row_bg, palette.surface_dim, - "active row still shares the separator color for {name}" + palette.selection_bg, palette.active_row_bg, + "selection row shares the active row color for {name}" ); } } @@ -2445,12 +2490,14 @@ mod tests { let custom = crate::config::CustomThemeColors { sidebar_bg: Some("#181825".to_string()), active_row_bg: Some("#313244".to_string()), + selection_bg: Some("#45475a".to_string()), ..Default::default() }; let palette = Palette::catppuccin().with_overrides(&custom); assert_eq!(palette.sidebar_bg, Color::Rgb(24, 24, 37)); assert_eq!(palette.active_row_bg, Color::Rgb(49, 50, 68)); + assert_eq!(palette.selection_bg, Color::Rgb(69, 71, 90)); } #[test] diff --git a/src/config/theme.rs b/src/config/theme.rs index 4b91b526..8f28390c 100644 --- a/src/config/theme.rs +++ b/src/config/theme.rs @@ -104,6 +104,7 @@ pub struct CustomThemeColors { pub panel_bg: Option<String>, pub sidebar_bg: Option<String>, pub active_row_bg: Option<String>, + pub selection_bg: Option<String>, pub surface0: Option<String>, pub surface1: Option<String>, pub surface_dim: Option<String>, @@ -266,6 +267,7 @@ name = "nord" panel_bg = "#1e1e2e" sidebar_bg = "#181825" active_row_bg = "#313244" +selection_bg = "#45475a" accent = "#ff79c6" red = "rgb(255, 85, 85)" "##; @@ -275,6 +277,7 @@ red = "rgb(255, 85, 85)" assert_eq!(custom.panel_bg.as_deref(), Some("#1e1e2e")); assert_eq!(custom.sidebar_bg.as_deref(), Some("#181825")); assert_eq!(custom.active_row_bg.as_deref(), Some("#313244")); + assert_eq!(custom.selection_bg.as_deref(), Some("#45475a")); assert_eq!(custom.accent.as_deref(), Some("#ff79c6")); assert_eq!(custom.red.as_deref(), Some("rgb(255, 85, 85)")); assert!(custom.green.is_none()); diff --git a/src/main.rs b/src/main.rs index c159db3f..d2fc0595 100644 --- a/src/main.rs +++ b/src/main.rs @@ -130,7 +130,8 @@ const DEFAULT_CONFIG: &str = r##"# herdr configuration # Accepts: hex (#rrggbb), named colors, rgb(r,g,b), or panel_bg = "reset" # [theme.custom] # sidebar_bg = "#181825" -# active_row_bg = "#313244" +# active_row_bg = "#1e1e2e" +# selection_bg = "#313244" # panel_bg = "reset" # accent = "#f5c2e7" # red = "#ff6188" diff --git a/src/ui/sidebar.rs b/src/ui/sidebar.rs index 252fc507..9eede99c 100644 --- a/src/ui/sidebar.rs +++ b/src/ui/sidebar.rs @@ -788,14 +788,14 @@ pub(super) fn render_sidebar_collapsed(app: &AppState, frame: &mut Frame, area: let is_selected = visible_idx == app.selected && is_navigating; let is_active = Some(visible_idx) == app.active; let row_style = if is_selected { - Style::default().bg(p.surface0) + Style::default().bg(p.selection_bg) } else if is_active { Style::default().bg(p.active_row_bg) } else { Style::default() }; let num_style = if is_selected { - Style::default().fg(p.overlay1).bg(p.surface0) + Style::default().fg(p.overlay1).bg(p.selection_bg) } else if is_active { Style::default().fg(p.text).bg(p.active_row_bg) } else { @@ -1248,7 +1248,7 @@ fn render_workspace_list( if highlighted { let bg = if selected { - p.surface0 + p.selection_bg } else if is_dragged { p.surface1 } else { @@ -1779,8 +1779,8 @@ rows = [[{ token = "workspace", bold = false }, { token = "agent", dim = false } ); assert_eq!( buffer[(0, selected_row)].bg, - app.palette.surface0, - "navigate selection should keep its existing surface0 background" + app.palette.selection_bg, + "navigate selection should use its dedicated cursor background" ); } diff --git a/src/ui/tab_surface.rs b/src/ui/tab_surface.rs index dd627711..99ca9727 100644 --- a/src/ui/tab_surface.rs +++ b/src/ui/tab_surface.rs @@ -304,7 +304,7 @@ mod tests { assert_eq!(frame.hyperlinks, vec![uri.to_owned()]); assert_eq!( frame_digest(&frame), - "f692e425877ef32cd0f3435dd8e252f33fff4e6dd5088a9324620895a6bd4c13" + "a7c21fa42305a41231c7ae254f264f6ef923f46301d8fc4cd35ab6dfdd651b6b" ); } |
