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 pub null_fg: Hsla,
35 pub null_bg: Hsla,
38}
39
40impl Default for GridTheme {
41 fn default() -> Self {
42 Self {
43 bg: hsla(0.0, 0.0, 1.0, 1.0),
44 header_bg: hsla(0.0, 0.0, 0.93, 1.0),
45 filter_bg: hsla(0.0, 0.0, 0.96, 1.0),
46 filter_active_bg: hsla(0.58, 0.30, 0.85, 1.0),
47 row_header_bg: hsla(0.0, 0.0, 0.90, 1.0),
48 selection_bg: hsla(0.58, 0.50, 0.80, 0.50),
49 alt_row_bg: hsla(0.0, 0.0, 0.95, 1.0),
50 grid_line: hsla(0.0, 0.0, 0.85, 1.0),
51 header_fg: hsla(0.0, 0.0, 0.15, 1.0),
52 text_fg: hsla(0.0, 0.0, 0.1, 1.0),
53 negative_fg: hsla(0.0, 0.75, 0.45, 1.0),
54 sort_indicator: hsla(0.58, 0.50, 0.40, 1.0),
55 filter_cursor: hsla(0.0, 0.0, 0.1, 1.0),
56 menu_bg: hsla(0.0, 0.0, 1.0, 1.0),
57 menu_hover_bg: hsla(0.58, 0.45, 0.85, 1.0),
58 menu_fg: hsla(0.0, 0.0, 0.1, 1.0),
59 muted_text: hsla(0.0, 0.0, 0.5, 1.0),
60 null_fg: hsla(0.0, 0.0, 0.45, 1.0),
61 null_bg: hsla(0.13, 0.55, 0.90, 1.0),
62 }
63 }
64}
65
66fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
67 Hsla { h, s, l, a }
68}
69
70impl GridTheme {
71 #[must_use]
74 pub fn light() -> Self {
75 Self::default()
76 }
77
78 #[must_use]
81 pub fn dark() -> Self {
82 Self {
83 bg: hsla(0.0, 0.0, 0.12, 1.0),
84 header_bg: hsla(0.0, 0.0, 0.18, 1.0),
85 filter_bg: hsla(0.0, 0.0, 0.15, 1.0),
86 filter_active_bg: hsla(0.58, 0.40, 0.30, 1.0),
87 row_header_bg: hsla(0.0, 0.0, 0.16, 1.0),
88 selection_bg: hsla(0.58, 0.50, 0.45, 0.50),
89 alt_row_bg: hsla(0.0, 0.0, 0.15, 1.0),
90 grid_line: hsla(0.0, 0.0, 0.28, 1.0),
91 header_fg: hsla(0.0, 0.0, 0.80, 1.0),
92 text_fg: hsla(0.0, 0.0, 0.90, 1.0),
93 negative_fg: hsla(0.0, 0.70, 0.62, 1.0),
94 sort_indicator: hsla(0.58, 0.60, 0.68, 1.0),
95 filter_cursor: hsla(0.0, 0.0, 0.90, 1.0),
96 menu_bg: hsla(0.0, 0.0, 0.16, 1.0),
97 menu_hover_bg: hsla(0.58, 0.45, 0.38, 1.0),
98 menu_fg: hsla(0.0, 0.0, 0.90, 1.0),
99 muted_text: hsla(0.0, 0.0, 0.55, 1.0),
100 null_fg: hsla(0.0, 0.0, 0.60, 1.0),
101 null_bg: hsla(0.13, 0.35, 0.22, 1.0),
102 }
103 }
104
105 #[must_use]
109 pub fn for_appearance(appearance: WindowAppearance) -> Self {
110 match appearance {
111 WindowAppearance::Dark | WindowAppearance::VibrantDark => Self::dark(),
112 WindowAppearance::Light | WindowAppearance::VibrantLight => Self::light(),
113 }
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
127 fn default_theme_exposes_distinct_menu_colors() {
128 let t = GridTheme::default();
129 assert_eq!(t.menu_bg.a, 1.0, "menu background must be opaque");
131 assert_ne!(
133 t.menu_hover_bg, t.menu_bg,
134 "menu hover fill must differ from the menu background"
135 );
136 assert_ne!(
138 t.menu_fg, t.menu_bg,
139 "menu label color must contrast with the menu background"
140 );
141 }
142
143 #[test]
147 fn light_matches_default_and_dark_differs() {
148 assert_eq!(
149 GridTheme::light().bg,
150 GridTheme::default().bg,
151 "light() must alias the default palette"
152 );
153 let dark = GridTheme::dark();
154 assert_ne!(dark.bg, GridTheme::light().bg, "dark bg must differ");
155 assert!(
157 dark.bg.l < dark.text_fg.l,
158 "dark theme must be light text on a dark surface"
159 );
160 assert_eq!(dark.menu_bg.a, 1.0, "dark menu background must be opaque");
161 assert_ne!(
162 dark.menu_hover_bg, dark.menu_bg,
163 "dark menu hover fill must differ from the menu background"
164 );
165 }
166
167 #[test]
170 fn for_appearance_maps_dark_and_light_variants() {
171 assert_eq!(
172 GridTheme::for_appearance(WindowAppearance::Dark).bg,
173 GridTheme::dark().bg
174 );
175 assert_eq!(
176 GridTheme::for_appearance(WindowAppearance::VibrantDark).bg,
177 GridTheme::dark().bg
178 );
179 assert_eq!(
180 GridTheme::for_appearance(WindowAppearance::Light).bg,
181 GridTheme::light().bg
182 );
183 assert_eq!(
184 GridTheme::for_appearance(WindowAppearance::VibrantLight).bg,
185 GridTheme::light().bg
186 );
187 }
188}