1use gpui::{Hsla, WindowAppearance};
6
7#[derive(Clone, Debug)]
8pub struct GridTheme {
9 pub bg: Hsla,
10 pub header_bg: Hsla,
11 pub filter_bg: Hsla,
12 pub filter_active_bg: Hsla,
13 pub row_header_bg: Hsla,
14 pub selection_bg: Hsla,
15 pub alt_row_bg: Hsla,
16 pub grid_line: Hsla,
17 pub header_fg: Hsla,
18 pub text_fg: Hsla,
19 pub negative_fg: Hsla,
20 pub sort_indicator: Hsla,
21 pub filter_cursor: Hsla,
22 pub menu_bg: Hsla,
24 pub menu_hover_bg: Hsla,
26 pub menu_fg: Hsla,
28 pub muted_text: Hsla,
32}
33
34impl Default for GridTheme {
35 fn default() -> Self {
36 Self {
37 bg: hsla(0.0, 0.0, 1.0, 1.0),
38 header_bg: hsla(0.0, 0.0, 0.93, 1.0),
39 filter_bg: hsla(0.0, 0.0, 0.96, 1.0),
40 filter_active_bg: hsla(0.58, 0.30, 0.85, 1.0),
41 row_header_bg: hsla(0.0, 0.0, 0.90, 1.0),
42 selection_bg: hsla(0.58, 0.50, 0.80, 0.50),
43 alt_row_bg: hsla(0.0, 0.0, 0.95, 1.0),
44 grid_line: hsla(0.0, 0.0, 0.85, 1.0),
45 header_fg: hsla(0.0, 0.0, 0.15, 1.0),
46 text_fg: hsla(0.0, 0.0, 0.1, 1.0),
47 negative_fg: hsla(0.0, 0.75, 0.45, 1.0),
48 sort_indicator: hsla(0.58, 0.50, 0.40, 1.0),
49 filter_cursor: hsla(0.0, 0.0, 0.1, 1.0),
50 menu_bg: hsla(0.0, 0.0, 1.0, 1.0),
51 menu_hover_bg: hsla(0.58, 0.45, 0.85, 1.0),
52 menu_fg: hsla(0.0, 0.0, 0.1, 1.0),
53 muted_text: hsla(0.0, 0.0, 0.5, 1.0),
54 }
55 }
56}
57
58fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
59 Hsla { h, s, l, a }
60}
61
62impl GridTheme {
63 #[must_use]
66 pub fn light() -> Self {
67 Self::default()
68 }
69
70 #[must_use]
73 pub fn dark() -> Self {
74 Self {
75 bg: hsla(0.0, 0.0, 0.12, 1.0),
76 header_bg: hsla(0.0, 0.0, 0.18, 1.0),
77 filter_bg: hsla(0.0, 0.0, 0.15, 1.0),
78 filter_active_bg: hsla(0.58, 0.40, 0.30, 1.0),
79 row_header_bg: hsla(0.0, 0.0, 0.16, 1.0),
80 selection_bg: hsla(0.58, 0.50, 0.45, 0.50),
81 alt_row_bg: hsla(0.0, 0.0, 0.15, 1.0),
82 grid_line: hsla(0.0, 0.0, 0.28, 1.0),
83 header_fg: hsla(0.0, 0.0, 0.80, 1.0),
84 text_fg: hsla(0.0, 0.0, 0.90, 1.0),
85 negative_fg: hsla(0.0, 0.70, 0.62, 1.0),
86 sort_indicator: hsla(0.58, 0.60, 0.68, 1.0),
87 filter_cursor: hsla(0.0, 0.0, 0.90, 1.0),
88 menu_bg: hsla(0.0, 0.0, 0.16, 1.0),
89 menu_hover_bg: hsla(0.58, 0.45, 0.38, 1.0),
90 menu_fg: hsla(0.0, 0.0, 0.90, 1.0),
91 muted_text: hsla(0.0, 0.0, 0.55, 1.0),
92 }
93 }
94
95 #[must_use]
99 pub fn for_appearance(appearance: WindowAppearance) -> Self {
100 match appearance {
101 WindowAppearance::Dark | WindowAppearance::VibrantDark => Self::dark(),
102 WindowAppearance::Light | WindowAppearance::VibrantLight => Self::light(),
103 }
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
117 fn default_theme_exposes_distinct_menu_colors() {
118 let t = GridTheme::default();
119 assert_eq!(t.menu_bg.a, 1.0, "menu background must be opaque");
121 assert_ne!(
123 t.menu_hover_bg, t.menu_bg,
124 "menu hover fill must differ from the menu background"
125 );
126 assert_ne!(
128 t.menu_fg, t.menu_bg,
129 "menu label color must contrast with the menu background"
130 );
131 }
132
133 #[test]
137 fn light_matches_default_and_dark_differs() {
138 assert_eq!(
139 GridTheme::light().bg,
140 GridTheme::default().bg,
141 "light() must alias the default palette"
142 );
143 let dark = GridTheme::dark();
144 assert_ne!(dark.bg, GridTheme::light().bg, "dark bg must differ");
145 assert!(
147 dark.bg.l < dark.text_fg.l,
148 "dark theme must be light text on a dark surface"
149 );
150 assert_eq!(dark.menu_bg.a, 1.0, "dark menu background must be opaque");
151 assert_ne!(
152 dark.menu_hover_bg, dark.menu_bg,
153 "dark menu hover fill must differ from the menu background"
154 );
155 }
156
157 #[test]
160 fn for_appearance_maps_dark_and_light_variants() {
161 assert_eq!(
162 GridTheme::for_appearance(WindowAppearance::Dark).bg,
163 GridTheme::dark().bg
164 );
165 assert_eq!(
166 GridTheme::for_appearance(WindowAppearance::VibrantDark).bg,
167 GridTheme::dark().bg
168 );
169 assert_eq!(
170 GridTheme::for_appearance(WindowAppearance::Light).bg,
171 GridTheme::light().bg
172 );
173 assert_eq!(
174 GridTheme::for_appearance(WindowAppearance::VibrantLight).bg,
175 GridTheme::light().bg
176 );
177 }
178}