use lepticons::LucideGlyph;
pub const MRU_LIMIT: usize = 8;
pub fn load(storage_key: &str) -> Vec<LucideGlyph> {
let Some(window) = web_sys::window() else {
return Vec::new();
};
let storage = match window.local_storage() {
Ok(Some(s)) => s,
_ => return Vec::new(),
};
let raw = match storage.get_item(storage_key) {
Ok(Some(v)) => v,
_ => return Vec::new(),
};
parse_names(&raw)
.into_iter()
.filter_map(|name| LucideGlyph::by_name(&name))
.take(MRU_LIMIT)
.collect()
}
pub fn save(storage_key: &str, list: &[LucideGlyph]) {
let Some(window) = web_sys::window() else {
return;
};
let storage = match window.local_storage() {
Ok(Some(s)) => s,
_ => return,
};
let _ = storage.set_item(storage_key, &serialize_names(list));
}
pub fn push_into(list: &mut Vec<LucideGlyph>, icon: LucideGlyph) {
list.retain(|g| *g != icon);
list.insert(0, icon);
if list.len() > MRU_LIMIT {
list.truncate(MRU_LIMIT);
}
}
fn parse_names(raw: &str) -> Vec<String> {
let s = raw.trim();
let s = s.strip_prefix('[').unwrap_or(s);
let s = s.strip_suffix(']').unwrap_or(s);
s.split(',')
.map(|p| {
p.trim()
.trim_start_matches('"')
.trim_end_matches('"')
.to_string()
})
.filter(|p| !p.is_empty())
.collect()
}
fn serialize_names(list: &[LucideGlyph]) -> String {
let mut s = String::with_capacity(list.len() * 16);
s.push('[');
for (i, g) in list.iter().enumerate() {
if i > 0 {
s.push(',');
}
s.push('"');
s.push_str(g.name());
s.push('"');
}
s.push(']');
s
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_handles_well_formed_json() {
assert_eq!(
parse_names(r#"["Heart","ArrowRight"]"#),
vec!["Heart".to_string(), "ArrowRight".to_string()]
);
}
#[test]
fn parse_skips_empty_segments() {
assert_eq!(parse_names("[]"), Vec::<String>::new());
assert_eq!(parse_names(""), Vec::<String>::new());
}
#[test]
fn serialize_roundtrips() {
let list = vec![LucideGlyph::Heart, LucideGlyph::Search];
let s = serialize_names(&list);
assert_eq!(s, r#"["Heart","Search"]"#);
let names = parse_names(&s);
assert_eq!(names, vec!["Heart".to_string(), "Search".to_string()]);
}
#[test]
fn push_dedups_and_caps() {
let mut list = Vec::new();
for _ in 0..(MRU_LIMIT + 2) {
push_into(&mut list, LucideGlyph::Heart);
}
assert_eq!(list, vec![LucideGlyph::Heart]);
push_into(&mut list, LucideGlyph::Search);
assert_eq!(list, vec![LucideGlyph::Search, LucideGlyph::Heart]);
}
}