Prisma

--- description: Hướng dẫn quản lý và sử dụng bộ Icon (Lucide Icons) trong Design System

Icon Component & Guidelines

Design System của chúng ta sử dụng bộ Lucide Icons (https://lucide.dev) làm quy chuẩn mặc định, đảm bảo tính thẩm mỹ, hiện đại và nhất quán trên toàn bộ các ứng dụng. Lucide là bộ icon open-source với 1,500+ icon, stroke-based, hỗ trợ currentColor hoàn hảo. Icon không được phép sử dụng kích thước hardcode (vd: 16px) mà phải được mapping từ hệ thống Icon Sizing Tokens.

CRITICAL RULES — ĐỌC TRƯỚC KHI SỬ DỤNG

Rule 1: CẤM DÙNG TEXT EMOJI THAY ICON KHÔNG BAO GIỜ sử dụng Unicode emoji (ℹ️ ✅ ⚠️ ❌ 🔍 🔔 📋 🗑 🖊 ⭐ ⬅️ ➡️...) để thay thế icon trong UI. Emoji hiển thị KHÔNG nhất quán giữa OS/browser, KHÔNG thể style bằng CSS, và phá vỡ design system. → PHẢI dùng SVG icon từ design-system/assets/icons/.

Rule 2: CẤM DÙNG ICON LIBRARY KHÁC CHỈ được phép sử dụng icon từ thư mục design-system/assets/icons/. KHÔNG dùng: FontAwesome, Material Icons, Heroicons, Phosphor Icons, Tabler Icons, Ionicons, Feather Icons, hoặc bất kỳ bộ icon bên ngoài nào khác. Nếu cần icon chưa có → thêm từ Lucide vào assets/icons/ theo quy trình mục 8.

Vi phạm 2 rule trên sẽ bị reject trong code review.

1. Tại sao chọn Lucide?

Tiêu chí Lucide Icons
Số lượng 1,500+ icons, cập nhật hàng tuần
Phong cách Stroke-based, clean, consistent
Màu sắc Dùng currentColor → kế thừa từ parent
Kích thước mặc định 24×24, viewBox 0 0 24 24
Stroke width Mặc định 2, có thể tuỳ chỉnh
License ISC License (free for commercial use)
Framework support React, Vue, Svelte, Angular, Web Components, SVG static
Package lucide, lucide-react, lucide-vue-next, lucide-static

2. Icon Variants

Lucide hỗ trợ tuỳ chỉnh thông qua stroke-width:

  • Regular (stroke-width: 2): Sử dụng cho trạng thái mặc định. Phù hợp Sidebar, navigation-menu, Buttons.
  • Light (stroke-width: 1.5): Sử dụng cho icon trang trí, minh họa, Empty State.
  • Bold (stroke-width: 2.5): Sử dụng cho điểm nhấn mạnh, Active/Selected state.

Quy tắc sử dụng variant:

Ngữ cảnh Stroke-width Ví dụ
Default / Inactive 2 Sidebar, navigation-menu, Standard button
Active / Selected 2.5 Active tab, Selected nav item
Trang trí / Minh họa 1.5 Hero section, Empty state
Compact / Small 2 Badge, Toast, Micro button

3. Token Kích Thước (Icon Sizing)

Hệ thống token đã ánh xạ chuẩn (xem ATOMIC-MAPPING.md → mục icon). Bất kỳ icon nào cũng phải sử dụng một trong các biến kích thước này:

Token Kích thước Gốc (Spacing Token) Kích thước Ngữ cảnh sử dụng (Use case)
var(--icon-sm) var(--spacing-4) 16px Badge, Hint text, Micro button, Input có kích thước hẹp.
var(--icon-md) var(--spacing-5) 20px Nút bấm tiêu chuẩn (Standard Button), Input field, Dropdown.
var(--icon-lg) var(--spacing-6) 24px Default Icon, navigation-menu, Sidebar tiêu chuẩn.
var(--icon-xl) var(--spacing-8) 32px Icon đại diện trạng thái, Empty State, Layout lớn.
var(--icon-2xl) var(--spacing-12) 48px Icon minh họa, Hero section, Empty State trọng tâm.

4. Màu sắc (Icon Colors)

Tuyệt đối KHÔNG gán màu cứng (Hardcode) trực tiếp lên thẻ <svg> (Ví dụ: Không dùng <svg stroke="#FFFFFF">).

  • Phải luôn sử dụng stroke="currentColor" (cho outline icons) hoặc fill="currentColor" (cho filled icons).
  • Màu thực tế sẽ được Component bọc (wrapper) truyền xuống hoặc thông qua class tiện ích.
  • CSS Example:
    css
    /* Icon linh động tự kế thừa màu của cha */
    .ds-icon {
        color: inherit;
    }
    
    /* Icon theo ngữ cảnh trạng thái */
    .ds-icon-primary { color: var(--primary); }
    .ds-icon-muted { color: var(--muted-foreground); }
    .ds-icon-danger { color: var(--destructive); }
    .ds-icon-success { color: var(--success); }
    .ds-icon-warning { color: var(--warning); }
    .ds-icon-info { color: var(--info); }

5. Base CSS Classes bắt buộc

Khi triển khai trên UI, bạn BẮT BUỘC phải tạo ra base class quản lý Icon nhằm tránh bị vỡ layout trong Flexbox/Grid:

css
/* ds-icon: Base class bắt buộc cho mọi Lucide Icons */
.ds-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0; /* Rất quan trọng: Ngăn Flexbox bóp méo icon */
    
    /* Kích thước mặc định */
    width: var(--icon-lg); 
    height: var(--icon-lg);
    color: inherit;
}

