Skip to main content

guise/
icon.rs

1//! `Icon` — a themed glyph. A single home for the symbols guise components draw
2//! (chevrons, checks, close, …) so they stay visually and tonally consistent.
3//!
4//! Icons are Unicode glyphs rather than SVG assets: no asset pipeline, and they
5//! inherit the surrounding text color by default (pass [`Icon::color`] to tint).
6
7use gpui::prelude::*;
8use gpui::{div, px, App, IntoElement, SharedString, Window};
9
10use crate::theme::{theme, ColorName, Size};
11
12/// A named icon. The glyph is resolved by [`IconName::glyph`].
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum IconName {
15    Check,
16    Close,
17    Minus,
18    Plus,
19    ChevronDown,
20    ChevronUp,
21    ChevronLeft,
22    ChevronRight,
23    Search,
24    Dot,
25    Info,
26    Warning,
27    Star,
28    Copy,
29    Menu,
30    Ellipsis,
31    ArrowRight,
32    ArrowLeft,
33    Eye,
34    EyeOff,
35}
36
37impl IconName {
38    /// The Unicode glyph drawn for this icon.
39    pub fn glyph(self) -> &'static str {
40        match self {
41            IconName::Check => "\u{2713}",
42            IconName::Close => "\u{00d7}",
43            IconName::Minus => "\u{2212}",
44            IconName::Plus => "+",
45            IconName::ChevronDown => "\u{25be}",
46            IconName::ChevronUp => "\u{25b4}",
47            IconName::ChevronLeft => "\u{25c2}",
48            IconName::ChevronRight => "\u{25b8}",
49            IconName::Search => "\u{2315}",
50            IconName::Dot => "\u{2022}",
51            IconName::Info => "\u{2139}",
52            IconName::Warning => "\u{26a0}",
53            IconName::Star => "\u{2605}",
54            IconName::Copy => "\u{29c9}",
55            IconName::Menu => "\u{2630}",
56            IconName::Ellipsis => "\u{2026}",
57            IconName::ArrowRight => "\u{2192}",
58            IconName::ArrowLeft => "\u{2190}",
59            IconName::Eye => "\u{25ce}",
60            IconName::EyeOff => "\u{2298}",
61        }
62    }
63}
64
65/// A themed icon glyph. Inherits the parent's text color unless [`color`] is set.
66///
67/// [`color`]: Icon::color
68#[derive(IntoElement)]
69pub struct Icon {
70    name: IconName,
71    size: Size,
72    color: Option<ColorName>,
73}
74
75impl Icon {
76    pub fn new(name: IconName) -> Self {
77        Icon {
78            name,
79            size: Size::Md,
80            color: None,
81        }
82    }
83
84    pub fn size(mut self, size: Size) -> Self {
85        self.size = size;
86        self
87    }
88
89    /// Tint the glyph with a palette color (defaults to inheriting text color).
90    pub fn color(mut self, color: ColorName) -> Self {
91        self.color = Some(color);
92        self
93    }
94
95    fn glyph_px(&self) -> f32 {
96        match self.size {
97            Size::Xs => 14.0,
98            Size::Sm => 16.0,
99            Size::Md => 20.0,
100            Size::Lg => 26.0,
101            Size::Xl => 32.0,
102        }
103    }
104}
105
106impl RenderOnce for Icon {
107    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
108        let t = theme(cx);
109        let tint = self.color.map(|c| t.color(c, t.primary_shade()).hsla());
110        let mut el = div()
111            .flex()
112            .items_center()
113            .justify_center()
114            .text_size(px(self.glyph_px()))
115            .child(SharedString::new_static(self.name.glyph()));
116        if let Some(tint) = tint {
117            el = el.text_color(tint);
118        }
119        el
120    }
121}