use ishou_tokens::{Rgb, TokenSet};
#[must_use]
pub fn base16_slots(t: &TokenSet) -> [(&'static str, Rgb); 16] {
let c = &t.color;
[
("base00", c.polar_night_0),
("base01", c.polar_night_1),
("base02", c.polar_night_2),
("base03", c.polar_night_3),
("base04", c.snow_storm_0),
("base05", c.snow_storm_1),
("base06", c.snow_storm_2),
("base07", c.frost_0),
("base08", c.aurora_red),
("base09", c.aurora_orange),
("base0A", c.aurora_yellow),
("base0B", c.aurora_green),
("base0C", c.frost_1),
("base0D", c.frost_2),
("base0E", c.aurora_purple),
("base0F", c.frost_3),
]
}
const NORD_META: crate::base16_nix::SchemeMeta = crate::base16_nix::SchemeMeta {
name: "Nord (pleme-io / ishou)",
author: "Arctic Ice Studio; mapped by pleme-io ishou",
variant: "dark",
slug: "nord-dark",
};
#[must_use]
pub fn render(t: &TokenSet) -> String {
let mut out = String::new();
out.push_str("# Generated by ishou-render::stylix — DO NOT EDIT\n");
out.push_str("# Source of truth: pleme-io/ishou/crates/ishou-tokens/src/color.rs\n");
out.push_str("# Architecture: pleme-io/theory/THEME-ARCHITECTURE.md\n");
out.push_str("scheme: \"Nord (pleme-io / ishou)\"\n");
out.push_str("author: \"Arctic Ice Studio; mapped by pleme-io ishou\"\n");
for (slot, rgb) in base16_slots(t) {
push_base(&mut out, slot, rgb);
}
out
}
#[must_use]
pub fn render_nix(t: &TokenSet) -> String {
crate::base16_nix::render(
&NORD_META,
&base16_slots(t),
"pleme-io/ishou/crates/ishou-tokens/src/color.rs",
"stylix.base16Scheme = import ./rendered/stylix-base16-nord-dark.nix;",
)
}
fn push_base(out: &mut String, slot: &str, rgb: Rgb) {
out.push_str(&format!(
"{}: \"{:02x}{:02x}{:02x}\"\n",
slot, rgb.r, rgb.g, rgb.b
));
}
#[cfg(test)]
mod tests {
use super::*;
use ishou_tokens::TokenSet;
#[test]
fn output_is_deterministic() {
let t = TokenSet::pleme();
assert_eq!(render(&t), render(&t));
}
#[test]
fn output_contains_all_16_base_slots() {
let out = render(&TokenSet::pleme());
for slot in [
"base00", "base01", "base02", "base03", "base04", "base05", "base06", "base07",
"base08", "base09", "base0A", "base0B", "base0C", "base0D", "base0E", "base0F",
] {
assert!(out.contains(&format!("{slot}: \"")), "missing {slot}");
}
}
#[test]
fn nord_polar_night_0_lands_at_base00() {
let out = render(&TokenSet::pleme());
assert!(
out.contains("base00: \"2e3440\""),
"base00 must be polar_night_0 (#2e3440); got:\n{out}"
);
}
#[test]
fn nord_snow_storm_1_lands_at_base05_for_foreground_role() {
let out = render(&TokenSet::pleme());
assert!(out.contains("base05: \"e5e9f0\""), "got:\n{out}");
}
#[test]
fn nord_aurora_red_lands_at_base08() {
let out = render(&TokenSet::pleme());
assert!(out.contains("base08: \"bf616a\""), "got:\n{out}");
}
#[test]
fn hex_is_lowercase_unprefixed_to_match_stylix_contract() {
let out = render(&TokenSet::pleme());
for line in out.lines() {
if let Some(rest) = line.strip_prefix("base") {
if let Some(value_part) = rest.split(": ").nth(1) {
let v = value_part.trim_matches('"');
assert_eq!(v.len(), 6, "wrong length: {line}");
assert!(
v.chars()
.all(|c| c.is_ascii_hexdigit() && !c.is_ascii_uppercase()),
"expected lowercase hex without prefix in: {line}"
);
}
}
}
}
#[test]
fn full_byte_for_byte_canonical_pleme_output() {
let out = render(&TokenSet::pleme());
let expected = "\
# Generated by ishou-render::stylix — DO NOT EDIT
# Source of truth: pleme-io/ishou/crates/ishou-tokens/src/color.rs
# Architecture: pleme-io/theory/THEME-ARCHITECTURE.md
scheme: \"Nord (pleme-io / ishou)\"
author: \"Arctic Ice Studio; mapped by pleme-io ishou\"
base00: \"2e3440\"
base01: \"3b4252\"
base02: \"434c5e\"
base03: \"4c566a\"
base04: \"d8dee9\"
base05: \"e5e9f0\"
base06: \"eceff4\"
base07: \"8fbcbb\"
base08: \"bf616a\"
base09: \"d08770\"
base0A: \"ebcb8b\"
base0B: \"a3be8c\"
base0C: \"88c0d0\"
base0D: \"81a1c1\"
base0E: \"b48ead\"
base0F: \"5e81ac\"
";
assert_eq!(out, expected);
}
}