use std::sync::Arc;
use laterite_core::i18n::Text;
use crate::AssetUrls;
pub const COMPACT_STYLESHEET: &str = "skins/compact.css";
#[derive(Debug, Clone)]
pub struct Skin {
pub code: &'static str,
pub label: Text,
pub stylesheet: Option<&'static str>,
}
#[derive(Debug, Clone)]
pub struct Active {
pub code: Arc<str>,
pub stylesheet: Option<String>,
}
impl Default for Active {
fn default() -> Self {
Self {
code: Arc::from("standard"),
stylesheet: None,
}
}
}
pub fn builtin() -> Vec<Skin> {
vec![
Skin {
code: "standard",
label: Text::new("Standard"),
stylesheet: None,
},
Skin {
code: "compact",
label: Text::new("Compact"),
stylesheet: Some(COMPACT_STYLESHEET),
},
]
}
pub(crate) fn resolve(code: &str, skins: &[Skin], base: &str, urls: &AssetUrls) -> Active {
let code = if code.trim().is_empty() {
"standard"
} else {
code.trim()
};
let Some(skin) = skins.iter().find(|s| s.code == code) else {
let known: Vec<&str> = skins.iter().map(|s| s.code).collect();
panic!(
"unknown admin skin `{code}` (registered: {})",
known.join(", ")
);
};
let stylesheet = skin.stylesheet.map(|key| {
let Some(path) = urls.get(key) else {
panic!("admin skin `{code}` names stylesheet `{key}`, which no module registered");
};
format!("{base}/assets/{path}")
});
Active {
code: Arc::from(skin.code),
stylesheet,
}
}
pub(crate) fn check(skins: &[Skin]) {
for (i, skin) in skins.iter().enumerate() {
if skins[..i].iter().any(|s| s.code == skin.code) {
panic!("duplicate admin skin `{}`", skin.code);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn urls() -> AssetUrls {
let mut urls = AssetUrls::new();
urls.insert(COMPACT_STYLESHEET, "skins/compact.abc123.css".to_string());
urls
}
#[test]
fn standard_has_no_stylesheet_and_blank_means_standard() {
let active = resolve("", &builtin(), "/admin", &urls());
assert_eq!(&*active.code, "standard");
assert!(active.stylesheet.is_none());
}
#[test]
fn compact_resolves_to_its_fingerprinted_stylesheet() {
let active = resolve("compact", &builtin(), "/manage", &urls());
assert_eq!(&*active.code, "compact");
assert_eq!(
active.stylesheet.as_deref(),
Some("/manage/assets/skins/compact.abc123.css")
);
}
#[test]
#[should_panic(expected = "unknown admin skin `dense`")]
fn an_unknown_code_aborts() {
resolve("dense", &builtin(), "/admin", &urls());
}
#[test]
#[should_panic(expected = "which no module registered")]
fn a_missing_stylesheet_aborts() {
resolve("compact", &builtin(), "/admin", &AssetUrls::new());
}
#[test]
#[should_panic(expected = "duplicate admin skin `compact`")]
fn a_duplicate_code_aborts() {
let mut skins = builtin();
skins.push(Skin {
code: "compact",
label: Text::new("Again"),
stylesheet: None,
});
check(&skins);
}
}