1use ratatui::style::Color;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct Theme {
7 pub name: String,
8 pub colors: ThemeColors,
9}
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct ThemeColors {
13 pub background: ColorValue,
15 pub foreground: ColorValue,
16
17 pub border: ColorValue,
19 pub border_focused: ColorValue,
20 pub header: ColorValue,
21 pub status_bar: ColorValue,
22
23 pub text_primary: ColorValue,
25 pub text_secondary: ColorValue,
26 pub text_disabled: ColorValue,
27 pub text_highlight: ColorValue,
28
29 pub user_message: ColorValue,
31 pub assistant_message: ColorValue,
32 pub system_message: ColorValue,
33 pub user_message_background: ColorValue,
37
38 pub code_background: ColorValue,
40 pub code_foreground: ColorValue,
41 pub code_keyword: ColorValue,
42 pub code_string: ColorValue,
43 pub code_comment: ColorValue,
44
45 pub mode_normal: ColorValue,
47 pub mode_accept_edits: ColorValue,
48 pub mode_plan: ColorValue,
49 pub mode_bypass_all: ColorValue,
50
51 pub success: ColorValue,
53 pub warning: ColorValue,
54 pub error: ColorValue,
55 pub info: ColorValue,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
59#[serde(untagged)]
60pub enum ColorValue {
61 Rgb { r: u8, g: u8, b: u8 },
62 Named(String),
63}
64
65impl ColorValue {
66 pub fn to_color(&self) -> Color {
67 match self {
68 ColorValue::Rgb { r, g, b } => Color::Rgb(*r, *g, *b),
69 ColorValue::Named(name) => match name.as_str() {
70 "black" => Color::Black,
71 "red" => Color::Red,
72 "green" => Color::Green,
73 "yellow" => Color::Yellow,
74 "blue" => Color::Blue,
75 "magenta" => Color::Magenta,
76 "cyan" => Color::Cyan,
77 "white" => Color::White,
78 "gray" | "grey" => Color::Gray,
79 "dark_gray" | "dark_grey" => Color::DarkGray,
80 _ => Color::White,
81 },
82 }
83 }
84}
85
86impl Theme {
87 pub fn light() -> Self {
94 Self {
95 name: "Light".to_string(),
96 colors: ThemeColors {
97 background: ColorValue::Rgb {
98 r: 250,
99 g: 250,
100 b: 250,
101 },
102 foreground: ColorValue::Rgb {
103 r: 30,
104 g: 30,
105 b: 30,
106 },
107
108 border: ColorValue::Named("gray".to_string()),
109 border_focused: ColorValue::Named("blue".to_string()),
110 header: ColorValue::Named("blue".to_string()),
111 status_bar: ColorValue::Named("white".to_string()),
112
113 text_primary: ColorValue::Named("black".to_string()),
114 text_secondary: ColorValue::Named("dark_gray".to_string()),
115 text_disabled: ColorValue::Named("gray".to_string()),
116 text_highlight: ColorValue::Named("magenta".to_string()),
117
118 user_message: ColorValue::Named("blue".to_string()),
119 assistant_message: ColorValue::Named("green".to_string()),
120 system_message: ColorValue::Named("yellow".to_string()),
121 user_message_background: ColorValue::Rgb {
122 r: 230,
123 g: 230,
124 b: 230,
125 },
126
127 code_background: ColorValue::Rgb {
128 r: 240,
129 g: 240,
130 b: 240,
131 },
132 code_foreground: ColorValue::Named("dark_gray".to_string()),
133 code_keyword: ColorValue::Named("magenta".to_string()),
134 code_string: ColorValue::Named("green".to_string()),
135 code_comment: ColorValue::Named("gray".to_string()),
136
137 mode_normal: ColorValue::Named("green".to_string()),
138 mode_accept_edits: ColorValue::Named("yellow".to_string()),
139 mode_plan: ColorValue::Named("blue".to_string()),
140 mode_bypass_all: ColorValue::Named("red".to_string()),
141
142 success: ColorValue::Named("green".to_string()),
143 warning: ColorValue::Named("yellow".to_string()),
144 error: ColorValue::Named("red".to_string()),
145 info: ColorValue::Named("blue".to_string()),
146 },
147 }
148 }
149
150 pub fn dark() -> Self {
152 Self {
153 name: "Dark".to_string(),
154 colors: ThemeColors {
155 background: ColorValue::Rgb {
156 r: 20,
157 g: 20,
158 b: 20,
159 },
160 foreground: ColorValue::Rgb {
161 r: 230,
162 g: 230,
163 b: 230,
164 },
165
166 border: ColorValue::Named("dark_gray".to_string()),
167 border_focused: ColorValue::Named("cyan".to_string()),
168 header: ColorValue::Named("cyan".to_string()),
169 status_bar: ColorValue::Named("black".to_string()),
170
171 text_primary: ColorValue::Named("white".to_string()),
172 text_secondary: ColorValue::Named("gray".to_string()),
173 text_disabled: ColorValue::Named("dark_gray".to_string()),
174 text_highlight: ColorValue::Named("yellow".to_string()),
175
176 user_message: ColorValue::Named("blue".to_string()),
177 assistant_message: ColorValue::Named("green".to_string()),
178 system_message: ColorValue::Named("yellow".to_string()),
179 user_message_background: ColorValue::Rgb {
180 r: 54,
181 g: 54,
182 b: 54,
183 },
184
185 code_background: ColorValue::Rgb {
186 r: 40,
187 g: 40,
188 b: 40,
189 },
190 code_foreground: ColorValue::Named("gray".to_string()),
191 code_keyword: ColorValue::Named("magenta".to_string()),
192 code_string: ColorValue::Named("green".to_string()),
193 code_comment: ColorValue::Named("dark_gray".to_string()),
194
195 mode_normal: ColorValue::Named("green".to_string()),
196 mode_accept_edits: ColorValue::Named("yellow".to_string()),
197 mode_plan: ColorValue::Named("blue".to_string()),
198 mode_bypass_all: ColorValue::Named("red".to_string()),
199
200 success: ColorValue::Named("green".to_string()),
201 warning: ColorValue::Named("yellow".to_string()),
202 error: ColorValue::Named("red".to_string()),
203 info: ColorValue::Named("cyan".to_string()),
204 },
205 }
206 }
207}