From 28367b4fc95ec19dfb8690066403f0746d243456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E6=AC=A3=E6=80=A1?= Date: Tue, 31 Mar 2026 15:49:24 +0800 Subject: [PATCH 01/20] docs: add component inventory for design system gap analysis Scan all prototype pages (login/dashboard/profile) and document all UI elements vs MASTER.md coverage. Identifies 8 undefined components (Toast, Navbar, Sidebar, Mobile Tab Bar, Avatar, Tooltip, Table, List) and missing variants (Button Danger/Ghost/ Loading, Input Readonly). Co-Authored-By: Claude Sonnet 4.6 --- design/system/inventory.md | 248 +++++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 design/system/inventory.md diff --git a/design/system/inventory.md b/design/system/inventory.md new file mode 100644 index 0000000..46518a7 --- /dev/null +++ b/design/system/inventory.md @@ -0,0 +1,248 @@ +# Component Inventory + +> **用途:** 記錄所有 prototype 頁面中出現的 UI elements,對照 MASTER.md 的定義狀態,作為 design system 擴充的依據。 +> +> **更新規則:** 每次新增 prototype 頁面時,同步更新本文件。新 component 進 prototype 前,必須先在 MASTER.md 定義 token。 +> +> **掃描範圍:** `design/prototype/` 所有頁面 +> **最後掃描:** 2026-03-31 +> **掃描頁面:** index.html、login.html、dashboard.html、profile.html + +--- + +## 狀態說明 + +| 狀態 | 意義 | +|------|------| +| ✅ 已定義 | MASTER.md 已有完整規格 | +| ⚠️ 部分定義 | MASTER.md 有提及但規格不完整 | +| ❌ 未定義 | prototype 已使用,但 MASTER.md 尚未定義 | +| 🔒 封存 | 已不再使用 | + +--- + +## Component 清單 + +### ✅ Button + +**MASTER.md 狀態:** 已定義(Primary + Secondary) + +| 變體 | 樣式 | 出現頁面 | MASTER.md | +|------|------|----------|-----------| +| Primary (CTA) | `bg-cta` hover:opacity-90 translateY(-1px) | login, dashboard, profile | ✅ | +| Secondary | `border-primary text-primary` transparent bg | dashboard | ✅ | +| Danger | `text-red-600 hover:bg-red-50 hover:border-red-200` | dashboard (logout) | ❌ 未定義 | +| Ghost / Text | `text-primary` underline on hover | dashboard (view all) | ❌ 未定義 | +| OAuth (Google/GitHub) | `border-slate-200 bg-white` + 品牌 icon | login | ❌ 未定義 | +| Icon-only | `w-9 h-9` no label, icon only | dashboard (mobile menu) | ❌ 未定義 | +| Language Toggle | `border-slate-200 rounded-full` | login, dashboard, profile | ❌ 未定義 | + +**缺少規格:** Loading 狀態(spinner + opacity-70 + cursor-not-allowed)、Disabled 狀態、Danger 變體、Ghost 變體 + +--- + +### ✅ Input + +**MASTER.md 狀態:** 已定義(Normal + Focus + Error) + +| 變體 | 樣式 | 出現頁面 | MASTER.md | +|------|------|----------|-----------| +| Normal | `border-slate-200 rounded-lg` focus:ring-primary | profile | ✅ | +| Error | `border-red-400` focus:ring-red-400 | profile | ✅ | +| Readonly / Disabled | `bg-slate-50 border-slate-100 cursor-not-allowed` | profile (email) | ❌ 未定義 | + +**缺少規格:** Readonly 狀態、字元計數提示(character counter)、必填標記(required indicator) + +--- + +### ✅ Card + +**MASTER.md 狀態:** 已定義(Interactive + Non-interactive) + +| 變體 | 樣式 | 出現頁面 | MASTER.md | +|------|------|----------|-----------| +| Interactive | `border-slate-200 rounded-xl` hover:border-primary translateY(-2px) | dashboard (stat card) | ✅ | +| Non-interactive | `border-slate-200 rounded-xl` 無 hover | dashboard, profile | ✅ | +| Login card | `border-slate-200 rounded-2xl p-8` | login | ⚠️ 尺寸未標準化 | +| Stat card | header + 大數字 + 副文字 + icon 的特定結構 | dashboard | ❌ 未定義結構 | + +--- + +### ✅ Status Badge + +**MASTER.md 狀態:** 已定義(In Progress / Not Started / Submitted / Error) + +| 變體 | 出現頁面 | MASTER.md | +|------|----------|-----------| +| In Progress (warning) | dashboard | ✅ | +| Not Started (info) | dashboard | ✅ | +| Submitted (success) | dashboard | ✅ | +| Role badge (indigo, rounded-full + icon) | profile | ❌ 未定義 | + +--- + +### ✅ Modal + +**MASTER.md 狀態:** 已定義 + +| 變體 | 出現頁面 | MASTER.md | +|------|----------|-----------| +| Confirmation dialog (cancel + confirm) | dashboard (logout) | ✅ | + +**缺少規格:** Escape 鍵關閉行為、click outside 關閉行為、focus trap + +--- + +### ✅ Error / Alert Banner + +**MASTER.md 狀態:** 已定義(Error) + +| 變體 | 出現頁面 | MASTER.md | +|------|----------|-----------| +| Error (red) | login | ✅ | +| Success (green) — Toast 形式 | profile | ❌ 未定義(Toast 與 Banner 需區分) | + +--- + +### ❌ Toast + +**MASTER.md 狀態:** 未定義 + +| 變體 | 樣式 | 出現頁面 | +|------|------|----------| +| Success | `bg-green-50 border-green-200 text-green-700` | profile | +| Error | `bg-red-50 border-red-200 text-red-700` | profile | + +**行為:** 4 秒後自動隱藏、有關閉按鈕、`aria-live="polite"` +**需與 Alert Banner 區分:** Toast 浮動定位、自動消失;Banner 嵌入頁面、手動關閉 + +--- + +### ❌ Navbar / Header + +**MASTER.md 狀態:** 未定義(Page Shell Patterns 有提及高度 56px,但無 component 規格) + +| 元素 | 說明 | +|------|------| +| Logo + wordmark | 左側,連結至首頁 | +| Nav links | Desktop 顯示,active state | +| User menu | Avatar + 名稱,連結至 profile | +| Language toggle | 右側固定 | +| Logout button | Danger 樣式 | +| Mobile hamburger | Icon-only button,展開 mobile drawer | + +--- + +### ❌ Sidebar + +**MASTER.md 狀態:** 未定義(Page Shell Pattern C 有提及寬度 224px,但無 component 規格) + +| 元素 | 說明 | +|------|------| +| Section nav items | active / inactive 狀態 | +| Divider | 分組用 | +| 僅 Desktop 顯示 | `hidden md:flex` | + +--- + +### ❌ Mobile Bottom Tab Bar + +**MASTER.md 狀態:** 未定義 + +| 元素 | 說明 | +|------|------| +| Tab item (icon + label) | active / inactive 狀態 | +| 固定底部 | `fixed bottom-0 h-14` | +| 僅 Mobile 顯示 | `md:hidden` | + +--- + +### ❌ Avatar + +**MASTER.md 狀態:** 未定義 + +| 變體 | 尺寸 | 出現頁面 | +|------|------|----------| +| Small (navbar) | w-8 h-8 | dashboard | +| Large (profile) | w-20 h-20 (desktop) / w-16 h-16 (mobile) | profile | + +**行為(profile):** hover 顯示上傳覆蓋層、支援拖放、檔案驗證(JPG/PNG/WebP, max 5MB) + +--- + +### ❌ Tooltip + +**MASTER.md 狀態:** 未定義 + +| 元素 | 說明 | +|------|------| +| 觸發器 | 小 info icon,tabindex="0" | +| 提示框 | `bg-ink text-white` 絕對定位,底部帶箭頭 | +| 出現時機 | hover + focus | + +--- + +### ❌ Table + +**MASTER.md 狀態:** 未定義 + +| 元素 | 說明 | +|------|------| +| Header row | `bg-slate-50 text-xs uppercase` | +| Body row | hover:bg-slate-50、cursor-pointer | +| Cell | `px-6 py-4` | +| Responsive | `overflow-x-auto` 水平捲動 | + +--- + +### ❌ List (Activity List) + +**MASTER.md 狀態:** 未定義 + +| 元素 | 說明 | +|------|------| +| List item | 左側任務名稱 + 右側日期/分數 | +| Divider | `divide-y divide-slate-100` | + +--- + +### ❌ Divider + +**MASTER.md 狀態:** 未定義 + +| 變體 | 說明 | 出現頁面 | +|------|------|----------| +| 水平線 | `h-px bg-slate-200` | login, profile | +| 文字分隔(「或」) | 線條 + 中間文字 | login | + +--- + +### ⚠️ Link + +**MASTER.md 狀態:** 未定義(Anti-patterns 有提及 `href="#"` 規範,但無 component 規格) + +| 變體 | 樣式 | 出現頁面 | +|------|------|----------| +| Inline text link | `underline hover:text-primary` | login (使用條款) | +| Nav link | `text-slate-600 hover:text-ink hover:bg-slate-50` | dashboard, profile | +| Action link | `text-primary hover:underline` | dashboard (view all) | + +--- + +## 優先補充至 MASTER.md 的項目 + +依使用頻率與即將開發的頁面排序: + +| 優先級 | Component | 理由 | +|--------|-----------|------| +| P1 | **Toast** | profile 已使用,與 Alert Banner 需區分 | +| P1 | **Button — Danger / Ghost / Loading 狀態** | 多頁面使用,規格不完整 | +| P1 | **Input — Readonly 狀態** | profile 已使用 | +| P2 | **Navbar** | 下個頁面必定使用 | +| P2 | **Sidebar** | Annotation task 頁面必定使用 | +| P2 | **Table** | Dashboard 核心元素 | +| P3 | **Avatar** | Upload 行為需規範 | +| P3 | **Tooltip** | 無障礙規範需特別注意 | +| P3 | **Mobile Bottom Tab Bar** | RWD 規範 | +| P4 | **Divider** | 簡單,低優先 | +| P4 | **List** | 簡單,低優先 | From d4e6ce951b63c54aa8dde6b6aa5907b693d3bc0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E6=AC=A3=E6=80=A1?= Date: Tue, 31 Mar 2026 15:52:01 +0800 Subject: [PATCH 02/20] docs: add P1 component specs to design system MASTER.md - Button: add Danger, Ghost, Loading, Disabled variants with summary table and When NOT to use guidelines - Input: add Readonly state spec with Readonly vs Disabled distinction - Toast: add full spec (Success/Error) with position, z-index, auto-dismiss behavior, and Alert Banner vs Toast comparison table Co-Authored-By: Claude Sonnet 4.6 --- design/system/MASTER.md | 162 +++++++++++++++++++++++++++++++++++++ design/system/inventory.md | 10 +-- 2 files changed, 167 insertions(+), 5 deletions(-) diff --git a/design/system/MASTER.md b/design/system/MASTER.md index 47913be..78481e9 100644 --- a/design/system/MASTER.md +++ b/design/system/MASTER.md @@ -182,8 +182,76 @@ Label Suite supports zh-TW / EN. Apply these rules when building bilingual pages transition: all 200ms ease; cursor: pointer; } + +/* Danger Button — destructive actions (logout, delete) */ +.btn-danger { + background: transparent; + color: #B91C1C; /* red-700 */ + border: 1px solid #E2E8F0; + padding: 8px 12px; + border-radius: var(--radius-md); + font-weight: 500; + transition: all 200ms ease; + cursor: pointer; +} + +.btn-danger:hover { + color: #B91C1C; + background: #FEF2F2; /* red-50 */ + border-color: #FECACA; /* red-200 */ +} + +/* Ghost / Text Button — low-emphasis actions (view all, cancel) */ +.btn-ghost { + background: transparent; + color: var(--color-primary); + border: none; + padding: 8px 12px; + border-radius: var(--radius-md); + font-weight: 500; + transition: all 200ms ease; + cursor: pointer; +} + +.btn-ghost:hover { + text-decoration: underline; +} + +/* Loading state — applies to any button variant */ +.btn-loading { + opacity: 0.7; + cursor: not-allowed; + pointer-events: none; +} + +/* Disabled state — applies to any button variant */ +.btn-disabled, +button[disabled] { + opacity: 0.4; + cursor: not-allowed; + pointer-events: none; +} ``` +**Button Variants Summary:** + +| Variant | Use case | When NOT to use | +|---------|----------|-----------------| +| Primary (`btn-primary`) | 每頁最重要的單一 CTA | 同頁面出現兩個以上 | +| Secondary (`btn-secondary`) | 次要操作、與 Primary 並列 | 獨立使用時(改用 Ghost) | +| Danger (`btn-danger`) | 破壞性操作(登出、刪除) | 一般取消操作(用 Secondary) | +| Ghost (`btn-ghost`) | 低優先操作(查看全部、跳過) | 需要明顯視覺重量時 | + +**Button States:** + +| State | Tailwind classes | +|-------|-----------------| +| Default | — | +| Hover | `hover:opacity-90` (primary) / `hover:underline` (ghost) | +| Focus | `focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2` | +| Loading | `opacity-70 cursor-not-allowed` + spinner icon | +| Disabled | `opacity-40 cursor-not-allowed pointer-events-none` | + ### Cards ```css @@ -225,8 +293,31 @@ Label Suite supports zh-TW / EN. Apply these rules when building bilingual pages .input.error { border-color: #B91C1C; } + +/* Readonly — managed by system, not user-editable (e.g. SSO email) */ +.input[readonly], +.input.readonly { + background: #F8FAFC; /* slate-50 */ + border-color: #F1F5F9; /* slate-100 */ + color: #94A3B8; /* slate-400 */ + cursor: not-allowed; +} ``` +**Input States:** + +| State | Visual cue | When to use | +|-------|-----------|-------------| +| Default | `border-slate-200` | 可編輯欄位 | +| Focus | `border-primary` + ring | 使用者聚焦時 | +| Error | `border-red-400` + ring-red | 驗證失敗 | +| Readonly | `bg-slate-50 border-slate-100 text-slate-400 cursor-not-allowed` | 系統管理欄位(如 SSO email) | +| Disabled | `opacity-40 cursor-not-allowed` | 條件未達成不可使用 | + +**Readonly vs Disabled 區分:** +- **Readonly** — 資料存在且有意義,只是不能修改(e.g. email 由 SSO 管理);仍可被表單提交 +- **Disabled** — 功能目前不可用;不會被表單提交 + ### Modals ```css @@ -275,6 +366,77 @@ Label Suite supports zh-TW / EN. Apply these rules when building bilingual pages ``` +**Alert Banner vs Toast 區分:** + +| | Alert Banner | Toast | +|---|---|---| +| **位置** | 嵌入頁面流(inline) | 浮動固定(fixed,右下角) | +| **消失方式** | 手動關閉 或 永久顯示 | 4 秒後自動消失,可手動關閉 | +| **使用時機** | 頁面級錯誤(登入失敗) | 操作結果回饋(儲存成功) | +| **aria** | `role="alert"` | `aria-live="polite"` | + +### Toast + +用於操作後的即時回饋(儲存成功、更新失敗等),浮動顯示於右下角,4 秒後自動消失。 + +```html + + +``` + +**Toast 規格:** + +| 屬性 | 值 | +|------|---| +| 位置 | `fixed bottom-6 right-6` | +| z-index | `400`(Toast 層,高於 Modal) | +| 最大寬度 | `max-w-sm`(384px) | +| 自動消失 | 4000ms | +| 動畫 | fade-in 150ms / fade-out 150ms(`transition-opacity`) | +| 陰影 | `shadow-md`(浮動感,Toast 是允許陰影的例外情境) | + +**Toast Variants:** + +| Variant | Color role | 使用時機 | +|---------|-----------|---------| +| Success | `bg-green-50 border-green-200 text-green-700` | 操作成功(儲存、更新) | +| Error | `bg-red-50 border-red-200 text-red-700` | 操作失敗(網路錯誤、伺服器錯誤) | + +**When NOT to use Toast:** +- ❌ 頁面級錯誤(登入失敗)→ 改用 Alert Banner +- ❌ 需要使用者確認的操作 → 改用 Modal +- ❌ 重要警告不應自動消失 → 改用 Alert Banner + --- ## Style Guidelines diff --git a/design/system/inventory.md b/design/system/inventory.md index 46518a7..db910f8 100644 --- a/design/system/inventory.md +++ b/design/system/inventory.md @@ -233,11 +233,11 @@ 依使用頻率與即將開發的頁面排序: -| 優先級 | Component | 理由 | -|--------|-----------|------| -| P1 | **Toast** | profile 已使用,與 Alert Banner 需區分 | -| P1 | **Button — Danger / Ghost / Loading 狀態** | 多頁面使用,規格不完整 | -| P1 | **Input — Readonly 狀態** | profile 已使用 | +| 優先級 | Component | 理由 | 狀態 | +|--------|-----------|------|------| +| P1 | **Toast** | profile 已使用,與 Alert Banner 需區分 | ✅ 已補充至 MASTER.md | +| P1 | **Button — Danger / Ghost / Loading 狀態** | 多頁面使用,規格不完整 | ✅ 已補充至 MASTER.md | +| P1 | **Input — Readonly 狀態** | profile 已使用 | ✅ 已補充至 MASTER.md | | P2 | **Navbar** | 下個頁面必定使用 | | P2 | **Sidebar** | Annotation task 頁面必定使用 | | P2 | **Table** | Dashboard 核心元素 | From a827fa2609fbaf571f1e698a76137d77011e0a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E6=AC=A3=E6=80=A1?= Date: Tue, 31 Mar 2026 15:56:00 +0800 Subject: [PATCH 03/20] docs: add P2 component specs to design system MASTER.md - Navbar: structure, sticky spec, nav link states, mobile drawer, accessibility requirements - Sidebar: width/z-index/spacing spec, nav item states, divider, When NOT to use - Table: full HTML structure, cell specs, overflow-x-auto pattern, accessibility (scope/aria-label), When NOT to use Co-Authored-By: Claude Sonnet 4.6 --- design/system/MASTER.md | 137 +++++++++++++++++++++++++++++++++++++ design/system/inventory.md | 6 +- 2 files changed, 140 insertions(+), 3 deletions(-) diff --git a/design/system/MASTER.md b/design/system/MASTER.md index 78481e9..e1fb24c 100644 --- a/design/system/MASTER.md +++ b/design/system/MASTER.md @@ -437,6 +437,143 @@ button[disabled] { - ❌ 需要使用者確認的操作 → 改用 Modal - ❌ 重要警告不應自動消失 → 改用 Alert Banner +### Navbar + +頂部固定導覽列,用於 Pattern A(Dashboard)與 Pattern C(Profile)頁面。 + +**規格:** + +| 屬性 | 值 | +|------|---| +| 高度 | `h-16`(64px) | +| 背景 | `bg-white` | +| 底部邊線 | `border-b border-slate-200` | +| 定位 | `sticky top-0 z-[200]` | +| 內容寬度 | `max-w-7xl mx-auto px-4 sm:px-6 lg:px-8` | + +**結構(左 → 右):** + +``` +[ Logo ] ─────── [ Nav links (desktop only) ] ─────── [ User menu ] + ├ Avatar + name → profile + ├ Language toggle + ├ Logout button (danger) + └ Mobile hamburger (mobile only) +``` + +**Nav link states:** + +| State | Classes | +|-------|---------| +| Active | `text-primary font-medium bg-surface rounded-lg` + `aria-current="page"` | +| Inactive | `text-slate-600 hover:text-ink hover:bg-slate-50 rounded-lg` | +| Disabled | `aria-disabled="true"` + same as inactive(無 pointer-events-none,保留 tab stop) | + +**Mobile drawer(`md:hidden`):** +- 展開後位於 navbar 下方,`border-t border-slate-200` +- 項目與 desktop nav link 相同,改為 `block` layout +- 包含 Profile 連結(desktop 的 avatar 在 mobile 隱藏) + +**Accessibility:** +- `
` +- `