aranet_cli/tui/ui/
theme.rs

1//! Centralized theme system for the TUI.
2//!
3//! This module provides a consistent color palette and styling based on
4//! Tailwind CSS color conventions for a modern, cohesive look.
5
6use ratatui::style::{Color, Modifier, Style};
7use ratatui::widgets::BorderType;
8
9/// Application theme with all UI colors.
10///
11/// Colors are based on the Tailwind CSS palette for consistency.
12#[derive(Debug, Clone, Copy)]
13pub struct AppTheme {
14    // Primary colors
15    pub primary: Color,
16
17    // Status colors
18    pub success: Color,
19    pub warning: Color,
20    pub danger: Color,
21    pub info: Color,
22
23    // Text colors
24    pub text_primary: Color,
25    pub text_secondary: Color,
26    pub text_muted: Color,
27
28    // Border colors
29    pub border_active: Color,
30    pub border_inactive: Color,
31
32    // Background colors
33    pub bg_selected: Color,
34    pub bg_header: Color,
35}
36
37impl Default for AppTheme {
38    fn default() -> Self {
39        Self::dark()
40    }
41}
42
43impl AppTheme {
44    /// Dark theme using Tailwind-inspired colors.
45    #[must_use]
46    pub const fn dark() -> Self {
47        Self {
48            // Primary: Cyan/Teal
49            primary: Color::Rgb(34, 211, 238), // cyan-400
50
51            // Status colors
52            success: Color::Rgb(74, 222, 128), // green-400
53            warning: Color::Rgb(251, 191, 36), // amber-400
54            danger: Color::Rgb(248, 113, 113), // red-400
55            info: Color::Rgb(96, 165, 250),    // blue-400
56
57            // Text
58            text_primary: Color::Rgb(248, 250, 252), // slate-50
59            text_secondary: Color::Rgb(148, 163, 184), // slate-400
60            text_muted: Color::Rgb(100, 116, 139),   // slate-500
61
62            // Borders
63            border_active: Color::Rgb(34, 211, 238), // cyan-400
64            border_inactive: Color::Rgb(71, 85, 105), // slate-600
65
66            // Backgrounds
67            bg_selected: Color::Rgb(51, 65, 85), // slate-700
68            bg_header: Color::Rgb(30, 41, 59),   // slate-800
69        }
70    }
71
72    /// Light theme using Tailwind-inspired colors.
73    #[must_use]
74    pub const fn light() -> Self {
75        Self {
76            // Primary: Cyan/Teal (darker for light theme)
77            primary: Color::Rgb(6, 182, 212), // cyan-500
78
79            // Status colors (darker for readability)
80            success: Color::Rgb(22, 163, 74), // green-600
81            warning: Color::Rgb(217, 119, 6), // amber-600
82            danger: Color::Rgb(220, 38, 38),  // red-600
83            info: Color::Rgb(37, 99, 235),    // blue-600
84
85            // Text (dark for light backgrounds)
86            text_primary: Color::Rgb(15, 23, 42),    // slate-900
87            text_secondary: Color::Rgb(71, 85, 105), // slate-600
88            text_muted: Color::Rgb(148, 163, 184),   // slate-400
89
90            // Borders
91            border_active: Color::Rgb(6, 182, 212), // cyan-500
92            border_inactive: Color::Rgb(203, 213, 225), // slate-300
93
94            // Backgrounds
95            bg_selected: Color::Rgb(226, 232, 240), // slate-200
96            bg_header: Color::Rgb(241, 245, 249),   // slate-100
97        }
98    }
99
100    // Style helpers
101
102    /// Style for active/focused borders.
103    #[inline]
104    #[must_use]
105    pub fn border_active_style(&self) -> Style {
106        Style::default().fg(self.border_active)
107    }
108
109    /// Style for inactive borders.
110    #[inline]
111    #[must_use]
112    pub fn border_inactive_style(&self) -> Style {
113        Style::default().fg(self.border_inactive)
114    }
115
116    /// Style for selected items (inverted/highlighted).
117    #[inline]
118    #[must_use]
119    pub fn selected_style(&self) -> Style {
120        Style::default()
121            .bg(self.bg_selected)
122            .fg(self.text_primary)
123            .add_modifier(Modifier::BOLD)
124    }
125
126    /// Style for titles.
127    #[inline]
128    #[must_use]
129    pub fn title_style(&self) -> Style {
130        Style::default()
131            .fg(self.primary)
132            .add_modifier(Modifier::BOLD)
133    }
134
135    /// Style for header/app bar.
136    #[inline]
137    #[must_use]
138    pub fn header_style(&self) -> Style {
139        Style::default().bg(self.bg_header)
140    }
141}
142
143/// Default border type for all blocks (rounded for modern look).
144pub const BORDER_TYPE: BorderType = BorderType::Rounded;