use clap::ValueEnum;
use ratatui::style::{Color, Style};
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, ValueEnum, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Theme {
#[default]
Solid,
#[serde(alias = "default")]
#[value(alias = "default")]
Transparent,
Compatible,
Monochrome,
}
impl Theme {
pub fn next(self) -> Self {
match self {
Theme::Solid => Theme::Transparent,
Theme::Transparent => Theme::Compatible,
Theme::Compatible => Theme::Monochrome,
Theme::Monochrome => Theme::Solid,
}
}
pub fn label(self) -> &'static str {
match self {
Theme::Solid => "solid",
Theme::Transparent => "transparent",
Theme::Compatible => "compatible",
Theme::Monochrome => "monochrome",
}
}
pub fn group(self) -> Color {
self.pick(Color::Rgb(104, 232, 246), Color::Cyan)
}
pub fn entry(self) -> Color {
self.pick(Color::Rgb(231, 236, 250), Color::White)
}
pub fn title(self) -> Color {
self.pick(Color::Rgb(177, 139, 255), Color::Magenta)
}
pub fn focused(self) -> Color {
self.pick(Color::Rgb(104, 232, 246), Color::Cyan)
}
pub fn unfocused(self) -> Color {
self.pick(Color::Rgb(143, 160, 179), Color::DarkGray)
}
pub fn success(self) -> Color {
self.pick(Color::Rgb(120, 230, 160), Color::Green)
}
pub fn warning(self) -> Color {
self.pick(Color::Rgb(250, 204, 102), Color::Yellow)
}
pub fn failure(self) -> Color {
self.pick(Color::Rgb(255, 120, 140), Color::Red)
}
pub fn disabled(self) -> Color {
self.pick(Color::DarkGray, Color::DarkGray)
}
pub fn muted(self) -> Color {
self.pick(Color::Rgb(143, 160, 179), Color::Gray)
}
pub fn faint(self) -> Color {
self.pick(Color::Rgb(110, 124, 145), Color::DarkGray)
}
pub fn line(self) -> Color {
self.pick(Color::Rgb(52, 64, 84), Color::DarkGray)
}
pub fn selected(self) -> Color {
self.pick(Color::Rgb(31, 53, 80), Color::Blue)
}
pub fn selected_line(self) -> Color {
self.pick(Color::Rgb(78, 110, 148), Color::Gray)
}
pub fn on_selected(self) -> Color {
self.pick(Color::Rgb(240, 246, 255), Color::White)
}
pub fn on_highlight(self) -> Color {
self.pick(Color::Rgb(11, 15, 28), Color::Black)
}
pub fn base(self) -> Style {
match self {
Theme::Solid => Style::default().bg(Color::Rgb(13, 17, 26)),
_ => Style::default(),
}
}
pub fn card(self) -> Style {
match self {
Theme::Solid => Style::default().bg(Color::Rgb(20, 26, 38)),
_ => Style::default(),
}
}
pub fn selection(self) -> Style {
match self {
Theme::Monochrome => Style::default().reversed().bold(),
_ => Style::default()
.bg(self.selected())
.fg(self.on_selected())
.bold(),
}
}
pub fn selected_fill(self) -> Style {
match self {
Theme::Monochrome => Style::default().reversed(),
_ => Style::default().bg(self.selected()),
}
}
pub fn button(self, colour: Color) -> Style {
match self {
Theme::Monochrome => Style::default().reversed().bold(),
_ => Style::default().bg(colour).fg(self.on_highlight()).bold(),
}
}
pub fn colourful(self) -> bool {
matches!(self, Theme::Solid | Theme::Transparent)
}
fn pick(self, rich: Color, compatible: Color) -> Color {
match self {
Theme::Solid | Theme::Transparent => rich,
Theme::Compatible => compatible,
Theme::Monochrome => Color::Reset,
}
}
}
pub fn no_color() -> bool {
std::env::var_os("NO_COLOR").is_some_and(|value| !value.is_empty())
}