//! The `Icon` component: renders a glyph from the central [`crate::icons`]
//! registry (Material Symbols via Iconify) as inline SVG.
use leptos::prelude::*;
use crate::icons::IconName;
/// Folder-shaped glyphs get the accent color; everything else stays muted.
fn icon_class(name: IconName) -> &'static str {
if name.is_folder() {
"ic-folder"
} else {
"ic-muted"
}
}
/// The icon markup, as a plain function rather than a component.
///
/// Prefer this over [`Icon`] inside long lists. A `#[component]` call costs a
/// reactive owner per instance, which is measurable at a thousand rows; a
/// plain function returning a view costs nothing extra.
///
/// `inner_html` rather than a `NodeRef` with an `on_load` callback, for the
/// same reason: `on_load` is an effect, so a thousand icons meant a thousand
/// effects. The registry bodies are raw SVG markup (``) and are
/// injected as-is: the strings are `const`, vendored from the Iconify API,
/// and never user input.
pub fn icon_svg(name: IconName, extra: &str) -> impl IntoView + use<> {
let mut cls = String::from("icon ");
cls.push_str(icon_class(name));
if !extra.is_empty() {
cls.push(' ');
cls.push_str(extra);
}
view! {
}
}
#[component]
pub fn Icon(name: IconName, #[prop(optional)] class: Option) -> impl IntoView {
icon_svg(name, class.as_deref().unwrap_or(""))
}