Skip to main content

iris_hub/ui/
theme.rs

1//! # Theme Module
2//! 
3//! Configurações de tema e estilo visual da aplicação Iris.
4//! Define cores, espaçamentos e estilos visuais.
5
6use eframe::egui::{self, Color32, Rounding, Margin, Stroke};
7
8/// Cores do tema escuro da aplicação
9pub struct ThemeColors;
10
11impl ThemeColors {
12    // Cores de fundo
13    pub const BG_DARK: Color32 = Color32::from_rgb(18, 18, 22);
14    pub const BG_HEADER: Color32 = Color32::from_rgb(22, 22, 26);
15    pub const BG_CARD: Color32 = Color32::from_rgb(32, 32, 38);
16    pub const BG_CARD_HOVER: Color32 = Color32::from_rgb(38, 38, 45);
17    pub const BG_INPUT: Color32 = Color32::from_rgb(38, 38, 45);
18    pub const BG_ICON: Color32 = Color32::from_rgb(45, 45, 52);
19    
20    // Cores de estado - Executando
21    pub const RUNNING_BG: Color32 = Color32::from_rgb(25, 35, 30);
22    pub const RUNNING_BORDER: Color32 = Color32::from_rgb(34, 197, 94);
23    pub const RUNNING_BADGE_BG: Color32 = Color32::from_rgb(34, 55, 40);
24    pub const RUNNING_TEXT: Color32 = Color32::from_rgb(80, 220, 120);
25    
26    // Cores de estado - Loading
27    pub const LOADING_BG: Color32 = Color32::from_rgb(25, 30, 40);
28    pub const LOADING_BORDER: Color32 = Color32::from_rgb(99, 102, 241);
29    
30    // Cores de botões
31    pub const BTN_PRIMARY: Color32 = Color32::from_rgb(99, 102, 241);  // Indigo
32    pub const BTN_DANGER: Color32 = Color32::from_rgb(239, 68, 68);   // Vermelho
33    pub const BTN_WARNING: Color32 = Color32::from_rgb(245, 158, 11); // Amarelo
34    pub const BTN_DELETE: Color32 = Color32::from_rgb(180, 80, 80);
35    pub const BTN_DELETE_BG: Color32 = Color32::from_rgb(60, 40, 40);
36    
37    // Cores de texto
38    pub const TEXT_PRIMARY: Color32 = Color32::WHITE;
39    pub const TEXT_SECONDARY: Color32 = Color32::from_rgb(160, 160, 170);
40    pub const TEXT_MUTED: Color32 = Color32::from_rgb(100, 100, 110);
41    pub const TEXT_SUBTLE: Color32 = Color32::from_rgb(80, 80, 90);
42    
43    // Cores de borda
44    pub const BORDER_DEFAULT: Color32 = Color32::from_rgb(55, 55, 62);
45}
46
47/// Configurações de espaçamento
48pub struct ThemeSpacing;
49
50impl ThemeSpacing {
51    pub const CARD_WIDTH: f32 = 250.0;
52    pub const CARD_HEIGHT: f32 = 240.0;
53    pub const CARD_PADDING: f32 = 18.0;
54    pub const CARD_ROUNDING: f32 = 16.0;
55    pub const CARD_GRID_SPACING: f32 = 16.0;
56    
57    pub const BUTTON_ROUNDING: f32 = 10.0;
58    pub const BUTTON_HEIGHT: f32 = 36.0;
59    
60    pub const ICON_SIZE: f32 = 32.0;
61    pub const ICON_CONTAINER_SIZE: f32 = 44.0;
62}
63
64/// Aplica o tema visual ao contexto egui
65pub fn apply_theme(ctx: &egui::Context) {
66    let mut visuals = egui::Visuals::dark();
67    
68    visuals.window_rounding = Rounding::same(12.0);
69    visuals.window_shadow = egui::epaint::Shadow {
70        offset: egui::vec2(0.0, 8.0),
71        blur: 24.0,
72        spread: 0.0,
73        color: Color32::from_black_alpha(100),
74    };
75    visuals.popup_shadow = visuals.window_shadow;
76    
77    visuals.widgets.noninteractive.bg_fill = Color32::from_rgb(28, 28, 32);
78    visuals.widgets.inactive.bg_fill = Color32::from_rgb(45, 45, 50);
79    visuals.widgets.inactive.weak_bg_fill = Color32::from_rgb(45, 45, 50);
80    visuals.widgets.hovered.bg_fill = Color32::from_rgb(60, 60, 68);
81    visuals.widgets.active.bg_fill = Color32::from_rgb(70, 70, 78);
82    visuals.selection.bg_fill = Color32::from_rgb(0, 120, 215);
83    visuals.extreme_bg_color = Color32::from_rgb(20, 20, 24);
84    visuals.faint_bg_color = Color32::from_rgb(35, 35, 40);
85    
86    ctx.set_visuals(visuals);
87    
88    // Configurar estilo
89    let mut style = (*ctx.style()).clone();
90    style.spacing.item_spacing = egui::vec2(10.0, 8.0);
91    style.spacing.button_padding = egui::vec2(12.0, 6.0);
92    style.spacing.window_margin = Margin::same(16.0);
93    style.visuals.widgets.noninteractive.rounding = Rounding::same(8.0);
94    style.visuals.widgets.inactive.rounding = Rounding::same(8.0);
95    style.visuals.widgets.hovered.rounding = Rounding::same(8.0);
96    style.visuals.widgets.active.rounding = Rounding::same(8.0);
97    ctx.set_style(style);
98}
99
100/// Retorna as cores do card baseadas no estado
101pub fn get_card_colors(is_running: bool, is_loading: bool) -> (Color32, Color32, Color32) {
102    if is_running {
103        (
104            ThemeColors::RUNNING_BG,
105            ThemeColors::RUNNING_BORDER,
106            Color32::from_rgba_unmultiplied(34, 197, 94, 30),
107        )
108    } else if is_loading {
109        (
110            ThemeColors::LOADING_BG,
111            ThemeColors::LOADING_BORDER,
112            Color32::from_rgba_unmultiplied(99, 102, 241, 30),
113        )
114    } else {
115        (
116            ThemeColors::BG_CARD,
117            ThemeColors::BORDER_DEFAULT,
118            Color32::TRANSPARENT,
119        )
120    }
121}
122
123/// Cria um frame estilizado para cards
124pub fn card_frame(bg_color: Color32, border_color: Color32, glow_color: Color32) -> egui::Frame {
125    egui::Frame::none()
126        .fill(bg_color)
127        .rounding(ThemeSpacing::CARD_ROUNDING)
128        .inner_margin(Margin::same(ThemeSpacing::CARD_PADDING))
129        .stroke(Stroke::new(1.5, border_color))
130        .shadow(egui::epaint::Shadow {
131            offset: egui::vec2(0.0, 4.0),
132            blur: 12.0,
133            spread: 0.0,
134            color: glow_color,
135        })
136}
137
138/// Cria um botão primário estilizado
139pub fn primary_button(text: &str) -> egui::Button<'_> {
140    egui::Button::new(
141        egui::RichText::new(text)
142            .size(14.0)
143            .color(ThemeColors::TEXT_PRIMARY),
144    )
145    .fill(ThemeColors::BTN_PRIMARY)
146    .rounding(ThemeSpacing::BUTTON_ROUNDING)
147}
148
149/// Cria um botão de ação (danger/warning)
150pub fn action_button(text: &str, color: Color32) -> egui::Button<'_> {
151    egui::Button::new(
152        egui::RichText::new(text)
153            .size(12.0)
154            .color(ThemeColors::TEXT_PRIMARY),
155    )
156    .fill(color)
157    .rounding(ThemeSpacing::BUTTON_ROUNDING)
158}