Icon Gallery
zenit 공개 아이콘을 검색·미리 보기·복사하고, 정적 상수, 동적 registry, 시맨틱 레이어가 어떻게 역할을 나누는지 알아봅니다.
두 가지 진입점
공개 빌드에는 Lucide(lucide-static v1.31.0)가 포함됩니다. 전체 provider 카탈로그는 ui.icons이며 이름이 2,026개입니다. 업스트림 SVG 2,025개에 호환 별칭 hand-pointing(업스트림 pointer.svg와 바이트 단위로 동일)을 더한 것입니다. ui.system_icons는 provider와 무관한 시맨틱 역할 45개를 제공합니다. zenit 자체 컴포넌트는 이것에만 의존하므로 벤더 이름이 공개 컴포넌트 계약에 새어 들어가지 않습니다.
ui.system_icons안정적인 시맨틱 역할 45개(close, search, alert, pointer…); 어떤 provider로도 컴파일되어야 하는 재사용 가능한 프레임워크 / 패키지 코드용ui.iconsLucide 이름 2,026개; 제품 UI와 동적 구성용ui.assets.common레거시 호환 아이콘 17개; 새 코드에는 권장하지 않음아이콘 2,026개 전체
이름을 입력하면 즉시 필터링됩니다. 아이콘은 180개씩 불러오므로 페이지가 DOM 노드 2천여 개를 한 번에 만들지 않습니다. 아이콘을 클릭하면 바로 붙여 넣을 수 있는 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 프로필은 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