Skip to main content

dioxus_swdir_tree_core/
icon.rs

1//! Icon theme types for [`crate::DirectoryTree`] rendering.
2//!
3//! Themes are a **rendering-only** concern (S10.4): they are consulted
4//! while building rows, never during state transitions. The view layer
5//! holds the theme outside the reactive state.
6
7use std::borrow::Cow;
8
9/// The six logical icon positions in a tree row (S10.1).
10///
11/// `#[non_exhaustive]` — future minor releases may add variants; external
12/// theme implementations must include a `_ =>` fallback arm (S10.2).
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14#[non_exhaustive]
15pub enum IconRole {
16    /// A collapsed directory.
17    FolderClosed,
18    /// An expanded directory.
19    FolderOpen,
20    /// A non-directory entry.
21    File,
22    /// A directory whose scan failed.
23    Error,
24    /// Caret for a collapsed directory.
25    CaretRight,
26    /// Caret for an expanded directory (or loading indicator).
27    CaretDown,
28}
29
30/// The rendering specification for one icon position (S10.3).
31#[derive(Debug, Clone, PartialEq)]
32pub struct IconSpec {
33    /// Text to render in the icon span.
34    pub glyph: Cow<'static, str>,
35    /// CSS `font-family` value for the span, or `None` to inherit the
36    /// row's ambient font.
37    pub font: Option<&'static str>,
38    /// Font size in CSS pixels, or `None` to use the widget default (14 px).
39    pub size: Option<f32>,
40}
41
42/// Plug-in icon rendering (S10.7).
43///
44/// Implementations should be cheap and pure — build any glyph map at
45/// construction time. The trait is object-safe; pass `Arc<dyn IconTheme>`.
46pub trait IconTheme: Send + Sync {
47    /// Return the rendering spec for `role`.
48    fn glyph(&self, role: IconRole) -> IconSpec;
49}
50
51// ── UnicodeTheme ──────────────────────────────────────────────────────────────
52
53/// Default theme: Unicode/emoji glyphs in the ambient system font.
54/// No font registration required (S10.5, without `icons` feature).
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
56pub struct UnicodeTheme;
57
58impl IconTheme for UnicodeTheme {
59    fn glyph(&self, role: IconRole) -> IconSpec {
60        let glyph: &'static str = match role {
61            IconRole::FolderClosed => "📁",
62            IconRole::FolderOpen => "📂",
63            IconRole::File => "📄",
64            IconRole::Error => "⚠",
65            IconRole::CaretRight => "▸",
66            IconRole::CaretDown => "▾",
67        };
68        IconSpec {
69            glyph: Cow::Borrowed(glyph),
70            font: None,
71            size: None,
72        }
73    }
74}
75
76// ── LucideTheme (icons feature) ───────────────────────────────────────────────
77
78/// Lucide vector-glyph theme, gated by the `icons` feature (S10.5).
79///
80/// Requires the `lucide` CSS font-family to be registered with the
81/// rendering engine (S10.6). Without registration, glyphs render as
82/// tofu while the widget keeps functioning. Use [`LUCIDE_FONT_BYTES`]
83/// with a `@font-face` rule in your application's stylesheet.
84///
85/// # Lucide licence
86///
87/// Lucide is distributed under the ISC licence; see `NOTICE` for the
88/// full attribution.
89#[cfg(feature = "icons")]
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
91pub struct LucideTheme;
92
93#[cfg(feature = "icons")]
94impl IconTheme for LucideTheme {
95    fn glyph(&self, role: IconRole) -> IconSpec {
96        // Codepoints from the @lucide/font package (lucide 0.441.0).
97        // Private-Use-Area entries mapped sequentially from U+E000.
98        let glyph: &'static str = match role {
99            IconRole::FolderClosed => "\u{ea83}", // folder
100            IconRole::FolderOpen => "\u{ea84}",   // folder-open
101            IconRole::File => "\u{ea7f}",         // file
102            IconRole::Error => "\u{ea78}",        // circle-alert
103            IconRole::CaretRight => "\u{ea59}",   // chevron-right
104            IconRole::CaretDown => "\u{ea56}",    // chevron-down
105            _ => "\u{ea30}",                      // square (fallback)
106        };
107        IconSpec {
108            glyph: Cow::Borrowed(glyph),
109            font: Some("lucide"),
110            size: Some(14.0),
111        }
112    }
113}
114
115/// Raw bytes of the Lucide icon font TTF (lucide 0.441.0, ISC licence).
116///
117/// Use these bytes to register the `lucide` CSS font-family in your app.
118/// Without registration, [`LucideTheme`] glyphs render as tofu but the
119/// widget continues to function correctly (S10.6).
120///
121/// # Example (`@font-face` via inline CSS)
122///
123/// ```html
124/// <style>
125///   @font-face {
126///     font-family: "lucide";
127///     src: url("/assets/lucide.ttf") format("truetype");
128///   }
129/// </style>
130/// ```
131/// Placeholder — substitute the real Lucide TTF bytes in your application.
132/// Download the font from <https://github.com/lucide-icons/lucide/releases>
133/// and register it with a `@font-face` CSS rule pointing to `font-family: "lucide"`.
134#[cfg(feature = "icons")]
135pub const LUCIDE_FONT_BYTES: &[u8] = &[];