A simple TUI Library written in Rust
at main 120 lines 3.1 kB view raw
1use crate::color::Color; 2use crate::style::Style; 3 4/// A named palette of semantic colors for consistent styling. 5/// Pass a `&Theme` through rendering functions — no global state. 6#[derive(Debug, Clone)] 7pub struct Theme { 8 pub primary: Color, 9 pub secondary: Color, 10 pub success: Color, 11 pub warning: Color, 12 pub error: Color, 13 pub muted: Color, 14 pub border: Color, 15 pub text: Color, 16} 17 18impl Theme { 19 /// Default theme suitable for most terminals. 20 pub fn default_theme() -> Self { 21 Theme { 22 primary: Color::Cyan, 23 secondary: Color::Blue, 24 success: Color::Green, 25 warning: Color::Yellow, 26 error: Color::Red, 27 muted: Color::BrightBlack, 28 border: Color::White, 29 text: Color::Default, 30 } 31 } 32 33 /// Dark theme with higher contrast accents. 34 pub fn dark() -> Self { 35 Theme { 36 primary: Color::BrightCyan, 37 secondary: Color::BrightBlue, 38 success: Color::BrightGreen, 39 warning: Color::BrightYellow, 40 error: Color::BrightRed, 41 muted: Color::BrightBlack, 42 border: Color::BrightBlack, 43 text: Color::BrightWhite, 44 } 45 } 46 47 /// Light theme (for terminals with white backgrounds). 48 pub fn light() -> Self { 49 Theme { 50 primary: Color::Blue, 51 secondary: Color::Magenta, 52 success: Color::Green, 53 warning: Color::Yellow, 54 error: Color::Red, 55 muted: Color::Black, 56 border: Color::Black, 57 text: Color::Black, 58 } 59 } 60 61 // --- Style helpers --- 62 63 pub fn primary_style(&self) -> Style { 64 Style::new().fg(self.primary.clone()) 65 } 66 67 pub fn success_style(&self) -> Style { 68 Style::new().fg(self.success.clone()) 69 } 70 71 pub fn warning_style(&self) -> Style { 72 Style::new().fg(self.warning.clone()) 73 } 74 75 pub fn error_style(&self) -> Style { 76 Style::new().fg(self.error.clone()) 77 } 78 79 pub fn muted_style(&self) -> Style { 80 Style::new().fg(self.muted.clone()).dim() 81 } 82 83 pub fn border_style(&self) -> Style { 84 Style::new().fg(self.border.clone()) 85 } 86} 87 88impl Default for Theme { 89 fn default() -> Self { 90 Self::default_theme() 91 } 92} 93 94#[cfg(test)] 95mod tests { 96 use super::*; 97 98 #[test] 99 fn default_theme_has_expected_colors() { 100 let t = Theme::default_theme(); 101 assert_eq!(t.primary, Color::Cyan); 102 assert_eq!(t.success, Color::Green); 103 assert_eq!(t.error, Color::Red); 104 } 105 106 #[test] 107 fn dark_theme_is_bright() { 108 let t = Theme::dark(); 109 assert_eq!(t.primary, Color::BrightCyan); 110 assert_eq!(t.success, Color::BrightGreen); 111 } 112 113 #[test] 114 fn style_helpers_produce_styles() { 115 let t = Theme::default_theme(); 116 assert_eq!(t.primary_style().fg, Some(Color::Cyan)); 117 assert_eq!(t.error_style().fg, Some(Color::Red)); 118 assert!(t.muted_style().dim); 119 } 120}