Icon Gallery
搜索、预览并复制 zenit 公开图标,理解静态常量、动态 registry 与语义图标层的分工。
两个图标入口
公开构建内置 Lucide(lucide-static v1.31.0)。完整 provider 目录位于 ui.icons,共 2,026 个名称:上游 2,025 个 SVG,加上兼容别名 hand-pointing(与上游 pointer.svg 字节相同)。ui.system_icons 则提供 45 个与 provider 无关的语义角色,zenit 自己的组件只依赖后者,避免把供应商命名写进公共组件契约。
ui.system_icons45 个稳定语义角色(close、search、alert、pointer…);可复用的框架 / 包代码用它,换 provider 也能编译ui.icons2,026 个 Lucide 名称;产品界面与动态配置用它ui.assets.common17 个历史兼容图标;新代码不再优先使用完整 2,026 项清单
输入名称即时过滤,每次追加 180 个,避免一次创建两千多个 DOM 节点。点击任意图标会给出一行可直接粘贴的 ui.iconTint 调用;需要转义的名称(例如 ui.icons.@"type")已按生成器规则处理。
渲染与着色
图标在构建期由 gen-icons 解析为扁平几何(每个 Asset 带 icon_id 和按尺寸划分的 reps),运行时 ui.iconTint 按逻辑尺寸选取最接近的 rep 写入节点,不在窗口里跑 SVG 引擎;没有预展平几何的 Asset 才回退到 svgTint 栅格化。宽高不是固定像素时,使用 Asset 的默认尺寸(Lucide 为 24)。
ui.iconTint 最适合跟随主题色;同一个 Asset 可以用不同尺寸和颜色反复使用。ui.icon 不带 tint 参数,默认以白色绘制,所以放在浅色背景上时请改用 iconTint。需要透明度等 BoxStyle 字段时用 ui.iconTintStyled。已挂载的图标要换色(hover、选中态)时调用 node.setTint(color):它同时覆盖 icon 表存储与 svgTint 回退的 image 存储,节点两者都没有时返回 false。
// Follow the theme: tint with a token color.
const settings = try ui.iconTint(
cx,
ui.icons.settings,
cx.tokens.color.fg_secondary,
.{ .width = .fixed(20), .height = .fixed(20) },
);
// Dynamic lookup by kebab-case source name (config files, user data).
const configured = ui.icons.get("circle-alert") orelse
return error.UnknownIcon;
const warning = try ui.iconTint(cx, configured, cx.tokens.color.warning, .{
.width = .fixed(24),
.height = .fixed(24),
});
// Enumerate the whole registry.
for (ui.icons.all) |entry| {
std.log.debug("{s}", .{entry.name});
}语义图标契约
组件代码优先写 ui.system_icons.close,而不是绑定某个供应商的具体名字。当前 Lucide profile 在 src/ui/system_icons_lucide.zig 里把 45 个角色映射到具体 Asset;用 -Dicon-set 切换 provider 时,组件 API 不变。
角色名与 Lucide 名不同的映射:
alertcircle-alertaudioheadphonesclosexhomehousenotificationbelltrashtrash-2editpencilmore_horizontalellipsiscursor_defaultmouse-pointer-2cursor_clickmouse-pointer-clickpointerhand-pointingnot_allowedbangrabhandresize_horizontalchevrons-left-rightresize_verticalchevrons-up-downresize_diagonalexpandwaithourglassprogressloader-circlehelpcircle-helpwarningtriangle-alert// Reusable code: depend on the role, not the provider's name.
const close = try ui.iconTint(cx, ui.system_icons.close, cx.tokens.color.fg_secondary, .{
.width = .fixed(16),
.height = .fixed(16),
});
// Icon-only button: no visible label, so set the accessible name explicitly.
const remove = try ui.widgets.Button(.{
.icon_only = true,
.icon_asset = ui.system_icons.trash,
.variant = .ghost,
}).mount(scope, cx);
remove.behavior.interaction.a11y.label = "Delete";命名、更新与许可
- ✓
两种写法。Registry 查询使用 Lucide 的 kebab-case 源名称(
ui.icons.get("circle-alert"));Zig 常量把连字符改为下划线(ui.icons.circle_alert)。 - ✓
自动转义。与 Zig 关键字、基础类型名(包括
iN/uN)同名或以数字开头的常量由生成器转义,例如ui.icons.@"type";动态get不受影响。 - ✓
可枚举。
ui.icons.all是按名称排序的{ name, asset }数组,get在其上做二分查找。 - ✓
与上游一致。SVG 原文件与上游字节相同,便于更新和许可审计;更新时先删除旧文件再复制,避免残留已改名的图标。
- ✓
单独许可。Lucide 使用 ISC License(
src/ui/icons_oss/LICENSE),不在 zenit 根目录 GPL-3.0-only 授权范围内。
# Verify the Lucide profile (test-headless + storybook build); the worktree is not modified
bash scripts/switch_icon_set.sh lucide
# Regenerate the committed provider module after the SVG set changes
zig build gen-icons-lucide
zig build test-ui