ratkit 0.2.14

A comprehensive collection of reusable TUI components for ratatui including resizable splits, tree views, markdown rendering, toast notifications, dialogs, and terminal embedding
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
use crate::widgets::markdown_preview::services::theme::ThemeVariant;
/// Application theme module for comprehensive TUI theming.
///
/// This module provides [`AppTheme`] which is the main theme struct that
/// contains all colors needed for a complete TUI application, including
/// UI colors, text colors, background colors, border colors, and specialized
/// color sets for diffs, markdown, and syntax highlighting.
///
/// # Color Categories
///
/// The theme is organized into logical categories:
///
/// - **UI Colors**: `primary`, `secondary`, `accent`, `error`, `warning`, `success`, `info`
/// - **Text Colors**: `text`, `text_muted`, `selected_text`
/// - **Background Colors**: `background`, `background_panel`, `background_element`, `background_menu`
/// - **Border Colors**: `border`, `border_active`, `border_subtle`
/// - **Specialized**: [`DiffColors`], [`MarkdownColors`], [`SyntaxColors`]
///
/// # Loading Themes
///
/// Themes can be loaded from JSON files in the opencode format using the
/// [`loader`](crate::widgets::markdown_preview::services::theme::loader) module.
///
/// # Example
///
/// ```rust,ignore
/// use ratatui_toolkit::services::theme::{AppTheme, ThemeVariant};
///
/// // Use default theme
/// let theme = AppTheme::default();
///
/// // Access UI colors
/// let primary = theme.primary;
/// let error = theme.error;
///
/// // Access specialized colors
/// let diff_added = theme.diff.added;
/// let heading_color = theme.markdown.heading;
/// ```
use ratatui::style::Color;

use crate::widgets::markdown_preview::services::theme::diff_colors::DiffColors;
use crate::widgets::markdown_preview::services::theme::markdown_colors::MarkdownColors;
use crate::widgets::markdown_preview::services::theme::syntax_colors::SyntaxColors;

/// Comprehensive application theme with all widget colors.
///
/// This struct provides a complete color scheme for TUI applications,
/// covering all common UI elements and specialized widget colors.
///
/// # Theme Structure
///
/// The theme is organized into:
///
/// 1. **UI Colors** - Semantic colors for interactive elements
/// 2. **Text Colors** - Colors for text content
/// 3. **Background Colors** - Surface and container backgrounds
/// 4. **Border Colors** - Border and divider colors
/// 5. **Diff Colors** - Colors for diff rendering
/// 6. **Markdown Colors** - Colors for markdown content
/// 7. **Syntax Colors** - Colors for code syntax highlighting
///
/// # Loading from JSON
///
/// Use [`AppTheme::from_json`] or the loader module to load themes
/// from opencode-format JSON files.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AppTheme {
    // ========== UI Colors ==========
    /// Primary UI color for main interactive elements.
    ///
    /// Used for primary buttons, active selections, and key UI elements.
    pub primary: Color,

    /// Secondary UI color for supporting elements.
    ///
    /// Used for secondary buttons and less prominent interactive elements.
    pub secondary: Color,

    /// Accent color for highlighting and emphasis.
    ///
    /// Used to draw attention to specific UI elements.
    pub accent: Color,

    /// Error color for error states and messages.
    ///
    /// Used for error indicators, validation errors, and destructive actions.
    pub error: Color,

    /// Warning color for warning states and messages.
    ///
    /// Used for warnings and caution indicators.
    pub warning: Color,

    /// Success color for success states and messages.
    ///
    /// Used for success indicators and confirmation feedback.
    pub success: Color,

    /// Info color for informational elements.
    ///
    /// Used for help text, hints, and informational messages.
    pub info: Color,

    // ========== Text Colors ==========
    /// Primary text color for main content.
    ///
    /// The default color for body text and content.
    pub text: Color,

    /// Muted text color for secondary content.
    ///
    /// Used for less important text, placeholders, and hints.
    pub text_muted: Color,

    /// Text color for selected items.
    ///
    /// Used for text within selected or highlighted regions.
    pub selected_text: Color,

    // ========== Background Colors ==========
    /// Main background color.
    ///
    /// The primary application background.
    pub background: Color,

    /// Panel background color.
    ///
    /// Used for content panels and cards.
    pub background_panel: Color,

    /// Element background color.
    ///
    /// Used for interactive elements like buttons and inputs.
    pub background_element: Color,

    /// Menu background color.
    ///
    /// Used for dropdown menus and popover backgrounds.
    pub background_menu: Color,

    // ========== Border Colors ==========
    /// Default border color.
    ///
    /// Used for container borders and dividers.
    pub border: Color,

    /// Active border color.
    ///
    /// Used for focused or active element borders.
    pub border_active: Color,

    /// Subtle border color.
    ///
    /// Used for subtle dividers and less prominent borders.
    pub border_subtle: Color,

    // ========== Specialized Color Sets ==========
    /// Colors for diff rendering.
    ///
    /// Contains all colors needed for the CodeDiff widget.
    pub diff: DiffColors,

    /// Colors for markdown rendering.
    ///
    /// Contains all colors needed for the MarkdownWidget.
    pub markdown: MarkdownColors,

    /// Colors for syntax highlighting.
    ///
    /// Contains all colors needed for code syntax highlighting.
    pub syntax: SyntaxColors,
}

