1use crate::canvas_timer::SceneStyle;
2use crate::model::ThemeVariant;
3use ratatui::style::Color;
4
5pub struct Theme {
6 pub bg: Color,
7 pub text: Color,
8 pub dim: Color,
9 pub accent: Color,
10 pub on_accent: Color,
11 pub success: Color,
12 pub warning: Color,
13 pub error: Color,
14 pub info: Color,
15 pub progress_dim: Color,
16 pub task_track: Color,
17 pub panel: Color,
18 pub panel_border: Color,
19 pub select_bg: Color,
20 pub select_fg: Color,
21 pub active_bg: Color,
22 pub active_fg: Color,
23}
24
25impl Theme {
26 pub fn dark() -> Self {
27 Self {
28 bg: Color::Rgb(15, 15, 20),
29 text: Color::Rgb(225, 225, 230),
30 dim: Color::Rgb(90, 90, 100),
31 accent: Color::Rgb(100, 180, 255),
32 on_accent: Color::Rgb(10, 10, 15),
33 success: Color::Rgb(80, 210, 130),
34 warning: Color::Rgb(245, 185, 70),
35 error: Color::Rgb(245, 85, 85),
36 info: Color::Rgb(170, 140, 250),
37 progress_dim: Color::Rgb(45, 45, 55),
38 task_track: Color::Rgb(35, 35, 42),
39 panel: Color::Rgb(20, 22, 30),
40 panel_border: Color::Rgb(55, 60, 75),
41 select_bg: Color::Rgb(38, 52, 78),
42 select_fg: Color::Rgb(230, 235, 245),
43 active_bg: Color::Rgb(32, 48, 72),
44 active_fg: Color::Rgb(170, 210, 255),
45 }
46 }
47
48 pub fn light() -> Self {
49 Self {
50 bg: Color::Rgb(250, 250, 252),
51 text: Color::Rgb(30, 30, 35),
52 dim: Color::Rgb(140, 140, 150),
53 accent: Color::Rgb(25, 110, 200),
54 on_accent: Color::Rgb(255, 255, 255),
55 success: Color::Rgb(30, 150, 80),
56 warning: Color::Rgb(200, 130, 20),
57 error: Color::Rgb(200, 50, 50),
58 info: Color::Rgb(110, 70, 190),
59 progress_dim: Color::Rgb(200, 205, 215),
60 task_track: Color::Rgb(220, 225, 232),
61 panel: Color::Rgb(242, 245, 250),
62 panel_border: Color::Rgb(190, 198, 210),
63 select_bg: Color::Rgb(210, 225, 245),
64 select_fg: Color::Rgb(20, 40, 70),
65 active_bg: Color::Rgb(195, 218, 245),
66 active_fg: Color::Rgb(15, 60, 120),
67 }
68 }
69
70 pub fn polaris() -> Self {
71 Self {
72 bg: Color::Rgb(10, 14, 30),
73 text: Color::Rgb(215, 225, 250),
74 dim: Color::Rgb(100, 120, 160),
75 accent: Color::Rgb(90, 200, 255),
76 on_accent: Color::Rgb(10, 14, 30),
77 success: Color::Rgb(80, 235, 180),
78 warning: Color::Rgb(255, 160, 75),
79 error: Color::Rgb(255, 95, 120),
80 info: Color::Rgb(180, 135, 255),
81 progress_dim: Color::Rgb(40, 50, 80),
82 task_track: Color::Rgb(25, 35, 60),
83 panel: Color::Rgb(14, 20, 38),
84 panel_border: Color::Rgb(55, 70, 110),
85 select_bg: Color::Rgb(28, 42, 78),
86 select_fg: Color::Rgb(210, 225, 255),
87 active_bg: Color::Rgb(22, 38, 68),
88 active_fg: Color::Rgb(140, 210, 255),
89 }
90 }
91
92 pub fn matrix() -> Self {
93 Self {
94 bg: Color::Rgb(3, 12, 5),
95 text: Color::Rgb(150, 240, 140),
96 dim: Color::Rgb(60, 110, 65),
97 accent: Color::Rgb(80, 230, 90),
98 on_accent: Color::Rgb(0, 0, 0),
99 success: Color::Rgb(70, 220, 110),
100 warning: Color::Rgb(220, 200, 60),
101 error: Color::Rgb(255, 80, 90),
102 info: Color::Rgb(100, 190, 240),
103 progress_dim: Color::Rgb(15, 40, 18),
104 task_track: Color::Rgb(8, 28, 10),
105 panel: Color::Rgb(5, 16, 7),
106 panel_border: Color::Rgb(35, 85, 40),
107 select_bg: Color::Rgb(10, 32, 14),
108 select_fg: Color::Rgb(160, 255, 165),
109 active_bg: Color::Rgb(14, 42, 18),
110 active_fg: Color::Rgb(110, 255, 120),
111 }
112 }
113
114 pub fn from_variant(variant: ThemeVariant) -> Self {
115 match variant {
116 ThemeVariant::Dark => Theme::dark(),
117 ThemeVariant::Light => Theme::light(),
118 ThemeVariant::Polaris => Theme::polaris(),
119 ThemeVariant::Matrix => Theme::matrix(),
120 }
121 }
122
123 pub fn scene_style(&self, mode: Color) -> SceneStyle {
125 SceneStyle {
126 mode,
127 track: self.progress_dim,
128 task: self.success,
129 task_dim: self.task_track,
130 bg: self.bg,
131 bg_mid: mix(self.bg, self.panel, 160),
132 bg_light: self.panel,
133 wave: self.accent,
134 core: mode,
135 glow: self.accent,
136 particle: self.dim,
137 text: self.text,
138 session_on: self.accent,
139 session_off: self.dim,
140 }
141 }
142}
143
144fn mix(a: Color, b: Color, t: u8) -> Color {
145 let (ar, ag, ab) = rgb(a);
146 let (br, bg, bb) = rgb(b);
147 let t = t as u16;
148 let inv = 255 - t;
149 Color::Rgb(
150 ((ar as u16 * inv + br as u16 * t) / 255) as u8,
151 ((ag as u16 * inv + bg as u16 * t) / 255) as u8,
152 ((ab as u16 * inv + bb as u16 * t) / 255) as u8,
153 )
154}
155
156fn rgb(c: Color) -> (u8, u8, u8) {
157 match c {
158 Color::Rgb(r, g, b) => (r, g, b),
159 Color::Black => (0, 0, 0),
160 Color::White => (255, 255, 255),
161 _ => (128, 128, 128),
162 }
163}