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}
34
35impl IconName {
36    /// The Unicode glyph drawn for this icon.
37    pub fn glyph(self) -> &'static str {
38        match self {
39            IconName::Check => "\u{2713}",
40            IconName::Close => "\u{00d7}",
41            IconName::Minus => "\u{2212}",
42            IconName::Plus => "+",
43            IconName::ChevronDown => "\u{25be}",
44            IconName::ChevronUp => "\u{25b4}",
45            IconName::ChevronLeft => "\u{25c2}",
46            IconName::ChevronRight => "\u{25b8}",
47            IconName::Search => "\u{2315}",
48            IconName::Dot => "\u{2022}",
49            IconName::Info => "\u{2139}",
50            IconName::Warning => "\u{26a0}",
51            IconName::Star => "\u{2605}",
52            IconName::Copy => "\u{29c9}",
53            IconName::Menu => "\u{2630}",
54            IconName::Ellipsis => "\u{2026}",
55            IconName::ArrowRight => "\u{2192}",
56            IconName::ArrowLeft => "\u{2190}",
57        }
58    }
59}
60
61/// A themed icon glyph. Inherits the parent's text color unless [`color`] is set.
62///
63/// [`color`]: Icon::color
64#[derive(IntoElement)]
65pub struct Icon {
66    name: IconName,
67    size: Size,
68    color: Option<ColorName>,
69}
70
71impl Icon {
72    pub fn new(name: IconName) -> Self {
73        Icon {
74            name,
75            size: Size::Md,
76            color: None,
77        }
78    }
79
80    pub fn size(mut self, size: Size) -> Self {
81        self.size = size;
82        self
83    }
84
85    /// Tint the glyph with a palette color (defaults to inheriting text color).
86    pub fn color(mut self, color: ColorName) -> Self {
87        self.color = Some(color);
88        self
89    }
90
91    fn glyph_px(&self) -> f32 {
92        match self.size {
93            Size::Xs => 14.0,
94            Size::Sm => 16.0,
95            Size::Md => 20.0,
96            Size::Lg => 26.0,
97            Size::Xl => 32.0,
98        }
99    }
100}
101
102impl RenderOnce for Icon {
103    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
104        let t = theme(cx);
105        let tint = self.color.map(|c| t.color(c, t.primary_shade()).hsla());
106        let mut el = div()
107            .flex()
108            .items_center()
109            .justify_center()
110            .text_size(px(self.glyph_px()))
111            .child(SharedString::new_static(self.name.glyph()));
112        if let Some(tint) = tint {
113            el = el.text_color(tint);
114        }
115        el
116    }
117}