197 lines
10 KiB
Markdown
197 lines
10 KiB
Markdown
# DS — Design System — <PROJECT>
|
||
|
||
| | |
|
||
|---|---|
|
||
| **Version** | 1.0 |
|
||
| **Date** | YYYY-MM-DD |
|
||
| **Author** | <BA/Design> (skill ba-design, activity `ds`) |
|
||
| **Status** | 🟡 Draft |
|
||
| **Approved by** | Designer: — · PO: — |
|
||
| **Source** | UICONV_<PROJECT> v1.0 · brand guideline: <đường dẫn / "chưa có — OQ-nnn"> · design system tham chiếu: <tên + version / "chưa có"> · SAD §7 (nếu có) |
|
||
| **Scope** | Toàn project — mọi `HIFI`, `FIGMA`, `DSPEC` có `PRODUCT = screen` |
|
||
| **Profile** | `screen · … · …` |
|
||
| **Tệp kèm** | `00-index/ds/tokens.json` (nguồn sự thật) · `ds/tokens.css` (sinh từ json) · `ds/components.html` (component sheet, mở bằng trình duyệt) |
|
||
|
||
## Change Log
|
||
|
||
| Version | Date | Người sửa | Thay đổi | CR |
|
||
|---|---|---|---|---|
|
||
| 1.0 | | | Bản đầu | — |
|
||
|
||
> **Vai trò của tài liệu này.** `UICONV` nói *hành xử thế nào* (phân trang, vị trí toast, validate lúc nào);
|
||
> tài liệu này nói *trông thế nào* (màu, chữ, khoảng cách, bo góc, đổ bóng, trạng thái hover/focus/disabled).
|
||
> `HIFI` và `FIGMA` chỉ dùng token và component ở đây; muốn khác phải có dòng ở §8.
|
||
>
|
||
> **Thứ tự ưu tiên khi lệch:** Brand guideline của khách > Design system tham chiếu (nếu dự án đã chọn) >
|
||
> `DS` này > `HIFI` từng US. Thiếu brand ⇒ giá trị ở đây là **đề xuất trung tính** chờ Designer/PO chốt — ghi `OQ`, không tự coi là đã duyệt.
|
||
|
||
---
|
||
|
||
## 0. Nguồn và độ tin cậy
|
||
|
||
| | |
|
||
|---|---|
|
||
| **Brand guideline** | *(file/URL + version, hoặc "Chưa có" ⇒ mọi giá trị màu/chữ ở §1 là placeholder trung tính, `OQ-nnn`)* |
|
||
| **Design system tham chiếu** | *(Material 3 / Ant Design / nội bộ… + version — theo `OQ` ở UICONV §0 hoặc quyết định của Tech Lead `DEC-nn`)* |
|
||
| **Prototype đã có** | *(Figma / HTML / SAD §7 — token được trích từ đây nếu có)* |
|
||
| **Ai sở hữu** | BA/Design đề xuất · **Designer duyệt** visual · PO duyệt giọng văn/nhận diện · Dev FE xác nhận khả năng hiện thực với stack đã chọn |
|
||
| **Độ tin cậy** | 🟢 Trích từ brand/DS thật · 🟡 Suy từ prototype · 🔴 Đề xuất trung tính, chưa có nguồn — *(chọn một, ghi lý do)* |
|
||
|
||
## 1. Token
|
||
|
||
*Bảng này tóm tắt; giá trị chuẩn ở `ds/tokens.json`. Sửa ⇒ sửa json, sinh lại css, chạy `design-check.mjs`.*
|
||
|
||
### 1.1 Màu
|
||
|
||
| Token | Giá trị | Dùng cho | Nguồn |
|
||
|---|---|---|---|
|
||
| `color.bg.canvas` | | Nền trang | |
|
||
| `color.bg.surface` | | Card, bảng, modal | |
|
||
| `color.bg.subtle` | | Header bảng, vùng phụ | |
|
||
| `color.border.default` / `.strong` | | Viền chia / viền ô nhập | |
|
||
| `color.text.primary` / `.secondary` / `.disabled` / `.inverse` | | Chữ chính / phụ / vô hiệu / trên nền đậm | |
|
||
| `color.brand.primary` / `-hover` / `-subtle` | | Nút chính, liên kết, focus / hover / nền chọn | |
|
||
| `color.status.danger` / `success` / `warning` (+ `-subtle`) | | Lỗi / thành công / cảnh báo | |
|
||
|
||
### 1.2 Chữ
|
||
|
||
| Token | Giá trị | Dùng cho |
|
||
|---|---|---|
|
||
| `font.family.base` | | Toàn hệ thống — *(font brand hay system stack? nguồn)* |
|
||
| `font.size.xs / sm / md / lg / xl / 2xl` | 12 / 14 / 16 / 20 / 24 / 32 px | Hint, nhãn / body / nhãn field lớn, h3 / h2 / h1 / số KPI |
|
||
| `font.weight.regular / semibold` | 400 / 600 | |
|
||
| `font.line-height.tight / normal` | 1.25 / 1.5 | Tiêu đề / body |
|
||
|
||
### 1.3 Khoảng cách, bo góc, đổ bóng, kích thước
|
||
|
||
| Token | Giá trị | Ghi chú |
|
||
|---|---|---|
|
||
| `space.1 … 12` | 4 · 8 · 12 · 16 · 24 · 32 · 48 px | Thang 4px; không dùng số ngoài thang |
|
||
| `radius.sm / md / pill` | 4 / 8 / 999 px | Nút, ô nhập / card, modal / badge |
|
||
| `shadow.sm / md` | | Card nổi / modal, toast |
|
||
| `size.control.desktop / touch` | 36 / 44 px | Chiều cao nút, ô nhập; **mobile ≥ 44px** (hit target) |
|
||
| `size.icon` | 20 px | Icon inline |
|
||
| `size.content-max` | 1200 px | Khớp UICONV §1 max-width |
|
||
| `breakpoint.tablet / desktop` | 768 / 1024 px | **Phải khớp UICONV §1** |
|
||
|
||
## 2. Thang chữ áp dụng
|
||
|
||
| Cấp | Token size / weight / line-height | Dùng ở |
|
||
|---|---|---|
|
||
| H1 — tiêu đề màn hình | xl / semibold / tight | `C01` kiểu "Tiêu đề cấp 1" |
|
||
| H2 — tiêu đề vùng, modal | lg / semibold / tight | |
|
||
| H3 — tiêu đề card | md / semibold / tight | |
|
||
| Body | sm / regular / normal | Bảng, form, câu dẫn |
|
||
| Nhãn field, hint, header bảng | xs / semibold hoặc regular / normal | |
|
||
|
||
## 3. Từ vựng component — ánh xạ ba chiều
|
||
|
||
*Cột 1 = UICONV §11 (BA) · cột 2 = lớp CSS trong `ds/components.html` (HIFI dùng) · cột 3 = component của design system tham chiếu (Dev FE dùng). Mọi kiểu trình bày xuất hiện trong `WF` phải có dòng ở đây.*
|
||
|
||
| Kiểu trình bày (UICONV §11) | Lớp DS | Component DS tham chiếu | Ghi chú |
|
||
|---|---|---|---|
|
||
| Nút chính | `.ds-btn.ds-btn--primary` | | Một nút chính mỗi màn hình |
|
||
| Nút phụ | `.ds-btn.ds-btn--secondary` | | |
|
||
| Nút nguy hiểm | `.ds-btn.ds-btn--danger` | | Luôn kèm modal xác nhận |
|
||
| Liên kết | `.ds-link` | | |
|
||
| Ô nhập / Ô nhập số | `.ds-field` + `.ds-input` | | Nhãn trên field, `*` sau nhãn |
|
||
| Chọn 1 (≤7) / (>7) | `.ds-check` radio / `.ds-select` | | |
|
||
| Chọn nhiều | `.ds-check` checkbox | | |
|
||
| Công tắc | `.ds-switch` | | |
|
||
| Bộ đếm số lượng | `.ds-stepper` | | |
|
||
| Bảng / Card | `.ds-table-wrap` / `.ds-cards > .ds-card` | | Bảng desktop → card mobile (UICONV §3) |
|
||
| Badge trạng thái | `.ds-badge[--info/--success/--warning/--danger]` | | Ánh xạ trạng thái BR §3 → biến thể: *(bảng riêng bên dưới)* |
|
||
| Tab | `.ds-tabs > .ds-tab` | | |
|
||
| Modal / Drawer / Bottom-sheet | `.ds-modal-backdrop > .ds-modal` | | Nút chính bên phải |
|
||
| Toast | `.ds-toast[--error]` | | Vị trí, thời lượng theo UICONV §5 |
|
||
| Banner trong vùng | `.ds-banner[--error/--warning]` | | |
|
||
| Skeleton | `.ds-skeleton` | | |
|
||
| Trạng thái rỗng (2 loại) | `.ds-empty` (có minh hoạ) / `.ds-empty.ds-empty--filter` (không) | | 🔴 Hai loại phải trông khác nhau |
|
||
| Trang trạng thái | `.ds-status-page` | | 404 / 403 / lỗi toàn trang |
|
||
|
||
**Ánh xạ trạng thái nghiệp vụ → badge** *(từ `BR` §3 của từng module; bổ sung dần)*:
|
||
|
||
| Trạng thái (BR) | Biến thể badge | Nhãn nguyên văn (SRS §4.2) |
|
||
|---|---|---|
|
||
| | | |
|
||
|
||
## 4. Trạng thái component
|
||
|
||
*Mỗi ô ghi thay đổi thị giác (token nào đổi). "—" = không có trạng thái đó. Ô trống = chưa thiết kế.*
|
||
|
||
| Component | Default | Hover | Focus | Disabled | Loading | Error / Invalid | Selected |
|
||
|---|---|---|---|---|---|---|---|
|
||
| Nút chính | `brand.primary` | `brand.primary-hover` | ring 2px `focus.ring` | opacity .45 + **tooltip lý do** | spinner + nhãn "Đang …" | — | — |
|
||
| Nút phụ | surface + `border.strong` | `bg.subtle` | ring | opacity .45 + tooltip | spinner | — | — |
|
||
| Ô nhập | `border.strong` | `text.secondary` | `brand.primary` + ring | `bg.subtle`, chữ disabled | — | `status.danger` + message dưới | — |
|
||
| Dòng bảng | surface | `bg.canvas` | ring | — | skeleton | — | `brand.primary-subtle` |
|
||
| Tab | `text.secondary` | | ring | | | | `brand.primary` + gạch dưới 2px |
|
||
| Card | | | | | | | |
|
||
|
||
## 5. Icon
|
||
|
||
| | |
|
||
|---|---|
|
||
| **Bộ icon** | *(tên bộ + version / "inline SVG tự vẽ theo mẫu components.html")* |
|
||
| **Quy cách** | Lưới 24, stroke 1.75, `stroke-linecap: round`, hiển thị 20px (`size.icon`), màu `currentColor` |
|
||
| **Cấm** | Emoji, ký hiệu ✓✕▲ dạng chữ thay icon (trừ mũi tên phân trang `‹ ›`), icon tô đặc trộn với icon nét |
|
||
| **Danh sách dùng** | search · plus · close · chevron-down · back · check · alert · trash · filter · *(bổ sung theo WF)* |
|
||
|
||
## 6. Tương phản và khả năng truy cập
|
||
|
||
*Kết quả chạy `node scripts/design-check.mjs --tokens ds/tokens.json` — chép nguyên văn, không sửa tay.*
|
||
|
||
| Cặp (fg / bg) | Dùng cho | Tỷ lệ | Ngưỡng | ☐/✅ |
|
||
|---|---|---|---|---|
|
||
| `text.primary` / `bg.surface` | Chữ thường | | 4.5 | |
|
||
| `text.secondary` / `bg.surface` | Hint, chữ phụ | | 4.5 | |
|
||
| `text.inverse` / `brand.primary` | Nhãn nút chính | | 4.5 | |
|
||
| `text.inverse` / `status.danger` | Nhãn nút nguy hiểm | | 4.5 | |
|
||
| `brand.primary` / `bg.surface` | Liên kết | | 4.5 | |
|
||
| `status.danger` / `bg.surface` | Message lỗi | | 4.5 | |
|
||
| `border.strong` / `bg.surface` | Viền ô nhập (non-text) | | 3.0 | |
|
||
|
||
| Quy tắc | Giá trị | Nguồn |
|
||
|---|---|---|
|
||
| Hit target tối thiểu trên mobile | 44 × 44 px | WCAG 2.5.8 / `size.control.touch` |
|
||
| Focus luôn thấy được | ring 2px `focus.ring`, offset 2px | WCAG 2.4.7 |
|
||
| Không truyền nghĩa chỉ bằng màu | Badge luôn có nhãn chữ; lỗi luôn có icon + text | WCAG 1.4.1 |
|
||
| Mọi ô nhập có nhãn | `<label>` bao ngoài hoặc `aria-label` | WCAG 1.3.1 |
|
||
| Thứ tự focus | Theo `WF` §3.x.6 của từng US | |
|
||
|
||
## 7. Motion
|
||
|
||
| Việc | Thời lượng | Easing | Ghi chú |
|
||
|---|---|---|---|
|
||
| Hover nút / dòng | 120 ms | ease | |
|
||
| Toast vào/ra | 200 ms | ease-out | Thời gian hiển thị theo UICONV §5 |
|
||
| Modal mở | 160 ms | ease-out | Không dùng bounce |
|
||
| Skeleton shimmer | 1.2 s lặp | linear | Tắt khi `prefers-reduced-motion` |
|
||
|
||
## 8. Ngoại lệ đã duyệt
|
||
|
||
*`HIFI`/`FIGMA` lệch DS ⇒ phải có dòng ở đây. Không có dòng ⇒ lệch là lỗi.*
|
||
|
||
| # | Tài liệu | Token/component lệch | DS nói | Thực tế | Vì sao | Ai duyệt | Ngày |
|
||
|---|---|---|---|---|---|---|---|
|
||
|
||
## 9. Open Questions
|
||
|
||
| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì |
|
||
|---|---|---|---|---|
|
||
|
||
---
|
||
|
||
## Tự chấm
|
||
|
||
| # | Tiêu chí | ☐/✅ |
|
||
|---|---|---|
|
||
| 1 | `tokens.json` parse được; `tokens.css` sinh khớp (design-check T1 = ok) | |
|
||
| 2 | Mọi cặp tương phản ở §6 đạt ngưỡng (design-check T2 = ok) | |
|
||
| 3 | §3: mọi kiểu trình bày của UICONV §11 có lớp DS **và** có mặt trong `components.html` | |
|
||
| 4 | §4: mọi component có đủ default / hover / focus / disabled; component nhập liệu có Error | |
|
||
| 5 | `breakpoint.*` khớp UICONV §1; `size.content-max` khớp UICONV §1 | |
|
||
| 6 | Hai trạng thái rỗng trong `components.html` trông khác nhau | |
|
||
| 7 | §0 ghi rõ độ tin cậy; giá trị placeholder có `OQ` | |
|
||
| 8 | Có chữ ký Designer (hoặc PO ký thay + `DEC-nn` "không có Designer") | |
|