use rich_rust::prelude::*;
#[derive(Debug)]
pub struct FastMcpTheme {
pub primary: Color, pub secondary: Color, pub accent: Color,
pub success: Color, pub warning: Color, pub error: Color, pub info: Color,
pub text: Color, pub text_muted: Color, pub text_dim: Color, pub border: Color, pub background: Color,
pub header_style: Style,
pub subheader_style: Style,
pub label_style: Style,
pub value_style: Style,
pub key_style: Style,
pub muted_style: Style,
pub success_style: Style,
pub warning_style: Style,
pub error_style: Style,
pub info_style: Style,
pub border_style: Style,
}
impl Default for FastMcpTheme {
fn default() -> Self {
Self {
primary: Color::from_rgb(0, 212, 255),
secondary: Color::from_rgb(168, 85, 247),
accent: Color::from_rgb(34, 197, 94),
success: Color::from_rgb(34, 197, 94),
warning: Color::from_rgb(245, 158, 11),
error: Color::from_rgb(239, 68, 68),
info: Color::from_rgb(59, 130, 246),
text: Color::from_rgb(229, 231, 235),
text_muted: Color::from_rgb(156, 163, 175),
text_dim: Color::from_rgb(107, 114, 128),
border: Color::from_rgb(55, 65, 81),
background: Color::from_rgb(31, 41, 55),
header_style: Style::new().bold().color(Color::from_rgb(0, 212, 255)),
subheader_style: Style::new().color(Color::from_rgb(156, 163, 175)),
label_style: Style::new().color(Color::from_rgb(107, 114, 128)),
value_style: Style::new().color(Color::from_rgb(229, 231, 235)),
key_style: Style::new().bold().color(Color::from_rgb(168, 85, 247)),
muted_style: Style::new().dim().color(Color::from_rgb(107, 114, 128)),
success_style: Style::new().bold().color(Color::from_rgb(34, 197, 94)),
warning_style: Style::new().bold().color(Color::from_rgb(245, 158, 11)),
error_style: Style::new().bold().color(Color::from_rgb(239, 68, 68)),
info_style: Style::new().color(Color::from_rgb(59, 130, 246)),
border_style: Style::new().color(Color::from_rgb(55, 65, 81)),
}
}
}
pub fn theme() -> &'static FastMcpTheme {
static THEME: std::sync::OnceLock<FastMcpTheme> = std::sync::OnceLock::new();
THEME.get_or_init(FastMcpTheme::default)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_theme_default_colors() {
let t = FastMcpTheme::default();
assert_eq!(t.primary.triplet.map(|tr| tr.red), Some(0));
assert_eq!(t.primary.triplet.map(|tr| tr.green), Some(212));
assert_eq!(t.primary.triplet.map(|tr| tr.blue), Some(255));
}
#[test]
fn test_theme_semantic_colors() {
let t = FastMcpTheme::default();
assert_eq!(t.success.triplet.map(|tr| tr.green), Some(197));
assert_eq!(t.error.triplet.map(|tr| tr.red), Some(239));
assert_eq!(t.warning.triplet.map(|tr| tr.red), Some(245));
}
#[test]
fn test_theme_global_singleton() {
let t1 = theme();
let t2 = theme();
assert!(std::ptr::eq(t1, t2));
}
#[test]
fn test_theme_styles_exist() {
let t = FastMcpTheme::default();
let _ = t.header_style.clone();
let _ = t.error_style.clone();
let _ = t.success_style.clone();
let _ = t.warning_style.clone();
}
#[test]
fn theme_neutral_palette() {
let t = FastMcpTheme::default();
assert_eq!(t.text.triplet.map(|tr| tr.red), Some(229));
assert_eq!(t.text_muted.triplet.map(|tr| tr.red), Some(156));
assert_eq!(t.text_dim.triplet.map(|tr| tr.red), Some(107));
assert_eq!(t.border.triplet.map(|tr| tr.red), Some(55));
assert_eq!(t.background.triplet.map(|tr| tr.red), Some(31));
}
#[test]
fn theme_info_and_secondary_colors() {
let t = FastMcpTheme::default();
assert_eq!(t.info.triplet.map(|tr| tr.blue), Some(246));
assert_eq!(t.secondary.triplet.map(|tr| tr.red), Some(168));
assert_eq!(t.accent.triplet.map(|tr| tr.green), Some(197));
}
#[test]
fn theme_all_styles_accessible() {
let t = FastMcpTheme::default();
let _ = t.subheader_style.clone();
let _ = t.label_style.clone();
let _ = t.value_style.clone();
let _ = t.key_style.clone();
let _ = t.muted_style.clone();
let _ = t.info_style.clone();
let _ = t.border_style.clone();
}
#[test]
fn theme_debug_impl() {
let t = FastMcpTheme::default();
let debug = format!("{t:?}");
assert!(debug.contains("FastMcpTheme"));
}
}