use rustlavel_core::Json;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Palette {
colours: Vec<String>,
}
pub const DEFAULT_COLOURS: [&str; 7] = [
"#2563eb", "#ea580c", "#0d9488", "#c026d3", "#ca8a04", "#4f46e5", "#dc2626", ];
impl Default for Palette {
fn default() -> Palette {
Palette { colours: DEFAULT_COLOURS.iter().map(|c| c.to_string()).collect() }
}
}
impl Palette {
pub fn new(colours: impl IntoIterator<Item = impl Into<String>>) -> Palette {
let colours: Vec<String> = colours.into_iter().map(Into::into).collect();
if colours.is_empty() {
return Palette::default();
}
Palette { colours }
}
pub fn at(&self, index: usize) -> &str {
&self.colours[index % self.colours.len()]
}
pub fn len(&self) -> usize {
self.colours.len()
}
pub fn is_empty(&self) -> bool {
false
}
pub fn translucent(&self, colour: &str) -> String {
let hex = colour.strip_prefix('#').unwrap_or("");
if hex.len() == 6 && hex.chars().all(|c| c.is_ascii_hexdigit()) {
return format!("{colour}22");
}
colour.to_string()
}
pub fn to_json(&self) -> Json {
Json::Array(self.colours.iter().map(|c| Json::from(c.as_str())).collect())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn colours_wrap_rather_than_panicking_on_an_eighth_series() {
let palette = Palette::default();
assert_eq!(palette.at(0), DEFAULT_COLOURS[0]);
assert_eq!(palette.at(7), DEFAULT_COLOURS[0]);
assert_eq!(palette.at(9), DEFAULT_COLOURS[2]);
}
#[test]
fn an_empty_palette_falls_back_rather_than_dividing_by_zero() {
let palette = Palette::new(Vec::<String>::new());
assert_eq!(palette.len(), DEFAULT_COLOURS.len());
assert_eq!(palette.at(0), DEFAULT_COLOURS[0]);
}
#[test]
fn only_a_six_digit_hex_gets_an_alpha_suffix() {
let palette = Palette::default();
assert_eq!(palette.translucent("#2563eb"), "#2563eb22");
assert_eq!(palette.translucent("rebeccapurple"), "rebeccapurple");
assert_eq!(palette.translucent("rgb(1,2,3)"), "rgb(1,2,3)");
assert_eq!(palette.translucent("#abc"), "#abc", "a short hex would become invalid");
}
}