/// UI Color pub trait UIColor { #[must_use] fn color_class(&self) -> &str; } pub trait ColorCircle { #[must_use] fn previous(&self) -> Self; #[must_use] fn middle(&self) -> Self; #[must_use] fn start(&self) -> Self; #[must_use] fn end(&self) -> Self; #[must_use] fn next(&self) -> Self; } #[allow(non_snake_case)] pub fn RGB(r: u8, g: u8, b: u8) -> RGBColor { RGBColor(format!("[#{r:02x}{g:02x}{b:02x}]")) } pub struct RGBColor(String); impl UIColor for RGBColor { fn color_class(&self) -> &str { self.0.as_ref() } } pub trait UIColorCircle: UIColor + ColorCircle + Sized {} macro_rules! color_map { ($name:ident, $id:literal) => { #[derive(Debug, Clone)] pub enum $name { _50, _100, _200, _300, _400, _500, _600, _700, _800, _900, _950, } impl UIColor for $name { fn color_class(&self) -> &str { match self { $name::_50 => concat!($id, "-50"), $name::_100 => concat!($id, "-100"), $name::_200 => concat!($id, "-200"), $name::_300 => concat!($id, "-300"), $name::_400 => concat!($id, "-400"), $name::_500 => concat!($id, "-500"), $name::_600 => concat!($id, "-600"), $name::_700 => concat!($id, "-700"), $name::_800 => concat!($id, "-800"), $name::_900 => concat!($id, "-900"), $name::_950 => concat!($id, "-950"), } } } impl ColorCircle for $name { fn next(&self) -> Self { match self { $name::_50 => $name::_100, $name::_100 => $name::_200, $name::_200 => $name::_300, $name::_300 => $name::_400, $name::_400 => $name::_500, $name::_500 => $name::_600, $name::_600 => $name::_700, $name::_700 => $name::_800, $name::_800 => $name::_900, $name::_900 => $name::_950, $name::_950 => $name::_50, } } fn middle(&self) -> Self { Self::_500 } fn start(&self) -> Self { Self::_50 } fn end(&self) -> Self { Self::_950 } fn previous(&self) -> Self { match self { $name::_50 => $name::_950, $name::_100 => $name::_50, $name::_200 => $name::_100, $name::_300 => $name::_200, $name::_400 => $name::_300, $name::_500 => $name::_400, $name::_600 => $name::_500, $name::_700 => $name::_600, $name::_800 => $name::_700, $name::_900 => $name::_800, $name::_950 => $name::_900, } } } }; } color_map!(Slate, "slate"); color_map!(Gray, "gray"); color_map!(Zinc, "zinc"); color_map!(Neutral, "neutral"); color_map!(Stone, "stone"); color_map!(Red, "red"); color_map!(Orange, "orange"); color_map!(Amber, "amber"); color_map!(Yellow, "yellow"); color_map!(Lime, "lime"); color_map!(Green, "green"); color_map!(Emerald, "emerald"); color_map!(Teal, "teal"); color_map!(Cyan, "cyan"); color_map!(Sky, "sky"); color_map!(Blue, "blue"); color_map!(Indigo, "indigo"); color_map!(Violet, "violet"); color_map!(Purple, "purple"); color_map!(Fuchsia, "fuchsia"); color_map!(Pink, "pink"); color_map!(Rose, "rose"); #[derive(Debug, Clone)] pub enum Colors { /// Inherit a color Inherit, /// Use current color Current, /// Transparency Transparent, /// Black Black, /// White White, } impl ColorCircle for Colors { fn previous(&self) -> Self { match self { Colors::Black => Colors::White, Colors::White => Colors::Black, _ => self.clone(), } } fn middle(&self) -> Self { self.clone() } fn start(&self) -> Self { match self { Colors::Black => Colors::White, Colors::White => Colors::White, _ => self.clone(), } } fn end(&self) -> Self { match self { Colors::Black => Colors::Black, Colors::White => Colors::Black, _ => self.clone(), } } fn next(&self) -> Self { match self { Colors::Black => Colors::White, Colors::White => Colors::Black, _ => self.clone(), } } } impl UIColor for Colors { fn color_class(&self) -> &str { match self { Self::Inherit => "inherit", Self::Current => "current", Self::Transparent => "transparent", Self::Black => "black", Self::White => "white", } } } pub struct Gradient { start: Box, middle: Option>, end: Option>, pos_start: Option, pos_middle: Option, pos_end: Option, } impl Gradient { pub fn from(start: C) -> Self { Self { start: Box::new(start), middle: None, end: None, pos_end: None, pos_middle: None, pos_start: None, } } pub fn via(mut self, middle: C) -> Self { self.middle = Some(Box::new(middle)); self } pub fn to(mut self, end: C) -> Self { self.end = Some(Box::new(end)); self } pub fn step_start(mut self, percentage: u8) -> Self { assert!(percentage <= 100, "Percentage should be under 100%"); self.pos_start = Some(percentage); self } pub fn step_middle(mut self, percentage: u8) -> Self { assert!(percentage <= 100, "Percentage should be under 100%"); self.pos_middle = Some(percentage); self } pub fn step_end(mut self, percentage: u8) -> Self { assert!(percentage <= 100, "Percentage should be under 100%"); self.pos_end = Some(percentage); self } pub fn color_class(&self) -> Vec { let mut classes = vec![format!("from-{}", self.start.color_class())]; if let Some(via) = &self.middle { classes.push(format!("via-{}", via.color_class())); } if let Some(end) = &self.end { classes.push(format!("to-{}", end.color_class())); } if let Some(step) = &self.pos_start { classes.push(format!("from-{step}%")); } if let Some(step) = &self.pos_middle { classes.push(format!("via-{step}%")); } if let Some(step) = &self.pos_end { classes.push(format!("to-{step}%")); } classes } }