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::dark()
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 get_role_style(&self, role: &str) -> Style {
119 let color = match role {
120 "user" => self.user_color.to_color(),
121 "assistant" => self.assistant_color.to_color(),
122 "system" => self.system_color.to_color(),
123 "tool" => self.tool_color.to_color(),
124 "error" => self.error_color.to_color(),
125 _ => Color::White,
126 };
127 Style::default().fg(color).add_modifier(Modifier::BOLD)
128 }
129}
130
131#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
133#[serde(untagged)]
134pub enum ColorDef {
135 Named(String),
137 Rgb(u8, u8, u8),
139 Indexed(u8),
141}
142
143impl ColorDef {
144 pub fn to_color(&self) -> Color {
146 match self {
147 ColorDef::Named(name) => match name.to_lowercase().as_str() {
148 "black" => Color::Black,
149 "red" => Color::Red,
150 "green" => Color::Green,
151 "yellow" => Color::Yellow,
152 "blue" => Color::Blue,
153 "magenta" => Color::Magenta,
154 "cyan" => Color::Cyan,
155 "gray" | "grey" => Color::Gray,
156 "darkgray" | "dark_gray" | "darkgrey" => Color::DarkGray,
157 "lightgray" | "light_gray" | "lightgrey" => Color::Gray,
158 "darkred" | "dark_red" => Color::Red,
160 "darkgreen" | "dark_green" => Color::Green,
161 "darkyellow" | "dark_yellow" => Color::Yellow,
162 "darkblue" | "dark_blue" => Color::Blue,
163 "darkmagenta" | "dark_magenta" => Color::Magenta,
164 "darkcyan" | "dark_cyan" => Color::Cyan,
165 "lightred" | "light_red" => Color::LightRed,
167 "lightgreen" | "light_green" => Color::LightGreen,
168 "lightyellow" | "light_yellow" => Color::LightYellow,
169 "lightblue" | "light_blue" => Color::LightBlue,
170 "lightmagenta" | "light_magenta" => Color::LightMagenta,
171 "lightcyan" | "light_cyan" => Color::LightCyan,
172 "white" => Color::White,
173 _ => Color::White,
174 },
175 ColorDef::Rgb(r, g, b) => Color::Rgb(*r, *g, *b),
176 ColorDef::Indexed(idx) => Color::Indexed(*idx),
177 }
178 }
179}
180
181impl From<Color> for ColorDef {
182 fn from(color: Color) -> Self {
183 match color {
184 Color::Black => ColorDef::Named("black".to_string()),
185 Color::Red => ColorDef::Named("red".to_string()),
186 Color::Green => ColorDef::Named("green".to_string()),
187 Color::Yellow => ColorDef::Named("yellow".to_string()),
188 Color::Blue => ColorDef::Named("blue".to_string()),
189 Color::Magenta => ColorDef::Named("magenta".to_string()),
190 Color::Cyan => ColorDef::Named("cyan".to_string()),
191 Color::Gray => ColorDef::Named("gray".to_string()),
192 Color::DarkGray => ColorDef::Named("darkgray".to_string()),
193 Color::LightRed => ColorDef::Named("lightred".to_string()),
194 Color::LightGreen => ColorDef::Named("lightgreen".to_string()),
195 Color::LightYellow => ColorDef::Named("lightyellow".to_string()),
196 Color::LightBlue => ColorDef::Named("lightblue".to_string()),
197 Color::LightMagenta => ColorDef::Named("lightmagenta".to_string()),
198 Color::LightCyan => ColorDef::Named("lightcyan".to_string()),
199 Color::White => ColorDef::Named("white".to_string()),
200 Color::Rgb(r, g, b) => ColorDef::Rgb(r, g, b),
201 Color::Indexed(idx) => ColorDef::Indexed(idx),
202 _ => ColorDef::Named("white".to_string()),
203 }
204 }
205}
206
207impl ColorDef {
209 pub fn black() -> Self {
210 ColorDef::Named("black".to_string())
211 }
212 pub fn red() -> Self {
213 ColorDef::Named("red".to_string())
214 }
215 pub fn green() -> Self {
216 ColorDef::Named("green".to_string())
217 }
218 pub fn yellow() -> Self {
219 ColorDef::Named("yellow".to_string())
220 }
221 pub fn blue() -> Self {
222 ColorDef::Named("blue".to_string())
223 }
224 pub fn magenta() -> Self {
225 ColorDef::Named("magenta".to_string())
226 }
227 pub fn cyan() -> Self {
228 ColorDef::Named("cyan".to_string())
229 }
230 pub fn white() -> Self {
231 ColorDef::Named("white".to_string())
232 }
233 pub fn gray() -> Self {
234 ColorDef::Named("gray".to_string())
235 }
236 pub fn dark_gray() -> Self {
237 ColorDef::Named("darkgray".to_string())
238 }
239 pub fn light_gray() -> Self {
240 ColorDef::Named("gray".to_string())
241 }
242}