use ratatui::{
style::{Color, Modifier, Style},
symbols,
};
#[derive(Debug, Clone, Copy)]
pub struct CargoColors;
impl CargoColors {
pub const RUST_ORANGE: Color = Color::Rgb(222, 165, 132);
pub const RUST_DARK_ORANGE: Color = Color::Rgb(210, 125, 74);
pub const CARGO_BLUE: Color = Color::Rgb(79, 172, 254);
pub const DARK_BLUE: Color = Color::Rgb(35, 55, 85);
pub const SUCCESS_GREEN: Color = Color::Rgb(88, 166, 88);
pub const WARNING_YELLOW: Color = Color::Rgb(255, 193, 7);
pub const ERROR_RED: Color = Color::Rgb(220, 53, 69);
pub const INFO_CYAN: Color = Color::Rgb(23, 162, 184);
pub const BACKGROUND_DARK: Color = Color::Rgb(33, 37, 41);
pub const BACKGROUND_LIGHT: Color = Color::Rgb(248, 249, 250);
pub const TEXT_PRIMARY: Color = Color::Rgb(255, 255, 255);
pub const TEXT_SECONDARY: Color = Color::Rgb(173, 181, 189);
pub const TEXT_MUTED: Color = Color::Rgb(108, 117, 125);
pub const BORDER: Color = Color::Rgb(52, 58, 64);
pub const HIGHLIGHT: Color = Color::Rgb(255, 235, 59);
pub const SELECTED_BG: Color = Color::Rgb(40, 44, 52);
}
pub struct CargoStyle;
impl CargoStyle {
pub fn default() -> Style {
Style::default()
.fg(CargoColors::TEXT_PRIMARY)
.bg(Color::Reset)
}
pub fn primary() -> Style {
Style::default()
.fg(CargoColors::RUST_ORANGE)
.add_modifier(Modifier::BOLD)
}
pub fn accent() -> Style {
Style::default()
.fg(CargoColors::CARGO_BLUE)
.add_modifier(Modifier::BOLD)
}
pub fn success() -> Style {
Style::default()
.fg(CargoColors::SUCCESS_GREEN)
.add_modifier(Modifier::BOLD)
}
pub fn warning() -> Style {
Style::default()
.fg(CargoColors::WARNING_YELLOW)
.add_modifier(Modifier::BOLD)
}
pub fn error() -> Style {
Style::default()
.fg(CargoColors::ERROR_RED)
.add_modifier(Modifier::BOLD)
}
pub fn info() -> Style {
Style::default()
.fg(CargoColors::INFO_CYAN)
.add_modifier(Modifier::BOLD)
}
pub fn muted() -> Style {
Style::default()
.fg(CargoColors::TEXT_MUTED)
}
pub fn secondary() -> Style {
Style::default()
.fg(CargoColors::TEXT_SECONDARY)
}
pub fn highlight() -> Style {
Style::default()
.fg(CargoColors::HIGHLIGHT)
.add_modifier(Modifier::BOLD)
}
pub fn selected() -> Style {
Style::default()
.fg(CargoColors::TEXT_PRIMARY)
.bg(CargoColors::SELECTED_BG)
.add_modifier(Modifier::BOLD)
}
pub fn border() -> Style {
Style::default()
.fg(CargoColors::BORDER)
}
pub fn title() -> Style {
Style::default()
.fg(CargoColors::RUST_ORANGE)
.add_modifier(Modifier::BOLD)
}
pub fn subtitle() -> Style {
Style::default()
.fg(CargoColors::CARGO_BLUE)
.add_modifier(Modifier::BOLD)
}
pub fn code() -> Style {
Style::default()
.fg(CargoColors::TEXT_PRIMARY)
.bg(CargoColors::BACKGROUND_DARK)
.add_modifier(Modifier::ITALIC)
}
pub fn command() -> Style {
Style::default()
.fg(CargoColors::CARGO_BLUE)
.bg(CargoColors::BACKGROUND_DARK)
.add_modifier(Modifier::BOLD)
}
pub fn status_bar() -> Style {
Style::default()
.fg(CargoColors::TEXT_PRIMARY)
.bg(CargoColors::BACKGROUND_DARK)
}
pub fn progress() -> Style {
Style::default()
.fg(CargoColors::RUST_ORANGE)
.bg(CargoColors::BACKGROUND_DARK)
}
pub fn security_gauge(level: SecurityLevel) -> Style {
match level {
SecurityLevel::Secure => Self::success(),
SecurityLevel::Warning => Self::warning(),
SecurityLevel::Danger => Self::error(),
SecurityLevel::Critical => Style::default()
.fg(CargoColors::ERROR_RED)
.bg(Color::Rgb(139, 0, 0))
.add_modifier(Modifier::BOLD | Modifier::BLINK),
}
}
pub fn activity_severity(severity: ActivitySeverity) -> Style {
match severity {
ActivitySeverity::Info => Self::info(),
ActivitySeverity::Success => Self::success(),
ActivitySeverity::Warning => Self::warning(),
ActivitySeverity::Error => Self::error(),
}
}
pub fn vim_mode(mode: VimMode) -> Style {
match mode {
VimMode::Normal => Self::default(),
VimMode::Insert => Self::accent(),
VimMode::Visual => Self::warning(),
VimMode::Command => Self::command(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SecurityLevel {
Secure,
Warning,
Danger,
Critical,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ActivitySeverity {
Info,
Success,
Warning,
Error,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum VimMode {
Normal,
Insert,
Visual,
Command,
}
pub struct CargoSymbols;
impl CargoSymbols {
pub const PACKAGE: &'static str = "📦";
pub const CRAB: &'static str = "🦀";
pub const LOCK: &'static str = "🔒";
pub const UNLOCK: &'static str = "🔓";
pub const KEY: &'static str = "🔑";
pub const SHIELD: &'static str = "🛡️";
pub const WARNING: &'static str = "⚠️";
pub const ERROR: &'static str = "❌";
pub const SUCCESS: &'static str = "✅";
pub const INFO: &'static str = "ℹ️";
pub const GEAR: &'static str = "⚙️";
pub const SEARCH: &'static str = "🔍";
pub const FILE: &'static str = "📄";
pub const FOLDER: &'static str = "📁";
pub const NETWORK: &'static str = "🌐";
pub const CLOCK: &'static str = "🕐";
pub const CHART: &'static str = "📊";
pub const TERMINAL: &'static str = "💻";
pub const SPINNER: &'static [&'static str] = &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
pub const CARGO_SPINNER: &'static [&'static str] = &["📦", "📫", "📪", "📬"];
pub const PROGRESS_FULL: &'static str = "█";
pub const PROGRESS_EMPTY: &'static str = "░";
pub const PROGRESS_PARTIAL: &'static [&'static str] = &["▏", "▎", "▍", "▌", "▋", "▊", "▉"];
pub const BOX_HORIZONTAL: &'static str = "─";
pub const BOX_VERTICAL: &'static str = "│";
pub const BOX_TOP_LEFT: &'static str = "┌";
pub const BOX_TOP_RIGHT: &'static str = "┐";
pub const BOX_BOTTOM_LEFT: &'static str = "└";
pub const BOX_BOTTOM_RIGHT: &'static str = "┘";
pub const BOX_TEE_UP: &'static str = "┴";
pub const BOX_TEE_DOWN: &'static str = "┬";
pub const BOX_TEE_LEFT: &'static str = "┤";
pub const BOX_TEE_RIGHT: &'static str = "├";
pub const BOX_CROSS: &'static str = "┼";
pub const VIM_UP: &'static str = "↑";
pub const VIM_DOWN: &'static str = "↓";
pub const VIM_LEFT: &'static str = "←";
pub const VIM_RIGHT: &'static str = "→";
}
pub struct CargoAnimation;
impl CargoAnimation {
pub fn spinner_frame(frame: usize) -> &'static str {
CargoSymbols::SPINNER[frame % CargoSymbols::SPINNER.len()]
}
pub fn cargo_spinner_frame(frame: usize) -> &'static str {
CargoSymbols::CARGO_SPINNER[frame % CargoSymbols::CARGO_SPINNER.len()]
}
pub fn progress_bar(progress: f64, width: usize) -> String {
let filled = (progress * width as f64) as usize;
let partial = ((progress * width as f64) % 1.0 * 8.0) as usize;
let mut bar = String::new();
for _ in 0..filled {
bar.push_str(CargoSymbols::PROGRESS_FULL);
}
if partial > 0 && filled < width {
bar.push_str(CargoSymbols::PROGRESS_PARTIAL[partial - 1]);
}
let remaining = width - filled - if partial > 0 { 1 } else { 0 };
for _ in 0..remaining {
bar.push_str(CargoSymbols::PROGRESS_EMPTY);
}
bar
}
pub fn pulse_color(phase: f64, base_color: Color) -> Color {
let intensity = (phase.sin() + 1.0) / 2.0;
match base_color {
Color::Rgb(r, g, b) => {
let new_r = ((r as f64 * intensity) as u8).min(255);
let new_g = ((g as f64 * intensity) as u8).min(255);
let new_b = ((b as f64 * intensity) as u8).min(255);
Color::Rgb(new_r, new_g, new_b)
}
_ => base_color,
}
}
pub fn breathing_alpha(phase: f64) -> f64 {
(phase.sin() + 1.0) / 2.0 * 0.5 + 0.5
}
}
#[derive(Debug, Clone)]
pub struct Theme {
pub name: String,
pub colors: ThemeColors,
pub animations_enabled: bool,
pub vim_mode_enabled: bool,
}
#[derive(Debug, Clone)]
pub struct ThemeColors {
pub primary: Color,
pub secondary: Color,
pub success: Color,
pub warning: Color,
pub error: Color,
pub info: Color,
pub background: Color,
pub text: Color,
pub border: Color,
pub highlight: Color,
}
impl Default for Theme {
fn default() -> Self {
Self {
name: "Cargo".to_string(),
colors: ThemeColors {
primary: CargoColors::RUST_ORANGE,
secondary: CargoColors::CARGO_BLUE,
success: CargoColors::SUCCESS_GREEN,
warning: CargoColors::WARNING_YELLOW,
error: CargoColors::ERROR_RED,
info: CargoColors::INFO_CYAN,
background: CargoColors::BACKGROUND_DARK,
text: CargoColors::TEXT_PRIMARY,
border: CargoColors::BORDER,
highlight: CargoColors::HIGHLIGHT,
},
animations_enabled: true,
vim_mode_enabled: true,
}
}
}
impl Theme {
pub fn light() -> Self {
Self {
name: "Cargo Light".to_string(),
colors: ThemeColors {
primary: CargoColors::RUST_DARK_ORANGE,
secondary: CargoColors::CARGO_BLUE,
success: CargoColors::SUCCESS_GREEN,
warning: Color::Rgb(255, 152, 0),
error: CargoColors::ERROR_RED,
info: CargoColors::INFO_CYAN,
background: CargoColors::BACKGROUND_LIGHT,
text: Color::Rgb(33, 37, 41),
border: Color::Rgb(222, 226, 230),
highlight: Color::Rgb(255, 193, 7),
},
animations_enabled: true,
vim_mode_enabled: true,
}
}
pub fn high_contrast() -> Self {
Self {
name: "High Contrast".to_string(),
colors: ThemeColors {
primary: Color::White,
secondary: Color::Yellow,
success: Color::Green,
warning: Color::Yellow,
error: Color::Red,
info: Color::Cyan,
background: Color::Black,
text: Color::White,
border: Color::White,
highlight: Color::Yellow,
},
animations_enabled: false,
vim_mode_enabled: true,
}
}
}