diff --git a/crates/mbr-tui/src/components/content.rs b/crates/mbr-tui/src/components/content.rs index 0c7c40c..804005a 100644 --- a/crates/mbr-tui/src/components/content.rs +++ b/crates/mbr-tui/src/components/content.rs @@ -14,6 +14,7 @@ use ratatui::{ use mbr_core::api::models::{CollectionItem, Database, Question, TableInfo}; use super::state_renderer::{LoadStateConfig, render_non_loaded_state}; +use super::styles::{HIGHLIGHT_SYMBOL, border_style, header_style, row_highlight_style}; use super::{Component, ScrollState}; use crate::layout::questions_table::{COLLECTION_WIDTH, ID_WIDTH, NAME_MIN_WIDTH}; use crate::service::LoadState; @@ -2256,8 +2257,6 @@ impl ContentPanel { _ => return, }; - let border_style = config.border_style; - if collections.is_empty() { super::state_renderer::render_empty( frame, @@ -2298,26 +2297,17 @@ impl ContentPanel { ) .header( Row::new(vec!["ID", "Name", "Location", "Description"]) - .style( - Style::default() - .fg(Color::Yellow) - .add_modifier(Modifier::BOLD), - ) + .style(header_style()) .bottom_margin(1), ) .block( Block::default() .title(format!(" Collections ({}) ", collections.len())) .borders(Borders::ALL) - .border_style(border_style), + .border_style(border_style(focused)), ) - .row_highlight_style( - Style::default() - .fg(Color::Black) - .bg(Color::Cyan) - .add_modifier(Modifier::BOLD), - ) - .highlight_symbol("► "); + .row_highlight_style(row_highlight_style()) + .highlight_symbol(HIGHLIGHT_SYMBOL); frame.render_stateful_widget(table, area, &mut self.collections_table_state); } @@ -2339,8 +2329,6 @@ impl ContentPanel { _ => return, }; - let border_style = config.border_style; - if databases.is_empty() { super::state_renderer::render_empty( frame, @@ -2379,26 +2367,17 @@ impl ContentPanel { ) .header( Row::new(vec!["ID", "Name", "Engine", "Description"]) - .style( - Style::default() - .fg(Color::Yellow) - .add_modifier(Modifier::BOLD), - ) + .style(header_style()) .bottom_margin(1), ) .block( Block::default() .title(format!(" Databases ({}) ", databases.len())) .borders(Borders::ALL) - .border_style(border_style), + .border_style(border_style(focused)), ) - .row_highlight_style( - Style::default() - .fg(Color::Black) - .bg(Color::Cyan) - .add_modifier(Modifier::BOLD), - ) - .highlight_symbol("► "); + .row_highlight_style(row_highlight_style()) + .highlight_symbol(HIGHLIGHT_SYMBOL); frame.render_stateful_widget(table, area, &mut self.databases_table_state); } @@ -2406,11 +2385,7 @@ impl ContentPanel { /// Render collection questions view with table. /// Shows questions filtered by a specific collection. fn render_collection_questions(&mut self, area: Rect, frame: &mut Frame, focused: bool) { - let border_style = if focused { - Style::default().fg(Color::Cyan) - } else { - Style::default().fg(Color::DarkGray) - }; + let border_style = border_style(focused); // Get collection name from ContentView variant let collection_name = match &self.view { diff --git a/crates/mbr-tui/src/components/mod.rs b/crates/mbr-tui/src/components/mod.rs index beb02c1..5c55320 100644 --- a/crates/mbr-tui/src/components/mod.rs +++ b/crates/mbr-tui/src/components/mod.rs @@ -11,6 +11,7 @@ mod help_overlay; mod record_detail; pub mod state_renderer; mod status_bar; +pub mod styles; pub use content::{ContentPanel, ContentView, InputMode, QueryResultData}; pub use help_overlay::HelpOverlay; diff --git a/crates/mbr-tui/src/components/styles.rs b/crates/mbr-tui/src/components/styles.rs new file mode 100644 index 0000000..1ceb957 --- /dev/null +++ b/crates/mbr-tui/src/components/styles.rs @@ -0,0 +1,135 @@ +//! Shared style definitions for TUI components. +//! +//! This module provides consistent styling across all TUI views, +//! eliminating duplication and ensuring visual consistency. +//! +//! Some styles are reserved for future View refactoring (PR 5, 6). + +#![allow(dead_code)] + +use ratatui::style::{Color, Modifier, Style}; + +// === Border Styles === + +/// Border style for focused components. +pub const BORDER_FOCUSED: Style = Style::new().fg(Color::Cyan); + +/// Border style for unfocused components. +pub const BORDER_UNFOCUSED: Style = Style::new().fg(Color::DarkGray); + +/// Get border style based on focus state. +#[inline] +pub fn border_style(focused: bool) -> Style { + if focused { + BORDER_FOCUSED + } else { + BORDER_UNFOCUSED + } +} + +// === Table Styles === + +/// Style for table header text. +pub fn header_style() -> Style { + Style::default() + .fg(Color::Yellow) + .add_modifier(Modifier::BOLD) +} + +/// Style for table row when selected/highlighted. +pub fn row_highlight_style() -> Style { + Style::default() + .fg(Color::Black) + .bg(Color::Cyan) + .add_modifier(Modifier::BOLD) +} + +/// Default highlight symbol for table selection. +pub const HIGHLIGHT_SYMBOL: &str = "► "; + +// === Text Styles === + +/// Style for dimmed/hint text. +pub const TEXT_DIM: Style = Style::new().fg(Color::DarkGray); + +/// Style for warning/loading text. +pub const TEXT_WARNING: Style = Style::new().fg(Color::Yellow); + +/// Style for error text. +pub const TEXT_ERROR: Style = Style::new().fg(Color::Red); + +/// Style for success text. +pub const TEXT_SUCCESS: Style = Style::new().fg(Color::Green); + +/// Style for bold white text. +pub fn text_bold_white() -> Style { + Style::default() + .fg(Color::White) + .add_modifier(Modifier::BOLD) +} + +// === Modal Styles === + +/// Style for modal titles. +pub fn modal_title_style() -> Style { + Style::default() + .fg(Color::White) + .add_modifier(Modifier::BOLD) +} + +/// Style for selected items in lists. +pub fn selected_style() -> Style { + Style::default() + .bg(Color::Blue) + .fg(Color::White) + .add_modifier(Modifier::BOLD) +} + +/// Style for selected index numbers. +pub fn selected_index_style() -> Style { + Style::default().fg(Color::Cyan) +} + +// === Input Styles === + +/// Style for cursor indicator. +pub fn cursor_style() -> Style { + Style::default() + .fg(Color::Yellow) + .add_modifier(Modifier::SLOW_BLINK) +} + +/// Style for input text. +pub fn input_text_style() -> Style { + Style::default().fg(Color::White) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_border_style_focused() { + let style = border_style(true); + assert_eq!(style.fg, Some(Color::Cyan)); + } + + #[test] + fn test_border_style_unfocused() { + let style = border_style(false); + assert_eq!(style.fg, Some(Color::DarkGray)); + } + + #[test] + fn test_header_style() { + let style = header_style(); + assert_eq!(style.fg, Some(Color::Yellow)); + } + + #[test] + fn test_row_highlight_style() { + let style = row_highlight_style(); + assert_eq!(style.bg, Some(Color::Cyan)); + assert_eq!(style.fg, Some(Color::Black)); + } +}