All checks were successful
Build and Release / build-and-release (push) Successful in 1m19s
- Remove all debug println statements - Remove unused service_tracker module - Remove unused struct fields and methods - Remove empty placeholder files (cpu.rs, memory.rs, defaults.rs) - Fix all compiler warnings - Clean build with zero warnings Version bump to 0.1.159
329 lines
10 KiB
Rust
329 lines
10 KiB
Rust
use cm_dashboard_shared::Status;
|
|
use ratatui::style::{Color, Modifier, Style};
|
|
use ratatui::widgets::{Block, Borders};
|
|
|
|
/// Complete terminal color palette matching your configuration
|
|
#[allow(dead_code)]
|
|
pub struct TerminalColors {
|
|
// Primary colors
|
|
pub foreground: Color,
|
|
pub dim_foreground: Color,
|
|
pub bright_foreground: Color,
|
|
pub background: Color,
|
|
|
|
// Normal colors
|
|
pub normal_black: Color,
|
|
pub normal_red: Color,
|
|
pub normal_green: Color,
|
|
pub normal_yellow: Color,
|
|
pub normal_blue: Color,
|
|
pub normal_magenta: Color,
|
|
pub normal_cyan: Color,
|
|
pub normal_white: Color,
|
|
|
|
// Bright colors
|
|
pub bright_black: Color,
|
|
pub bright_red: Color,
|
|
pub bright_green: Color,
|
|
pub bright_yellow: Color,
|
|
pub bright_blue: Color,
|
|
pub bright_magenta: Color,
|
|
pub bright_cyan: Color,
|
|
pub bright_white: Color,
|
|
|
|
// Dim colors
|
|
pub dim_black: Color,
|
|
pub dim_red: Color,
|
|
pub dim_green: Color,
|
|
pub dim_yellow: Color,
|
|
pub dim_blue: Color,
|
|
pub dim_magenta: Color,
|
|
pub dim_cyan: Color,
|
|
pub dim_white: Color,
|
|
}
|
|
|
|
impl Default for TerminalColors {
|
|
fn default() -> Self {
|
|
Self {
|
|
// Primary colors
|
|
foreground: Color::Rgb(198, 198, 198), // #c6c6c6
|
|
dim_foreground: Color::Rgb(112, 112, 112), // #707070
|
|
bright_foreground: Color::Rgb(255, 255, 255), // #ffffff
|
|
background: Color::Rgb(38, 38, 38), // #262626
|
|
|
|
// Normal colors
|
|
normal_black: Color::Rgb(0, 0, 0), // #000000
|
|
normal_red: Color::Rgb(215, 84, 0), // #d75400
|
|
normal_green: Color::Rgb(175, 215, 135), // #afd787
|
|
normal_yellow: Color::Rgb(215, 175, 95), // #d7af5f
|
|
normal_blue: Color::Rgb(135, 175, 215), // #87afd7
|
|
normal_magenta: Color::Rgb(215, 215, 175), // #d7d7af
|
|
normal_cyan: Color::Rgb(160, 160, 160), // #a0a0a0
|
|
normal_white: Color::Rgb(238, 238, 238), // #eeeeee
|
|
|
|
// Bright colors
|
|
bright_black: Color::Rgb(48, 48, 48), // #303030
|
|
bright_red: Color::Rgb(215, 84, 0), // #d75400
|
|
bright_green: Color::Rgb(175, 215, 135), // #afd787
|
|
bright_yellow: Color::Rgb(215, 175, 95), // #d7af5f
|
|
bright_blue: Color::Rgb(135, 175, 215), // #87afd7
|
|
bright_magenta: Color::Rgb(215, 215, 175), // #d7d7af
|
|
bright_cyan: Color::Rgb(160, 160, 160), // #a0a0a0
|
|
bright_white: Color::Rgb(255, 255, 255), // #ffffff
|
|
|
|
// Dim colors
|
|
dim_black: Color::Rgb(0, 0, 0), // #000000
|
|
dim_red: Color::Rgb(215, 84, 0), // #d75400
|
|
dim_green: Color::Rgb(175, 215, 135), // #afd787
|
|
dim_yellow: Color::Rgb(215, 175, 95), // #d7af5f
|
|
dim_blue: Color::Rgb(135, 175, 215), // #87afd7
|
|
dim_magenta: Color::Rgb(215, 215, 175), // #d7d7af
|
|
dim_cyan: Color::Rgb(160, 160, 160), // #a0a0a0
|
|
dim_white: Color::Rgb(221, 221, 221), // #dddddd
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Comprehensive theming engine for dashboard consistency
|
|
pub struct Theme;
|
|
|
|
#[allow(dead_code)]
|
|
impl Theme {
|
|
fn colors() -> &'static TerminalColors {
|
|
static COLORS: std::sync::OnceLock<TerminalColors> = std::sync::OnceLock::new();
|
|
COLORS.get_or_init(TerminalColors::default)
|
|
}
|
|
|
|
// Semantic color mapping using the terminal color struct
|
|
pub fn primary_text() -> Color {
|
|
Self::colors().normal_white
|
|
}
|
|
|
|
pub fn secondary_text() -> Color {
|
|
Self::colors().foreground
|
|
}
|
|
|
|
pub fn muted_text() -> Color {
|
|
Self::colors().dim_foreground
|
|
}
|
|
|
|
pub fn border() -> Color {
|
|
Self::colors().dim_foreground
|
|
}
|
|
|
|
pub fn border_title() -> Color {
|
|
Self::colors().bright_white
|
|
}
|
|
|
|
pub fn background() -> Color {
|
|
Self::colors().background
|
|
}
|
|
|
|
pub fn success() -> Color {
|
|
Self::colors().normal_green
|
|
}
|
|
|
|
pub fn warning() -> Color {
|
|
Self::colors().normal_yellow
|
|
}
|
|
|
|
pub fn error() -> Color {
|
|
Self::colors().normal_red
|
|
}
|
|
|
|
pub fn info() -> Color {
|
|
Self::colors().normal_cyan
|
|
}
|
|
|
|
pub fn highlight() -> Color {
|
|
Self::colors().normal_blue
|
|
}
|
|
|
|
/// Get color for status level
|
|
pub fn status_color(status: Status) -> Color {
|
|
match status {
|
|
Status::Ok => Self::success(),
|
|
Status::Inactive => Self::muted_text(), // Gray for inactive services in service list
|
|
Status::Pending => Self::highlight(), // Blue for pending
|
|
Status::Warning => Self::warning(),
|
|
Status::Critical => Self::error(),
|
|
Status::Unknown => Self::muted_text(),
|
|
Status::Offline => Self::muted_text(), // Dark gray for offline
|
|
}
|
|
}
|
|
|
|
/// Get style for status level
|
|
pub fn status_style(status: Status) -> Style {
|
|
Style::default().fg(Self::status_color(status))
|
|
}
|
|
|
|
/// CPU usage colors using terminal color struct
|
|
pub fn cpu_color(percentage: u16) -> Color {
|
|
match percentage {
|
|
0..=25 => Self::colors().normal_green, // Low usage
|
|
26..=50 => Self::colors().normal_yellow, // Medium usage
|
|
51..=75 => Self::colors().normal_magenta, // High usage
|
|
76..=100 => Self::colors().normal_red, // Critical usage
|
|
_ => Self::colors().normal_red, // Over 100%
|
|
}
|
|
}
|
|
|
|
/// Memory usage colors using terminal color struct
|
|
pub fn memory_color(percentage: u16) -> Color {
|
|
match percentage {
|
|
0..=60 => Self::colors().normal_green, // Low usage
|
|
61..=80 => Self::colors().normal_yellow, // Medium usage
|
|
81..=95 => Self::colors().normal_magenta, // High usage
|
|
96..=100 => Self::colors().normal_red, // Critical usage
|
|
_ => Self::colors().normal_red, // Over 100%
|
|
}
|
|
}
|
|
|
|
/// Get gauge color based on percentage
|
|
pub fn gauge_color(percentage: u16, warning_threshold: u16, critical_threshold: u16) -> Color {
|
|
if percentage >= critical_threshold {
|
|
Self::error()
|
|
} else if percentage >= warning_threshold {
|
|
Self::warning()
|
|
} else {
|
|
Self::success()
|
|
}
|
|
}
|
|
|
|
/// Widget border style
|
|
pub fn widget_border_style() -> Style {
|
|
Style::default().fg(Self::border()).bg(Self::background())
|
|
}
|
|
|
|
/// Inactive widget border style
|
|
pub fn widget_border_inactive_style() -> Style {
|
|
Style::default()
|
|
.fg(Self::muted_text())
|
|
.bg(Self::background())
|
|
}
|
|
|
|
/// Title style
|
|
pub fn title_style() -> Style {
|
|
Style::default()
|
|
.fg(Self::border_title())
|
|
.bg(Self::background())
|
|
}
|
|
|
|
/// Status bar style
|
|
pub fn status_bar_style() -> Style {
|
|
Style::default()
|
|
.fg(Self::muted_text())
|
|
.bg(Self::background())
|
|
}
|
|
}
|
|
|
|
/// Layout and spacing constants
|
|
pub struct Layout;
|
|
|
|
impl Layout {
|
|
/// Left panel percentage (system + backup)
|
|
pub const LEFT_PANEL_WIDTH: u16 = 45;
|
|
/// Right panel percentage (services)
|
|
pub const RIGHT_PANEL_WIDTH: u16 = 55;
|
|
}
|
|
|
|
/// Typography system
|
|
pub struct Typography;
|
|
|
|
/// Component styling system
|
|
pub struct Components;
|
|
|
|
/// Status icons and styling
|
|
pub struct StatusIcons;
|
|
|
|
impl StatusIcons {
|
|
/// Get status icon symbol
|
|
pub fn get_icon(status: Status) -> &'static str {
|
|
match status {
|
|
Status::Ok => "●",
|
|
Status::Inactive => "○", // Empty circle for inactive services
|
|
Status::Pending => "◉", // Hollow circle for pending
|
|
Status::Warning => "◐",
|
|
Status::Critical => "!",
|
|
Status::Unknown => "?",
|
|
Status::Offline => "○", // Empty circle for offline
|
|
}
|
|
}
|
|
|
|
/// Create spans with status icon colored and text in foreground color
|
|
pub fn create_status_spans(status: Status, text: &str) -> Vec<ratatui::text::Span<'static>> {
|
|
let icon = Self::get_icon(status);
|
|
let status_color = match status {
|
|
Status::Ok => Theme::success(), // Green
|
|
Status::Inactive => Theme::muted_text(), // Gray for inactive services
|
|
Status::Pending => Theme::highlight(), // Blue
|
|
Status::Warning => Theme::warning(), // Yellow
|
|
Status::Critical => Theme::error(), // Red
|
|
Status::Unknown => Theme::muted_text(), // Gray
|
|
Status::Offline => Theme::muted_text(), // Dark gray for offline
|
|
};
|
|
|
|
vec![
|
|
ratatui::text::Span::styled(
|
|
format!("{} ", icon),
|
|
Style::default().fg(status_color).bg(Theme::background()),
|
|
),
|
|
ratatui::text::Span::styled(
|
|
text.to_string(),
|
|
Style::default()
|
|
.fg(Theme::secondary_text())
|
|
.bg(Theme::background()),
|
|
),
|
|
]
|
|
}
|
|
}
|
|
|
|
impl Components {
|
|
/// Standard widget block with title using bright foreground for title
|
|
pub fn widget_block(title: &str) -> Block<'_> {
|
|
Block::default()
|
|
.title(title)
|
|
.borders(Borders::ALL)
|
|
.style(Style::default().fg(Theme::border()).bg(Theme::background()))
|
|
.title_style(
|
|
Style::default()
|
|
.fg(Theme::border_title())
|
|
.bg(Theme::background()),
|
|
)
|
|
}
|
|
|
|
}
|
|
|
|
impl Typography {
|
|
|
|
/// Widget title style (panel headers) - bold bright white
|
|
pub fn widget_title() -> Style {
|
|
Style::default()
|
|
.fg(Color::White)
|
|
.bg(Theme::background())
|
|
.add_modifier(Modifier::BOLD)
|
|
}
|
|
|
|
/// Secondary content text
|
|
pub fn secondary() -> Style {
|
|
Style::default()
|
|
.fg(Theme::secondary_text())
|
|
.bg(Theme::background())
|
|
}
|
|
|
|
/// Muted text (inactive items, placeholders) - now bold bright white for headers
|
|
pub fn muted() -> Style {
|
|
Style::default()
|
|
.fg(Color::White)
|
|
.bg(Theme::background())
|
|
.add_modifier(Modifier::BOLD)
|
|
}
|
|
|
|
/// Tree symbols style (blue color)
|
|
pub fn tree() -> Style {
|
|
Style::default()
|
|
.fg(Theme::highlight())
|
|
.bg(Theme::background())
|
|
}
|
|
}
|