Icon

GPUI Component 中的 IconNameIcon 提供了一套可直接在 GPUI 应用中使用的图标接口。

但为了尽量减小应用体积,gpui-component 默认 不会内置任何图标资源

因此仓库把图标资源拆分到了独立的 gpui-kit-assets crate 中。这样你可以自行决定:

  • 直接使用默认内置图标资源
  • 完全不引入图标资源
  • 自己维护一套 SVG 资源

#共享名称与兼容性

gpui_kit::assets::IconName 提供不依赖 Component 的完整共享目录。 gpui_kit::component::IconName 保留为原来的兼容枚举:现有导入、穷尽匹配和 .view(cx) 调用均无需改动,也无需新增 trait 导入。Icon::new(...) 同时接受 两种类型;旧名称可以通过 .into() 转为共享名称。

对于新的共享枚举,需要组件实体时使用 Icon::new(name).view(cx),也可导入 gpui_kit::component::IconNameExt 后使用 name.view(cx)

IconName::ALL 列出完整的 1,830 个名称,IconName::Accessibility.path() 返回 icons/accessibility.svg。默认资源源只包含原来的 101 个组件图标;额外图标请使用 下文的自定义资源源,或者显式注册 AllAssets 使用完整资源包。

#使用默认内置资源

gpui-kit-assets 提供了一个默认的资源实现,包含 crates/assets/default-icons.txt 中列出的原有 101 个组件图标。

如果要使用默认资源,需要在 Cargo.toml 中添加:

[dependencies]
gpui-component = { git = "https://github.com/longbridge/gpui-kit" }
gpui-kit-assets = { git = "https://github.com/longbridge/gpui-kit" }

然后在创建 GPUI 应用时,通过 with_assets 注册资源源:

use gpui_kit::*;
use gpui_kit::assets::Assets;

let app = gpui_kit::application().with_assets(Assets);

完成后,你就可以像平常一样使用 IconNameIcon。这些图标会从默认打包资源中读取。

继续阅读下面的 使用图标 小节查看实际示例。

#自定义资源

如果你只想带上一小部分图标,或者希望使用项目自己的 SVG 资源,可以自己构建资源源。

仓库中的 assets 目录包含了目前支持的全部 SVG 图标文件,文件名与 IconName 枚举一一对应。

你可以:

  • 直接从 assets 目录拷贝需要的 SVG
  • 或按 IconName 的命名规则准备自己的 SVG 文件

在 GPUI 应用中,通常可以结合 rust-embed 将这些 SVG 嵌入可执行文件,并通过 AssetSource 提供加载能力。

use gpui_kit::*;
use gpui_kit::assets::Assets as ComponentAssets;
use gpui_kit::component::{v_flex, IconName, Root};
use rust_embed::RustEmbed;
use std::borrow::Cow;

/// An asset source that loads assets from the `./assets` folder.
#[derive(RustEmbed)]
#[folder = "./assets"]
#[include = "icons/**/*.svg"]
pub struct Assets;

impl AssetSource for Assets {
    fn load(&self, path: &str) -> Result<Option<Cow<'static, [u8]>>> {
        if path.is_empty() {
            return Ok(None);
        }

        if let Some(file) = Self::get(path) {
            return Ok(Some(file.data));
        }
        ComponentAssets.load(path)
    }

    fn list(&self, path: &str) -> Result<Vec<SharedString>> {
        let mut paths = ComponentAssets.list(path)?;
        paths.extend(Self::iter().filter_map(|p| p.starts_with(path).then(|| p.into())));
        paths.sort();
        paths.dedup();
        Ok(paths)
    }
}

同样需要在创建应用时调用 with_assets

fn main() {
    // Register Assets to GPUI application.
    let app = gpui_kit::application().with_assets(Assets);

    app.run(move |cx| {
        // We must initialize gpui_component before using it.
        gpui_kit::init(cx);

        cx.spawn(async move |cx| {
            cx.open_window(WindowOptions::default(), |window, cx| {
                let view = cx.new(|_| Example);
                // The first level on the window must be Root.
                cx.new(|cx| Root::new(view, window, cx))
            })
            .expect("Failed to open window");
        })
        .detach();
    });
}

#使用图标

完成资源注册后,就可以在应用中直接使用图标:

pub struct Example;

impl Render for Example {
    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
        v_flex()
            .gap_2()
            .size_full()
            .items_center()
            .justify_center()
            .text_center()
            .child(IconName::Inbox)
            .child(IconName::Bot)
    }
}

#单独嵌入 SVG 图标

自定义图标可以通过 Icon::data 直接传入 SVG 字节,无须维护资源路径注册表:

use gpui_kit::component::{Icon, button::Button};

Button::new("search")
    .icon(Icon::default().data(include_bytes!("search.svg")))
    .label("Search")

这样可以省去该图标的资源查找。内置 IconName 和组件中使用的其他路径图标仍需要资源源。 数据所有权、来源替换、加载图标与自定义图标类型的说明见 SVG 字节

#参考资源

  • Lucide Icons - GPUI Component 的图标集主要基于 Lucide 开源图标库