1use crate::style::{Color, Style};
4use alloc::string::String;
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23pub struct Theme {
24 pub name: String,
26 pub palette: PaletteTheme,
28 pub widgets: WidgetTheme,
30}
31
32impl Theme {
33 #[must_use]
35 pub fn new(name: impl Into<String>) -> Self {
36 Self {
37 name: name.into(),
38 palette: PaletteTheme::default(),
39 widgets: WidgetTheme::default(),
40 }
41 }
42
43 #[must_use]
45 pub fn dark() -> Self {
46 Self {
47 name: String::from("dark"),
48 palette: PaletteTheme {
49 background: Color::Black,
50 foreground: Color::White,
51 primary: Color::Blue,
52 secondary: Color::Cyan,
53 accent: Color::Magenta,
54 error: Color::Red,
55 warning: Color::Yellow,
56 success: Color::Green,
57 muted: Color::Gray,
58 },
59 widgets: WidgetTheme::default(),
60 }
61 }
62
63 #[must_use]
65 pub fn light() -> Self {
66 Self {
67 name: String::from("light"),
68 palette: PaletteTheme {
69 background: Color::White,
70 foreground: Color::Black,
71 primary: Color::Blue,
72 secondary: Color::Cyan,
73 accent: Color::Magenta,
74 error: Color::Red,
75 warning: Color::Yellow,
76 success: Color::Green,
77 muted: Color::Gray,
78 },
79 widgets: WidgetTheme::default(),
80 }
81 }
82
83 #[must_use]
85 pub fn high_contrast() -> Self {
86 Self {
87 name: String::from("high-contrast"),
88 palette: PaletteTheme {
89 background: Color::Black,
90 foreground: Color::White,
91 primary: Color::LightBlue,
92 secondary: Color::LightCyan,
93 accent: Color::LightMagenta,
94 error: Color::LightRed,
95 warning: Color::LightYellow,
96 success: Color::LightGreen,
97 muted: Color::LightGray,
98 },
99 widgets: WidgetTheme::default(),
100 }
101 }
102}
103
104impl Default for Theme {
105 fn default() -> Self {
106 Self::dark()
107 }
108}
109
110#[derive(Debug, Clone, PartialEq, Eq)]
112#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
113pub struct PaletteTheme {
114 pub background: Color,
116 pub foreground: Color,
118 pub primary: Color,
120 pub secondary: Color,
122 pub accent: Color,
124 pub error: Color,
126 pub warning: Color,
128 pub success: Color,
130 pub muted: Color,
132}
133
134impl Default for PaletteTheme {
135 fn default() -> Self {
136 Self {
137 background: Color::Black,
138 foreground: Color::White,
139 primary: Color::Blue,
140 secondary: Color::Cyan,
141 accent: Color::Magenta,
142 error: Color::Red,
143 warning: Color::Yellow,
144 success: Color::Green,
145 muted: Color::Gray,
146 }
147 }
148}
149
150#[derive(Debug, Clone, PartialEq, Eq)]
152#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
153pub struct WidgetTheme {
154 pub block: Style,
156 pub selected: Style,
158 pub highlighted: Style,
160 pub active: Style,
162 pub inactive: Style,
164}
165
166impl Default for WidgetTheme {
167 fn default() -> Self {
168 Self {
169 block: Style::new().fg(Color::White),
170 selected: Style::new().fg(Color::Black).bg(Color::White),
171 highlighted: Style::new().fg(Color::Yellow),
172 active: Style::new().fg(Color::Green),
173 inactive: Style::new().fg(Color::Gray),
174 }
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181
182 #[test]
183 fn test_theme_creation() {
184 let theme = Theme::dark();
185 assert_eq!(theme.name, "dark");
186 assert_eq!(theme.palette.background, Color::Black);
187 }
188
189 #[test]
190 fn test_light_theme() {
191 let theme = Theme::light();
192 assert_eq!(theme.palette.background, Color::White);
193 }
194
195 #[cfg(feature = "serde")]
196 #[test]
197 fn test_theme_serialization() {
198 let theme = Theme::dark();
199 let json = serde_json::to_string(&theme).unwrap();
200 let deserialized: Theme = serde_json::from_str(&json).unwrap();
201 assert_eq!(theme, deserialized);
202 }
203}