/// JSON constructor for [`AppTheme`].
use std::path::Path;

use crate::widgets::markdown_preview::services::theme::loader::{load_theme_file, load_theme_str};

impl AppTheme {
    /// Creates an [`AppTheme`] from a JSON string in opencode format.
    ///
    /// This parses the JSON, resolves all color references from the `defs`
    /// section, and constructs a complete theme.
    ///
    /// # Arguments
    ///
    /// * `json` - The JSON string in opencode theme format
    /// * `variant` - Which theme variant (dark/light) to use
    ///
    /// # Returns
    ///
    /// `Ok(AppTheme)` if parsing succeeds, `Err` with a description otherwise.
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - The JSON is malformed
    /// - Color values cannot be resolved
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// use ratatui_toolkit::services::theme::{AppTheme, ThemeVariant};
    ///
    /// let json = r#"{
    ///   "defs": { "myBlue": "#0066ff" },
    ///   "theme": { "primary": { "dark": "myBlue", "light": "myBlue" } }
    /// }"#;
    ///
    /// let theme = AppTheme::from_json(json, ThemeVariant::Dark)
    ///     .expect("Failed to parse theme");
    /// ```
    pub fn from_json(json: &str, variant: ThemeVariant) -> Result<Self, String> {
        load_theme_str(json, variant)
    }

    /// Creates an [`AppTheme`] from a JSON file path.
    ///
    /// Reads the file and parses it as an opencode theme.
    ///
    /// # Arguments
    ///
    /// * `path` - Path to the JSON theme file
    /// * `variant` - Which theme variant (dark/light) to use
    ///
    /// # Returns
    ///
    /// `Ok(AppTheme)` if the file can be read and parsed,
    /// `Err` with a description otherwise.
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - The file cannot be read
    /// - The JSON is malformed
    /// - Color values cannot be resolved
    ///
    /// # Example
    ///
    /// ```rust,ignore,no_run
    /// use ratatui_toolkit::services::theme::{AppTheme, ThemeVariant};
    ///
    /// let theme = AppTheme::from_json_file("themes/gruvbox.json", ThemeVariant::Dark)
    ///     .expect("Failed to load theme");
    /// ```
    pub fn from_json_file<P: AsRef<Path>>(path: P, variant: ThemeVariant) -> Result<Self, String> {
        load_theme_file(path, variant)
    }
}

/// New constructor for [`AppTheme`].

impl AppTheme {
    /// Creates a new [`AppTheme`] with all colors specified.
    ///
    /// This is a low-level constructor that requires all colors to be provided.
    /// For most use cases, prefer [`AppTheme::default()`] or [`AppTheme::from_json()`].
    ///
    /// # Arguments
    ///
    /// * `primary` - Primary UI color
    /// * `secondary` - Secondary UI color
    /// * `accent` - Accent color
    /// * `error` - Error color
    /// * `warning` - Warning color
    /// * `success` - Success color
    /// * `info` - Info color
    /// * `text` - Primary text color
    /// * `text_muted` - Muted text color
    /// * `selected_text` - Selected text color
    /// * `background` - Main background color
    /// * `background_panel` - Panel background color
    /// * `background_element` - Element background color
    /// * `background_menu` - Menu background color
    /// * `border` - Default border color
    /// * `border_active` - Active border color
    /// * `border_subtle` - Subtle border color
    /// * `diff` - Diff colors
    /// * `markdown` - Markdown colors
    /// * `syntax` - Syntax colors
    ///
    /// # Returns
    ///
    /// A new `AppTheme` instance with all colors configured.
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// use ratatui::style::Color;
    /// use ratatui_toolkit::services::theme::{AppTheme, DiffColors, MarkdownColors, SyntaxColors};
    ///
    /// let theme = AppTheme::new(
    ///     Color::Blue, Color::Magenta, Color::Cyan,
    ///     Color::Red, Color::Yellow, Color::Green, Color::LightBlue,
    ///     Color::White, Color::Gray, Color::White,
    ///     Color::Black, Color::DarkGray, Color::DarkGray, Color::DarkGray,
    ///     Color::Gray, Color::White, Color::DarkGray,
    ///     DiffColors::default(),
    ///     MarkdownColors::default(),
    ///     SyntaxColors::default(),
    /// );
    /// ```
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        primary: Color,
        secondary: Color,
        accent: Color,
        error: Color,
        warning: Color,
        success: Color,
        info: Color,
        text: Color,
        text_muted: Color,
        selected_text: Color,
        background: Color,
        background_panel: Color,
        background_element: Color,
        background_menu: Color,
        border: Color,
        border_active: Color,
        border_subtle: Color,
        diff: DiffColors,
        markdown: MarkdownColors,
        syntax: SyntaxColors,
    ) -> Self {
        Self {
            primary,
            secondary,
            accent,
            error,
            warning,
            success,
            info,
            text,
            text_muted,
            selected_text,
            background,
            background_panel,
            background_element,
            background_menu,
            border,
            border_active,
            border_subtle,
            diff,
            markdown,
            syntax,
        }
    }
}

