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] = &[];