use iocraft::Color;
use starbase_styles::Style;
use starbase_styles::theme::is_light_theme;
use std::collections::HashMap;
pub fn style_to_color(style: Style) -> Color {
Color::AnsiValue(style.ansi_color())
}
#[derive(Clone, Debug)]
pub struct ConsoleTheme {
pub brand_color: Color,
pub bg_alt_color: Color,
pub border_color: Color,
pub border_focus_color: Color,
pub form_label_color: Color,
pub form_failure_symbol: String,
pub form_success_symbol: String,
pub input_active_color: Color,
pub input_prefix_color: Color,
pub input_prefix_symbol: String,
pub input_selected_color: Color,
pub input_selected_symbol: String,
pub layout_fallback_symbol: String,
pub layout_list_bullet: String,
pub layout_map_separator: String,
pub progress_bar_color: Color,
pub progress_bar_filled_char: char,
pub progress_bar_position_char: char,
pub progress_bar_unfilled_char: char,
pub progress_loader_color: Color,
pub progress_loader_frames: Vec<String>,
pub style_caution_color: Color,
pub style_failure_color: Color,
pub style_info_color: Color,
pub style_invalid_color: Color,
pub style_neutral_color: Color,
pub style_muted_color: Color,
pub style_muted_light_color: Color,
pub style_success_color: Color,
pub style_file_color: Color,
pub style_hash_color: Color,
pub style_id_color: Color,
pub style_label_color: Color,
pub style_path_color: Color,
pub style_property_color: Color,
pub style_shell_color: Color,
pub style_symbol_color: Color,
pub style_url_color: Color,
pub supports_color: bool,
pub custom_tags: HashMap<String, Color>,
}
impl Default for ConsoleTheme {
fn default() -> Self {
if is_light_theme() {
Self::light()
} else {
Self::dark()
}
}
}
impl ConsoleTheme {
pub fn new(fg: Color, bg: Color) -> Self {
Self {
brand_color: fg,
bg_alt_color: bg,
border_color: style_to_color(Style::Muted),
border_focus_color: style_to_color(Style::MutedLight),
form_label_color: fg,
form_failure_symbol: "✘".into(),
form_success_symbol: "✔".into(),
input_active_color: style_to_color(Style::Path),
input_prefix_color: fg,
input_prefix_symbol: "❯".into(),
input_selected_color: style_to_color(Style::File),
input_selected_symbol: "✔".into(),
layout_fallback_symbol: "—".into(),
layout_list_bullet: "-".into(),
layout_map_separator: "=".into(),
progress_bar_color: fg,
progress_bar_filled_char: '█',
progress_bar_position_char: '▒',
progress_bar_unfilled_char: '░',
progress_loader_color: fg,
progress_loader_frames: DEFAULT_FRAMES.iter().map(|f| f.to_string()).collect(),
style_caution_color: style_to_color(Style::Caution),
style_failure_color: style_to_color(Style::Failure),
style_info_color: style_to_color(Style::Label),
style_invalid_color: style_to_color(Style::Invalid),
style_neutral_color: style_to_color(Style::Muted),
style_muted_color: style_to_color(Style::Muted),
style_muted_light_color: style_to_color(Style::MutedLight),
style_success_color: style_to_color(Style::Success),
style_file_color: style_to_color(Style::File),
style_hash_color: style_to_color(Style::Hash),
style_id_color: style_to_color(Style::Id),
style_label_color: style_to_color(Style::Label),
style_path_color: style_to_color(Style::Path),
style_property_color: style_to_color(Style::Property),
style_shell_color: style_to_color(Style::Shell),
style_symbol_color: style_to_color(Style::Symbol),
style_url_color: style_to_color(Style::Url),
supports_color: true,
custom_tags: HashMap::new(),
}
}
pub fn branded(color: Color) -> Self {
Self {
brand_color: color,
input_prefix_color: color,
progress_bar_color: color,
progress_loader_color: color,
..Self::default()
}
}
pub fn dark() -> Self {
let mut theme = Self::new(Color::White, Color::Black);
theme.bg_alt_color = Color::AnsiValue(234);
theme
}
pub fn light() -> Self {
let mut theme = Self::new(Color::Black, Color::White);
theme.bg_alt_color = Color::AnsiValue(254);
theme
}
pub fn style_to_color(&self, style: &Style) -> Option<Color> {
let color = match style {
Style::Caution => self.style_caution_color,
Style::Failure => self.style_failure_color,
Style::Invalid => self.style_invalid_color,
Style::Muted => self.style_muted_color,
Style::MutedLight => self.style_muted_light_color,
Style::Success => self.style_success_color,
Style::File => self.style_file_color,
Style::Hash => self.style_hash_color,
Style::Id => self.style_id_color,
Style::Label => self.style_label_color,
Style::Path => self.style_path_color,
Style::Property => self.style_property_color,
Style::Shell => self.style_shell_color,
Style::Symbol => self.style_symbol_color,
Style::Url => self.style_url_color,
Style::Tag(tag) => return self.custom_tags.get(tag).cloned(),
};
Some(color)
}
pub fn tag_to_color(&self, tag: &str) -> Option<Color> {
self.style_to_color(&match tag {
"caution" => Style::Caution,
"failure" => Style::Failure,
"invalid" => Style::Invalid,
"muted" => Style::Muted,
"mutedlight" => Style::MutedLight,
"success" => Style::Success,
"file" => Style::File,
"hash" => Style::Hash,
"id" => Style::Id,
"label" => Style::Label,
"path" => Style::Path,
"property" => Style::Property,
"shell" => Style::Shell,
"symbol" => Style::Symbol,
"url" => Style::Url,
tag => Style::Tag(tag.to_owned()),
})
}
pub fn variant(&self, variant: Variant) -> Color {
match variant {
Variant::Caution => self.style_caution_color,
Variant::Failure => self.style_failure_color,
Variant::Info => self.style_info_color,
Variant::Neutral => self.style_neutral_color,
Variant::Success => self.style_success_color,
}
}
}
#[derive(Clone, Copy, Default)]
pub enum Variant {
Caution,
Failure,
Info,
#[default]
Neutral,
Success,
}
const DEFAULT_FRAMES: &[&str] = &["▏", "▎", "▍", "▌", "▋", "▊", "▉", "▊", "▋", "▌", "▍", "▎"];