.ds-icon svg {
    width: 100%;
    height: 100%;
    /* Lucide dùng stroke — KHÔNG fill */
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* Các biến thể kích thước */
.ds-icon-sm { width: var(--icon-sm); height: var(--icon-sm); }
.ds-icon-md { width: var(--icon-md); height: var(--icon-md); }
.ds-icon-lg { width: var(--icon-lg); height: var(--icon-lg); }
.ds-icon-xl { width: var(--icon-xl); height: var(--icon-xl); }
.ds-icon-2xl { width: var(--icon-2xl); height: var(--icon-2xl); }

6. Cấu trúc HTML áp dụng (Implementation)

Cách 1: Inline SVG (Khuyến nghị)

Copy SVG trực tiếp từ https://lucide.dev/icons:

html
<span class="ds-icon ds-icon-md ds-icon-primary">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <circle cx="11" cy="11" r="8"/>
        <path d="m21 21-4.3-4.3"/>
    </svg>
</span>

Cách 2: Sử dụng tên icon từ assets

Reference SVG file trong design-system/assets/icons/:

html
<!-- Sử dụng img tag -->
<span class="ds-icon ds-icon-md">
    <img src="assets/icons/search.svg" alt="Search" />
</span>

Cách 3: Framework (React/Vue/etc.)

jsx
// React
import { Search, Bell, User } from 'lucide-react';

<Search className="ds-icon ds-icon-md" />
<Bell size={20} />
<User size={24} strokeWidth={2} />

7. Bộ Icon mặc định (Default Set)

Design System bundle sẵn 42 icon phổ biến nhất, phân theo category:

Navigation (10 icons)

arrow-left arrow-right arrow-up arrow-down chevron-left chevron-right chevron-up chevron-down menu home

Action (14 icons)

plus minus x check search filter sliders-horizontal pencil trash copy upload download share link

Feedback (5 icons)

info triangle-alert circle-check circle-x bell

Content (8 icons)

file folder clipboard image calendar list grid layout-dashboard

User & Auth (5 icons)

user log-in log-out eye settings

Media & Social (5 icons)

star heart globe sun moon

Brand (1 icon)

github

8. Cách thêm Icon mới

  1. Vào https://lucide.dev/icons và tìm icon cần dùng
  2. Copy SVG code
  3. Đảm bảo SVG đã có: fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
  4. Lưu file SVG vào design-system/assets/icons/ với tên kebab-case
  5. Cập nhật icon-catalog.tokens.json → thêm tên icon vào category phù hợp
  6. Chạy node scripts/build-docs.js để cập nhật docs

9. Migration từ Heroicons

Nếu project cũ đang dùng Heroicons, lưu ý:

  • Lucide icons dùng stroke thay vì fill cho variant outline
  • Thay đổi trong .ds-icon svg: fill: currentColorfill: none; stroke: currentColor
  • Hầu hết icon Lucide có tên tương đương với Heroicons (vd: arrow-right, chevron-down, bell)
  • Xem bảng mapping đầy đủ tại: https://lucide.dev/guide/comparison

10. ⛔ Governance — Quy tắc bắt buộc

10.1. CẤM tuyệt đối dùng Text Emoji thay Icon

❌ SAI (Emoji) ✅ ĐÚNG (Lucide SVG) Tên icon file
ℹ️ <span class="ds-icon"><svg>...</svg></span> info.svg
<span class="ds-icon"><svg>...</svg></span> circle-check.svg
⚠️ <span class="ds-icon"><svg>...</svg></span> triangle-alert.svg
<span class="ds-icon"><svg>...</svg></span> circle-x.svg
🔍 <span class="ds-icon"><svg>...</svg></span> search.svg
🔔 <span class="ds-icon"><svg>...</svg></span> bell.svg
📋 <span class="ds-icon"><svg>...</svg></span> clipboard.svg
🗑 <span class="ds-icon"><svg>...</svg></span> trash.svg
✏️ <span class="ds-icon"><svg>...</svg></span> pencil.svg
<span class="ds-icon"><svg>...</svg></span> star.svg
❤️ <span class="ds-icon"><svg>...</svg></span> heart.svg

Lý do:

  • Emoji hiển thị khác nhau giữa Windows, macOS, iOS, Android
  • Emoji KHÔNG thể điều chỉnh color, size, stroke-width qua CSS
  • Emoji phá vỡ visual consistency của design system
  • Emoji có kích thước không đồng nhất giữa các font

10.2. CẤM dùng Icon Library ngoài danh sách cho phép

Chỉ được phép dùng icon từ:

text
design-system/assets/icons/  ← 53 icons hiện tại

KHÔNG được phép import/reference:

  • ❌ FontAwesome (fa-*)
  • ❌ Material Icons (material-icons)
  • ❌ Heroicons (@heroicons/*)
  • ❌ Phosphor Icons (phosphor-icons)
  • ❌ Tabler Icons (@tabler/icons)
  • ❌ Ionicons (ionicons)
  • ❌ Feather Icons (feather-icons)
  • ❌ Bootstrap Icons (bi-*)
  • ❌ Bất kỳ CDN icon nào

Nếu cần icon chưa có: Theo quy trình mục 8 để thêm icon mới từ Lucide.

10.3. Mapping Icon theo Component

Các component PHẢI sử dụng đúng icon được chỉ định:

Component Ngữ cảnh Icon bắt buộc (Lucide name)
Alert (info) Icon trạng thái info
Alert (success) Icon trạng thái circle-check
Alert (warning) Icon trạng thái triangle-alert
Alert (destructive) Icon trạng thái circle-x
Toast (info/default) Icon trạng thái info
Toast (success) Icon trạng thái circle-check
Toast (warning) Icon trạng thái triangle-alert
Toast (destructive) Icon trạng thái circle-x
Modal / Drawer Close button x
Accordion Expand indicator chevron-down
Breadcrumb Separator chevron-right
Breadcrumb Home icon home
Input (search) Leading icon search
Input (password) Toggle visibility eye
Select Dropdown arrow chevron-down
Checkbox Checked state check
navigation-menu Search action search
navigation-menu Notifications bell
navigation-menu Mobile menu menu
Sidebar Collapse toggle chevron-left / chevron-right
Dropdown Delete action trash
Dropdown Copy action copy
Dropdown Edit action pencil
Dropdown Share action share
Badge Close/remove x
Empty State Illustration Theo ngữ cảnh (file, search, inbox...)