283 lines
7.1 KiB
Rust
283 lines
7.1 KiB
Rust
/// 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<dyn UIColor>,
|
|
middle: Option<Box<dyn UIColor>>,
|
|
end: Option<Box<dyn UIColor>>,
|
|
pos_start: Option<u8>,
|
|
pos_middle: Option<u8>,
|
|
pos_end: Option<u8>,
|
|
}
|
|
|
|
impl Gradient {
|
|
pub fn from<C: UIColor + 'static>(start: C) -> Self {
|
|
Self {
|
|
start: Box::new(start),
|
|
middle: None,
|
|
end: None,
|
|
pos_end: None,
|
|
pos_middle: None,
|
|
pos_start: None,
|
|
}
|
|
}
|
|
|
|
pub fn via<C: UIColor + 'static>(mut self, middle: C) -> Self {
|
|
self.middle = Some(Box::new(middle));
|
|
self
|
|
}
|
|
|
|
pub fn to<C: UIColor + 'static>(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<String> {
|
|
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
|
|
}
|
|
}
|