/// Color resolution methods for [`AppTheme`].

impl AppTheme {
    /// Gets a semantic color by name.
    ///
    /// This method allows looking up theme colors by their semantic name,
    /// which is useful for dynamic color resolution from configuration.
    ///
    /// # Arguments
    ///
    /// * `name` - The semantic name of the color (e.g., "primary", "error")
    ///
    /// # Returns
    ///
    /// `Some(Color)` if the name matches a known semantic color,
    /// `None` otherwise.
    ///
    /// # Supported Names
    ///
    /// - UI: `primary`, `secondary`, `accent`, `error`, `warning`, `success`, `info`
    /// - Text: `text`, `text_muted`, `selected_text`
    /// - Background: `background`, `background_panel`, `background_element`, `background_menu`
    /// - Border: `border`, `border_active`, `border_subtle`
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// use ratatui_toolkit::services::theme::AppTheme;
    ///
    /// let theme = AppTheme::default();
    /// let primary = theme.get_color("primary");
    /// assert!(primary.is_some());
    /// ```
    pub fn get_color(&self, name: &str) -> Option<Color> {
        match name {
            // UI colors
            "primary" => Some(self.primary),
            "secondary" => Some(self.secondary),
            "accent" => Some(self.accent),
            "error" => Some(self.error),
            "warning" => Some(self.warning),
            "success" => Some(self.success),
            "info" => Some(self.info),
            // Text colors
            "text" => Some(self.text),
            "text_muted" | "textMuted" => Some(self.text_muted),
            "selected_text" | "selectedText" => Some(self.selected_text),
            // Background colors
            "background" => Some(self.background),
            "background_panel" | "backgroundPanel" => Some(self.background_panel),
            "background_element" | "backgroundElement" => Some(self.background_element),
            "background_menu" | "backgroundMenu" => Some(self.background_menu),
            // Border colors
            "border" => Some(self.border),
            "border_active" | "borderActive" => Some(self.border_active),
            "border_subtle" | "borderSubtle" => Some(self.border_subtle),
            _ => None,
        }
    }
}

/// Default trait implementation for [`AppTheme`].

impl Default for AppTheme {
    /// Creates a default application theme based on the Gruvbox dark theme.
    ///
    /// This provides a cohesive dark theme that works well in most terminals
    /// and provides good contrast and readability.
    ///
    /// # Returns
    ///
    /// An `AppTheme` instance with Gruvbox dark colors.
    fn default() -> Self {
        Self {
            // UI colors
            primary: Color::Rgb(131, 165, 152), // gruvbox bright blue
            secondary: Color::Rgb(211, 134, 155), // gruvbox bright purple
            accent: Color::Rgb(142, 192, 124),  // gruvbox bright aqua
            error: Color::Rgb(251, 73, 52),     // gruvbox bright red
            warning: Color::Rgb(254, 128, 25),  // gruvbox bright orange
            success: Color::Rgb(184, 187, 38),  // gruvbox bright green
            info: Color::Rgb(250, 189, 47),     // gruvbox bright yellow

            // Text colors
            text: Color::Rgb(235, 219, 178),          // gruvbox fg1
            text_muted: Color::Rgb(146, 131, 116),    // gruvbox gray
            selected_text: Color::Rgb(251, 241, 199), // gruvbox fg0

            // Background colors
            background: Color::Rgb(40, 40, 40), // gruvbox bg0
            background_panel: Color::Rgb(60, 56, 54), // gruvbox bg1
            background_element: Color::Rgb(80, 73, 69), // gruvbox bg2
            background_menu: Color::Rgb(60, 56, 54), // gruvbox bg1

            // Border colors
            border: Color::Rgb(102, 92, 84),          // gruvbox bg3
            border_active: Color::Rgb(235, 219, 178), // gruvbox fg1
            border_subtle: Color::Rgb(80, 73, 69),    // gruvbox bg2

            // Specialized colors
            diff: DiffColors::default(),
            markdown: MarkdownColors::default(),
            syntax: SyntaxColors::default(),
        }
    }
}