1use ratatui::style::{Color, Modifier, Style};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6pub struct Theme {
7 pub user_color: ColorDef,
9 pub assistant_color: ColorDef,
11 pub system_color: ColorDef,
13 pub tool_color: ColorDef,
15 pub error_color: ColorDef,
17 pub border_color: ColorDef,
19 pub input_border_color: ColorDef,
21 pub help_border_color: ColorDef,
23 pub timestamp_color: ColorDef,
25 pub code_block_color: ColorDef,
27 pub status_bar_foreground: ColorDef,
29 pub status_bar_background: ColorDef,
30 pub background: Option<ColorDef>,
32}
33
34impl Default for Theme {
35 fn default() -> Self {
36 Self::marketing()
37 }
38}
39
40impl Theme {
41 pub fn dark() -> Self {
43 Self {
44 user_color: ColorDef::Named("green".to_string()),
45 assistant_color: ColorDef::Named("cyan".to_string()),
46 system_color: ColorDef::Named("yellow".to_string()),
47 tool_color: ColorDef::Named("magenta".to_string()),
48 error_color: ColorDef::Named("red".to_string()),
49 border_color: ColorDef::Named("cyan".to_string()),
50 input_border_color: ColorDef::Named("white".to_string()),
51 help_border_color: ColorDef::Named("yellow".to_string()),
52 timestamp_color: ColorDef::Named("darkgray".to_string()),
53 code_block_color: ColorDef::Named("darkgray".to_string()),
54 status_bar_foreground: ColorDef::Named("black".to_string()),
55 status_bar_background: ColorDef::Named("white".to_string()),
56 background: None,
57 }
58 }
59
60 pub fn light() -> Self {
62 Self {
63 user_color: ColorDef::Named("darkgreen".to_string()),
64 assistant_color: ColorDef::Named("darkblue".to_string()),
65 system_color: ColorDef::Named("darkyellow".to_string()),
66 tool_color: ColorDef::Named("darkmagenta".to_string()),
67 error_color: ColorDef::Named("darkred".to_string()),
68 border_color: ColorDef::Named("darkgray".to_string()),
69 input_border_color: ColorDef::Named("black".to_string()),
70 help_border_color: ColorDef::Named("darkyellow".to_string()),
71 timestamp_color: ColorDef::Named("gray".to_string()),
72 code_block_color: ColorDef::Named("gray".to_string()),
73 status_bar_foreground: ColorDef::Named("white".to_string()),
74 status_bar_background: ColorDef::Named("black".to_string()),
75 background: Some(ColorDef::Named("white".to_string())),
76 }
77 }
78
79 pub fn solarized_dark() -> Self {
81 Self {
82 user_color: ColorDef::Rgb(133, 153, 0), assistant_color: ColorDef::Rgb(42, 161, 152), system_color: ColorDef::Rgb(181, 137, 0), tool_color: ColorDef::Rgb(211, 54, 130), error_color: ColorDef::Rgb(220, 50, 47), border_color: ColorDef::Rgb(131, 148, 150), input_border_color: ColorDef::Rgb(238, 232, 213), help_border_color: ColorDef::Rgb(181, 137, 0), timestamp_color: ColorDef::Rgb(101, 123, 131), code_block_color: ColorDef::Rgb(88, 110, 117), status_bar_foreground: ColorDef::Rgb(0, 43, 54), status_bar_background: ColorDef::Rgb(238, 232, 213), background: Some(ColorDef::Rgb(0, 43, 54)), }
96 }
97
98 pub fn solarized_light() -> Self {
100 Self {
101 user_color: ColorDef::Rgb(133, 153, 0), assistant_color: ColorDef::Rgb(42, 161, 152), system_color: ColorDef::Rgb(181, 137, 0), tool_color: ColorDef::Rgb(211, 54, 130), error_color: ColorDef::Rgb(220, 50, 47), border_color: ColorDef::Rgb(88, 110, 117), input_border_color: ColorDef::Rgb(147, 161, 161), help_border_color: ColorDef::Rgb(181, 137, 0), timestamp_color: ColorDef::Rgb(131, 148, 150), code_block_color: ColorDef::Rgb(147, 161, 161), status_bar_foreground: ColorDef::Rgb(238, 232, 213), status_bar_background: ColorDef::Rgb(88, 110, 117), background: Some(ColorDef::Rgb(253, 246, 227)), }
115 }
116
117 pub fn marketing() -> Self {
120 Self {
121 user_color: ColorDef::Rgb(6, 182, 212), assistant_color: ColorDef::Rgb(34, 211, 238), system_color: ColorDef::Rgb(250, 204, 21), tool_color: ColorDef::Rgb(232, 121, 249), error_color: ColorDef::Rgb(248, 113, 113), border_color: ColorDef::Rgb(31, 41, 55), input_border_color: ColorDef::Rgb(55, 65, 81), help_border_color: ColorDef::Rgb(6, 182, 212), timestamp_color: ColorDef::Rgb(107, 114, 128), code_block_color: ColorDef::Rgb(75, 85, 99), status_bar_foreground: ColorDef::Rgb(17, 24, 39), status_bar_background: ColorDef::Rgb(6, 182, 212), background: Some(ColorDef::Rgb(3, 7, 18)), }
148 }
149
150 pub fn get_role_style(&self, role: &str) -> Style {
152 let color = match role {
153 "user" => self.user_color.to_color(),
154 "assistant" => self.assistant_color.to_color(),
155 "system" => self.system_color.to_color(),
156 "tool" => self.tool_color.to_color(),
157 "error" => self.error_color.to_color(),
158 _ => Color::White,
159 };
160 Style::default().fg(color).add_modifier(Modifier::BOLD)
161 }
162}
163
164#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
166#[serde(untagged)]
167pub enum ColorDef {
168 Named(String),
170 Rgb(u8, u8, u8),
172 Indexed(u8),
174}
175
176impl ColorDef {
177 pub fn to_color(&self) -> Color {
179 match self {
180 ColorDef::Named(name) => match name.to_lowercase().as_str() {
181 "black" => Color::Black,
182 "red" => Color::Red,
183 "green" => Color::Green,
184 "yellow" => Color::Yellow,
185 "blue" => Color::Blue,
186 "magenta" => Color::Magenta,
187 "cyan" => Color::Cyan,
188 "gray" | "grey" => Color::Gray,
189 "darkgray" | "dark_gray" | "darkgrey" => Color::DarkGray,
190 "lightgray" | "light_gray" | "lightgrey" => Color::Gray,
191 "darkred" | "dark_red" => Color::Red,
193 "darkgreen" | "dark_green" => Color::Green,
194 "darkyellow" | "dark_yellow" => Color::Yellow,
195 "darkblue" | "dark_blue" => Color::Blue,
196 "darkmagenta" | "dark_magenta" => Color::Magenta,
197 "darkcyan" | "dark_cyan" => Color::Cyan,
198 "lightred" | "light_red" => Color::LightRed,
200 "lightgreen" | "light_green" => Color::LightGreen,
201 "lightyellow" | "light_yellow" => Color::LightYellow,
202 "lightblue" | "light_blue" => Color::LightBlue,
203 "lightmagenta" | "light_magenta" => Color::LightMagenta,
204 "lightcyan" | "light_cyan" => Color::LightCyan,
205 "white" => Color::White,
206 _ => Color::White,
207 },
208 ColorDef::Rgb(r, g, b) => Color::Rgb(*r, *g, *b),
209 ColorDef::Indexed(idx) => Color::Indexed(*idx),
210 }
211 }
212}
213
214impl From<Color> for ColorDef {
215 fn from(color: Color) -> Self {
216 match color {
217 Color::Black => ColorDef::Named("black".to_string()),
218 Color::Red => ColorDef::Named("red".to_string()),
219 Color::Green => ColorDef::Named("green".to_string()),
220 Color::Yellow => ColorDef::Named("yellow".to_string()),
221 Color::Blue => ColorDef::Named("blue".to_string()),
222 Color::Magenta => ColorDef::Named("magenta".to_string()),
223 Color::Cyan => ColorDef::Named("cyan".to_string()),
224 Color::Gray => ColorDef::Named("gray".to_string()),
225 Color::DarkGray => ColorDef::Named("darkgray".to_string()),
226 Color::LightRed => ColorDef::Named("lightred".to_string()),
227 Color::LightGreen => ColorDef::Named("lightgreen".to_string()),
228 Color::LightYellow => ColorDef::Named("lightyellow".to_string()),
229 Color::LightBlue => ColorDef::Named("lightblue".to_string()),
230 Color::LightMagenta => ColorDef::Named("lightmagenta".to_string()),
231 Color::LightCyan => ColorDef::Named("lightcyan".to_string()),
232 Color::White => ColorDef::Named("white".to_string()),
233 Color::Rgb(r, g, b) => ColorDef::Rgb(r, g, b),
234 Color::Indexed(idx) => ColorDef::Indexed(idx),
235 _ => ColorDef::Named("white".to_string()),
236 }
237 }
238}
239
240impl ColorDef {
242 pub fn black() -> Self {
243 ColorDef::Named("black".to_string())
244 }
245 pub fn red() -> Self {
246 ColorDef::Named("red".to_string())
247 }
248 pub fn green() -> Self {
249 ColorDef::Named("green".to_string())
250 }
251 pub fn yellow() -> Self {
252 ColorDef::Named("yellow".to_string())
253 }
254 pub fn blue() -> Self {
255 ColorDef::Named("blue".to_string())
256 }
257 pub fn magenta() -> Self {
258 ColorDef::Named("magenta".to_string())
259 }
260 pub fn cyan() -> Self {
261 ColorDef::Named("cyan".to_string())
262 }
263 pub fn white() -> Self {
264 ColorDef::Named("white".to_string())
265 }
266 pub fn gray() -> Self {
267 ColorDef::Named("gray".to_string())
268 }
269 pub fn dark_gray() -> Self {
270 ColorDef::Named("darkgray".to_string())
271 }
272 pub fn light_gray() -> Self {
273 ColorDef::Named("gray".to_string())
274 }
275}