bezel

Foundations / Assets

Icons

Markdown crates/icons/src/lib.rs docs.rs

use ui::icons::{self, Icon, glyph};
use ui::widgets::Icons;

theme.icon(glyph::Search)                        // the ladder's body step, in the text tone
theme.icon_at(TextStyle::Caption, glyph::Search) // another rung
icons::icon(glyph::Search).size(px(16.0)).text_color(theme.text_muted)

gpui resolves an svg's tone from that element's own style and never inherits one, so icons::icon(..) with no text_color anywhere paints nothing — no warning, no fallback. theme.icon is the same builder with the size and tone already in it.

Sources

theme.row_icon(glyph::Monitor)                 // a glyph compiled in
theme.row_icon(Icon::asset("brand/mark.svg"))  // the app's own AssetSource
theme.row_icon(Icon::file(picked))             // a file on disk

Every component takes impl Into<Icon>, so a constant passes as itself and the component never learns which kind it got.

Solid twins

theme.icon(Icon::glyph(glyph::Star).solid())
icons::solid(glyph::Star)                     // the same, for the common case

A property of the value rather than a second call, so a control can hold one Icon and flip the variant instead of branching between two functions.

Features

bezel-icons = { version = "0.1", features = ["arrows", "navigation"] }

One per Lucide category, named as Lucide names them; full is all 42, and nothing is on by default. Cargo unions features across a graph, so ui's own three — arrows, notifications, text — are the floor for anything depending on it.

API

pub trait Icons: ThemeExt {
    /// Returns a gpui `Svg`, so a `Styled` call after it wins — the tone is a
    /// floor, not a decision.
    fn icon(&self, icon: impl Into<Icon>) -> Svg;

    /// Another rung of the ladder.
    fn icon_at(&self, role: TextStyle, icon: impl Into<Icon>) -> Svg;
}
// icons — an `Icon` carries no size and no colour: those belong to the
// component painting it.

impl Icon {
    pub const fn glyph(svg: &'static [u8]) -> Self;

    /// Resolved through the app's registered `AssetSource`.
    pub fn asset(key: impl Into<SharedString>) -> Self;

    /// Loaded off the paint thread and cached, so the first frame or two paint
    /// nothing.
    pub fn file(path: impl Into<SharedString>) -> Self;

    /// Fills the outline — filled *and* stroked, so the outer edge lands where
    /// the outline puts it and a control swapping between them does not jump.
    pub fn solid(self) -> Self;

    // ...
}

/// The bare builder: it carries no tone, so it needs one set on the glyph.
pub fn icon(icon: impl Into<Icon>) -> Svg;
pub fn solid(icon: impl Into<Icon>) -> Svg;

/// Every enabled category and its `(name, svg)` pairs, for an icon browser.
/// Naming it pins the whole enabled set.
pub const CATEGORIES: &[(&str, &[(&str, Icon)])];

An Icon carries no size and no colour: those belong to the component. Modules and constants are Lucide's own, generated by crates/icons/build.rs from a pinned release — bumping the version is the upgrade, and the diff says which glyphs upstream redrew. Lucide is ISC-licensed and asks for no attribution in a shipped binary.

Icons