Skip to main content

tui_kit/
theme.rs

1use ratatui::style::{Color, Modifier, Style};
2
3/// Color and style palette for tui-kit components.
4///
5/// ## Usage
6///
7/// Use [`Theme::native()`] (the default) for a palette that adapts to the
8/// user's terminal color scheme, or [`Theme::dark()`] for a fixed
9/// lazygit-inspired dark palette.
10///
11/// ## Extending for your app
12///
13/// Wrap `Theme` in your own struct for app-specific semantic roles:
14///
15/// ```rust
16/// pub struct AppTheme {
17///     pub base: Theme,            // passed to all tui-kit calls
18///     pub my_semantic: Style,     // app-specific roles
19/// }
20///
21/// impl AppTheme {
22///     pub fn native() -> Self {
23///         Self {
24///             base: Theme::native(),
25///             my_semantic: Style::default().fg(Color::LightGreen),
26///         }
27///     }
28/// }
29/// ```
30///
31/// `Theme` is `Copy` so it is cheap to pass by value or reference.
32#[derive(Debug, Clone, Copy)]
33pub struct Theme {
34    /// Border of the currently-focused interactive panel.
35    pub border_focused: Style,
36    /// Border of passive / display-only panels.
37    pub border_unfocused: Style,
38    /// Border of floating popups (always treated as focused).
39    pub border_popup: Style,
40    /// Border of error popups.
41    pub border_error: Style,
42    /// Border of warning popups.
43    pub border_warning: Style,
44
45    /// Label of the active tab.
46    pub tab_active: Style,
47    /// Label of an inactive tab.
48    pub tab_inactive: Style,
49
50    /// Style applied to the selected row in a list (fg + bg combined).
51    pub selection: Style,
52
53    /// Inline keyboard shortcut labels (e.g. "Enter", "Tab").
54    pub shortcut_key: Style,
55    /// The `-[n]-` digit indicator shown in widget titles.
56    pub shortcut_indicator: Style,
57
58    /// Section / group headers inside popups.
59    pub section_header: Style,
60    /// Normal body text.
61    pub body: Style,
62    /// Dimmed hint and footer text.
63    pub hint: Style,
64    /// Separator lines (─ characters).
65    pub separator: Style,
66
67    /// Positive / success signal (e.g. toast success, CI pass).
68    pub success: Style,
69}
70
71impl Theme {
72    /// 16-color native palette — adapts to the user's terminal color scheme.
73    ///
74    /// Uses only the 16 named ANSI colors so the result respects the terminal
75    /// theme (dark/light, Solarized, Nord, etc.).
76    ///
77    /// | Role               | Color          |
78    /// |--------------------|----------------|
79    /// | Accent / focused   | LightBlue      |
80    /// | Tabs / headers     | LightBlue      |
81    /// | Shortcuts          | Yellow         |
82    /// | Selection          | Black on LightBlue |
83    /// | Positive signal    | LightGreen     |
84    /// | Negative signal    | LightRed       |
85    /// | Muted / hints      | DarkGray       |
86    pub fn native() -> Self {
87        Self {
88            border_focused: Style::default()
89                .fg(Color::LightBlue)
90                .add_modifier(Modifier::BOLD),
91            border_unfocused: Style::default().fg(Color::DarkGray),
92            border_popup: Style::default()
93                .fg(Color::LightBlue)
94                .add_modifier(Modifier::BOLD),
95            border_error: Style::default()
96                .fg(Color::LightRed)
97                .add_modifier(Modifier::BOLD),
98            border_warning: Style::default()
99                .fg(Color::Yellow)
100                .add_modifier(Modifier::BOLD),
101
102            tab_active: Style::default()
103                .fg(Color::LightBlue)
104                .add_modifier(Modifier::BOLD),
105            tab_inactive: Style::default().fg(Color::DarkGray),
106
107            selection: Style::default()
108                .fg(Color::Black)
109                .bg(Color::LightBlue)
110                .add_modifier(Modifier::BOLD),
111
112            shortcut_key: Style::default().fg(Color::Yellow),
113            shortcut_indicator: Style::default()
114                .fg(Color::Yellow)
115                .add_modifier(Modifier::BOLD),
116
117            section_header: Style::default()
118                .fg(Color::LightBlue)
119                .add_modifier(Modifier::BOLD),
120            body: Style::default().fg(Color::Gray),
121            hint: Style::default().fg(Color::DarkGray),
122            separator: Style::default().fg(Color::DarkGray),
123
124            success: Style::default().fg(Color::LightGreen),
125        }
126    }
127
128    /// Fixed dark palette with green accents — does not adapt to terminal theme.
129    ///
130    /// Use when you know the terminal has a dark background and want a
131    /// consistent lazygit-inspired look regardless of terminal settings.
132    ///
133    /// | Role               | Color        |
134    /// |--------------------|--------------|
135    /// | Accent / focused   | Green + Bold |
136    /// | Unfocused border   | White        |
137    /// | Active tab         | Green + Bold |
138    /// | Selection          | White on Blue + Bold |
139    /// | Shortcut keys      | Yellow       |
140    /// | Section headers    | Cyan + Bold  |
141    /// | Hints              | DarkGray     |
142    pub fn dark() -> Self {
143        Self {
144            border_focused: Style::default()
145                .fg(Color::Green)
146                .add_modifier(Modifier::BOLD),
147            border_unfocused: Style::default().fg(Color::White),
148            border_popup: Style::default()
149                .fg(Color::Green)
150                .add_modifier(Modifier::BOLD),
151            border_error: Style::default().fg(Color::Red).add_modifier(Modifier::BOLD),
152            border_warning: Style::default()
153                .fg(Color::Yellow)
154                .add_modifier(Modifier::BOLD),
155
156            tab_active: Style::default()
157                .fg(Color::Green)
158                .add_modifier(Modifier::BOLD),
159            tab_inactive: Style::default().fg(Color::White),
160
161            selection: Style::default()
162                .fg(Color::Indexed(7))
163                .bg(Color::Indexed(6))
164                .add_modifier(Modifier::BOLD),
165
166            shortcut_key: Style::default().fg(Color::Yellow),
167            shortcut_indicator: Style::default()
168                .fg(Color::Yellow)
169                .add_modifier(Modifier::BOLD),
170
171            section_header: Style::default()
172                .fg(Color::Cyan)
173                .add_modifier(Modifier::BOLD),
174            body: Style::default().fg(Color::Gray),
175            hint: Style::default().fg(Color::DarkGray),
176            separator: Style::default().fg(Color::Green),
177
178            success: Style::default().fg(Color::Green),
179        }
180    }
181}
182
183impl Default for Theme {
184    fn default() -> Self {
185        Self::native()
186    }
187}