GPUI Box GitHub

Components / display

Icon builder

A glyph from the bundled catalog.

A builder is RenderOnce. Construct and mount it in one expression.

use gpui_kit::display::icon::Icon;

Reviewed in icon.

Also drawn by reading-direction, which arranges components rather than reviewing them.

Construct
new(glyph: Glyph) -> Self
named(ident: impl Into<Ident>, glyph: Glyph, name: impl Into<SharedString>) -> Self
Options

Chain onto the value.

spinning(ident: impl Into<Ident>) -> Self
breathing(ident: impl Into<Ident>) -> Self
reacting(ident: impl Into<Ident>, reaction: motion::Micro) -> Self
tone(tone: IconTone) -> Self
muted() -> Self
faint() -> Self
on_accent() -> Self
accent() -> Self
danger() -> Self
warning() -> Self
success() -> Self
info() -> Self
follow_direction(follow: bool) -> Self
Queries

Only answer; they change nothing.

resolved_size(theme: &Theme) -> f32
resolved_color(theme: &Theme) -> Hsla
flips_in(direction: LayoutDirection) -> bool
Example · icon
fn icon(_window: &mut Window, cx: &mut App) -> AnyElement {
    let theme = cx.theme().clone();
    let tones = [
        ("primary", IconTone::Primary),
        ("muted", IconTone::Muted),
        ("faint", IconTone::Faint),
        ("accent", IconTone::Accent),
        ("accent strong", IconTone::AccentStrong),
        ("success", IconTone::Success),
        ("warning", IconTone::Warning),
        ("danger", IconTone::Danger),
        ("info", IconTone::Info),
    ];

    stack(&theme)
        .child(caption(
            &theme,
            "Phosphor Regular is the resting catalog; every glyph is rendered at a real control size",
        ))
        .child(
            row(&theme)
                .gap(px(theme.space(Space::Xs)))
                .children(Icon::ALL.iter().map(|glyph| {
                    let name = glyph.name().source_name();
                    div()
                        .row()
                        .items_center()
                        .gap(px(theme.space(Space::Xs)))
                        .w(px(160.0))
                        .h(px(32.0))
                        .px(px(theme.space(Space::Xs)))
                        .radius(&theme, Radius::Control)
                        .well(&theme)
                        .child(IconView::named(
                            format!("scene.icon.glyph.{name}"),
                            *glyph,
                            name,
                        ))
                        .child(
                            crate::foundation::text(&theme, TypeScale::Caption, name)
                                .text_tone(&theme, TextTone::Muted)
                                .text_ellipsis(),
                        )
                        .into_any_element()
                })),
        )
        .child(caption(
            &theme,
            "Fill is the selected or committed state of the same symbol, never an ornamental weight",
        ))
        .child(
            row(&theme).gap(px(theme.space(Space::Md))).children(
                [
                    (Icon::Star, "star"),
                    (Icon::CheckCircle, "check-circle"),
                    (Icon::Home, "home"),
                    (Icon::Browser, "browser"),
                ]
                .map(|(glyph, label)| {
                    div()
                        .row()
                        .items_center()
                        .gap(px(theme.space(Space::Sm)))
                        .p(px(theme.space(Space::Sm)))
                        .radius(&theme, Radius::Card)
                        .surface(&theme, Surface::Panel)
                        .child(IconView::new(glyph).large().muted())
                        .child(IconView::new(glyph.filled()).large().accent())
                        .child(
                            crate::foundation::text(&theme, TypeScale::Caption, label)
                                .text_tone(&theme, TextTone::Muted),
                        )
                        .into_any_element()
                }),
            ),
        )
        .child(caption(
            &theme,
            "The token size ramp keeps icon and control geometry on the same scale",
        ))
        .child(
            row(&theme)
                .gap(px(theme.space(Space::Md)))
                .child(IconView::new(Icon::Sparkle).xs().faint())
                .child(IconView::new(Icon::Sparkle).small().muted())
                .child(IconView::new(Icon::Sparkle).medium())
                .child(IconView::new(Icon::Sparkle).large().accent()),
        )
        .child(caption(
            &theme,
            "Every tone. These are facts about what a glyph reports, not decoration",
        ))
        // At the size a glyph is actually drawn, a stroke two steps apart on
        // the text ramp is a few pixels of difference nobody can hold side by
        // side. Each tone is shown once large enough to be compared and once
        // at the size it is used, on a panel so the comparison is against one
        // ground rather than against the canvas at three different insets.
        .child(
            row(&theme)
                .gap(px(theme.space(Space::Md)))
                .children(tones.map(|(label, tone)| {
                    div()
                        .column()
                        .items_center()
                        .gap(px(theme.space(Space::Xs)))
                        .w(px(88.0))
                        .p(px(theme.space(Space::Sm)))
                        .radius(&theme, Radius::Card)
                        .surface(&theme, Surface::Panel)
                        .child(
                            IconView::named(format!("scene.icon.tone.{label}"), Icon::Info, label)
                                .tone(tone)
                                .large(),
                        )
                        .child(
                            div()
                                .row()
                                .gap(px(theme.space(Space::Xs)))
                                .child(IconView::new(Icon::Check).tone(tone))
                                .child(IconView::new(Icon::Danger).tone(tone))
                                .child(IconView::new(Icon::Refresh).tone(tone)),
                        )
                        .child(
                            crate::foundation::text(&theme, TypeScale::Caption, label)
                                .text_tone(&theme, TextTone::Muted),
                        )
                        .into_any_element()
                })),
        )
        .child(caption(
            &theme,
            "A glyph that means a direction turns with the reading order; one that \
             means a thing does not",
        ))
        .child(
            row(&theme).gap(px(theme.space(Space::Md))).children(
                [
                    (Icon::ArrowRight, "arrow-right"),
                    (Icon::Return, "return"),
                    (Icon::Copy, "copy"),
                    (Icon::Check, "check"),
                    (Icon::Settings, "settings"),
                ]
                .map(|(glyph, name)| {
                    IconView::named(format!("scene.icon.direction.{name}"), glyph, name)
                        .follow_direction(true)
                        .into_any_element()
                }),
            ),
        )
        .child(caption(
            &theme,
            "Semantic motion recipes: ongoing work spins, deliberation breathes, and settled feedback reacts once",
        ))
        .child(
            row(&theme)
                .gap(px(theme.space(Space::Lg)))
                .child(
                    IconView::named("scene.icon.motion.working", Icon::Spinner, "Working")
                        .large()
                        .accent()
                        .spinning("scene.icon.motion.working.spin"),
                )
                .child(
                    IconView::named(
                        "scene.icon.motion.deliberating",
                        Icon::Sparkle,
                        "Deliberating",
                    )
                    .large()
                    .breathing("scene.icon.motion.deliberating.breathe"),
                )
                .child(
                    IconView::named(
                        "scene.icon.motion.success",
                        Icon::CheckCircle.filled(),
                        "Succeeded",
                    )
                    .large()
                    .success()
                    .reacting("scene.icon.motion.success.pop", crate::motion::Micro::Pop),
                )
                .child(
                    IconView::named("scene.icon.motion.error", Icon::Danger, "Failed")
                        .large()
                        .danger()
                        .reacting("scene.icon.motion.error.wobble", crate::motion::Micro::Wobble),
                ),
        )
        .into_any_element()
}

Source: crates/gpui-kit/src/display/icon.rs