Icon Gallery
搜索、预览并复制 zenit 公开图标,理解静态常量、动态 registry 与语义图标层的分工。Search, preview and copy zenit’s public icons, and see how static constants, the dynamic registry and the semantic layer divide the work.
两个图标入口Two entry points
公开构建内置 Lucide(lucide-static v1.31.0)。完整 provider 目录位于 ui.icons,共 2,026 个名称:上游 2,025 个 SVG,加上兼容别名 hand-pointing(与上游 pointer.svg 字节相同)。ui.system_icons 则提供 45 个与 provider 无关的语义角色,zenit 自己的组件只依赖后者,避免把供应商命名写进公共组件契约。Public builds ship Lucide (lucide-static v1.31.0). The full provider catalog is ui.icons with 2,026 names: 2,025 upstream SVGs plus the compatibility alias hand-pointing (byte-identical to upstream pointer.svg). ui.system_icons offers 45 provider-neutral semantic roles; zenit’s own components depend only on those, so no vendor names leak into the public component contract.
ui.system_icons45 个稳定语义角色(close、search、alert、pointer…);可复用的框架 / 包代码用它,换 provider 也能编译45 stable semantic roles (close, search, alert, pointer…); for reusable framework / package code that must compile with any providerui.icons2,026 个 Lucide 名称;产品界面与动态配置用它2,026 Lucide names; for product UI and dynamic configurationui.assets.common17 个历史兼容图标;新代码不再优先使用17 legacy compatibility icons; not preferred for new code完整 2,026 项清单All 2,026 icons
输入名称即时过滤,每次追加 180 个,避免一次创建两千多个 DOM 节点。点击任意图标会给出一行可直接粘贴的 ui.iconTint 调用;需要转义的名称(例如 ui.icons.@"type")已按生成器规则处理。Type to filter instantly; icons load 180 at a time so the page never creates two thousand DOM nodes at once. Click any icon for a ready-to-paste ui.iconTint call; names that need escaping (such as ui.icons.@"type") follow the generator’s rules.
渲染与着色Rendering and tint
图标在构建期由 gen-icons 解析为扁平几何(每个 Asset 带 icon_id 和按尺寸划分的 reps),运行时 ui.iconTint 按逻辑尺寸选取最接近的 rep 写入节点,不在窗口里跑 SVG 引擎;没有预展平几何的 Asset 才回退到 svgTint 栅格化。宽高不是固定像素时,使用 Asset 的默认尺寸(Lucide 为 24)。At build time gen-icons turns each icon into flattened geometry (every Asset carries an icon_id and size-specific reps). At runtime ui.iconTint picks the rep closest to the logical size and writes it to the node — no SVG engine runs in the window; only an Asset without pre-flattened geometry falls back to svgTint rasterization. When width / height aren’t fixed pixels, the Asset’s default size applies (24 for Lucide).
ui.iconTint 最适合跟随主题色;同一个 Asset 可以用不同尺寸和颜色反复使用。ui.icon 不带 tint 参数,默认以白色绘制,所以放在浅色背景上时请改用 iconTint。需要透明度等 BoxStyle 字段时用 ui.iconTintStyled。已挂载的图标要换色(hover、选中态)时调用 node.setTint(color):它同时覆盖 icon 表存储与 svgTint 回退的 image 存储,节点两者都没有时返回 false。ui.iconTint is the best fit for theme-following colors; one Asset can be reused at any size and color. ui.icon takes no tint and draws white, so reach for iconTint on light backgrounds. Use ui.iconTintStyled when you need BoxStyle fields such as opacity. To recolor a mounted icon (hover, selected state), call node.setTint(color): it handles both icon-table storage and the image storage of the svgTint fallback, and returns false when the node has neither.
// 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});
}语义图标契约The semantic icon contract
组件代码优先写 ui.system_icons.close,而不是绑定某个供应商的具体名字。当前 Lucide profile 在 src/ui/system_icons_lucide.zig 里把 45 个角色映射到具体 Asset;用 -Dicon-set 切换 provider 时,组件 API 不变。Component code should say ui.system_icons.close rather than bind to a vendor’s name. The Lucide profile maps all 45 roles to concrete Assets in src/ui/system_icons_lucide.zig; switching providers with -Dicon-set leaves the component API unchanged.
角色名与 Lucide 名不同的映射:Roles whose Lucide name differs:
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";命名、更新与许可Naming, updates and license
- ✓
两种写法。Registry 查询使用 Lucide 的 kebab-case 源名称(
ui.icons.get("circle-alert"));Zig 常量把连字符改为下划线(ui.icons.circle_alert)。Two spellings. Registry lookups use Lucide’s kebab-case source name (ui.icons.get("circle-alert")); Zig constants swap hyphens for underscores (ui.icons.circle_alert). - ✓
自动转义。与 Zig 关键字、基础类型名(包括
iN/uN)同名或以数字开头的常量由生成器转义,例如ui.icons.@"type";动态get不受影响。Automatic escaping. Constants that collide with Zig keywords or primitive type names (includingiN/uN) or start with a digit are escaped by the generator — for exampleui.icons.@"type"; dynamicgetis unaffected. - ✓
可枚举。
ui.icons.all是按名称排序的{ name, asset }数组,get在其上做二分查找。Enumerable.ui.icons.allis a name-sorted array of{ name, asset }entries;getbinary-searches it. - ✓
与上游一致。SVG 原文件与上游字节相同,便于更新和许可审计;更新时先删除旧文件再复制,避免残留已改名的图标。Identical to upstream. SVG files are byte-identical to upstream for clean updates and license audits; delete the old files before copying so renamed icons don’t linger.
- ✓
单独许可。Lucide 使用 ISC License(
src/ui/icons_oss/LICENSE),不在 zenit 根目录 GPL-3.0-only 授权范围内。Separately licensed. Lucide is ISC-licensed (src/ui/icons_oss/LICENSE) and not covered by zenit’s root GPL-3.0-only license.
# 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