@qijenchen/design-system 0.1.0-beta.71 → 0.1.0-beta.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AppShell/_demo-helpers.d.ts +3 -1
- package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -1
- package/ds-canonical/fork/governance.lock +106 -2
- package/ds-canonical/fork/launchers/inject_fork_governance_preamble.sh +8 -0
- package/ds-canonical/fork/manifest.json +15 -1
- package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +181 -0
- package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +63 -0
- package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +229 -0
- package/ds-canonical/fork/skills/delivery-handoff/references/flow-diagram.md +180 -0
- package/ds-canonical/fork/skills/delivery-handoff/references/handoff-template.md +177 -0
- package/ds-canonical/fork/skills/delivery-handoff/references/inventory-checklist.md +196 -0
- package/ds-canonical/fork/skills/performance-audit/SKILL.md +107 -0
- package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +230 -0
- package/ds-canonical/fork/skills/product-ui-audit/references/audit-checks.md +246 -0
- package/ds-canonical/fork/skills/product-ui-audit/references/common-misuses.md +329 -0
- package/ds-canonical/fork/skills/product-ui-audit/references/report-template.md +159 -0
- package/ds-canonical/fork/skills/propose-options/SKILL.md +177 -0
- package/ds-canonical/fork/skills/prototype/SKILL.md +244 -0
- package/ds-canonical/fork/skills/prototype/references/audit-checks.md +37 -0
- package/ds-canonical/fork/skills/prototype/references/benchmark-sources.md +94 -0
- package/ds-canonical/fork/skills/prototype/references/checkpoints.md +191 -0
- package/ds-canonical/fork/skills/prototype/references/evaluation-matrix.md +141 -0
- package/ds-canonical/fork/skills/prototype/references/ooux-template.md +198 -0
- package/ds-canonical/fork/skills/prototype/references/proposal-template.md +229 -0
- package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +198 -0
- package/ds-canonical/fork/skills/ux-audit/SKILL.md +130 -0
- package/ds-canonical/fork/skills/visual-audit/SKILL.md +245 -0
- package/ds-canonical/fork/skills/visual-audit/output/.gitkeep +0 -0
- package/ds-canonical/fork/skills/visual-audit/references/audit-architecture.md +100 -0
- package/ds-canonical/fork/skills/visual-audit/references/visual-checklist.md +297 -0
- package/ds-canonical/fork/skills/visual-audit/references/world-class-benchmarks.md +198 -0
- package/ds-canonical/hooks/lib/_app_shell_primary_header_consistency.sh +6 -3
- package/ds-canonical/hooks/tests/test_check_app_shell_primary_header_consistency.sh +12 -0
- package/llms-full.txt +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/src/components/AppShell/_demo-helpers.tsx +65 -6
- package/src/components/AppShell/app-shell.principles.stories.tsx +11 -0
- package/src/components/AppShell/app-shell.spec.md +32 -0
- package/src/components/AppShell/app-shell.stories.tsx +5 -0
- package/src/components/Avatar/avatar.spec.md +3 -1
- package/src/components/Sidebar/sidebar.spec.md +2 -0
- package/src/patterns/header-canonical/header-canonical.spec.md +5 -4
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Flow Diagram — Mermaid UI Flow 指引
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## 為什麼用 Mermaid
|
|
6
|
+
|
|
7
|
+
- **Text-based**:可 git diff / review / version control
|
|
8
|
+
- **Storybook 支援**:`mdx` 可直接 render;純 `tsx` story 用 `<pre>` 包 mermaid source + 指引
|
|
9
|
+
- **世界級工具支援**:GitHub / Notion / GitLab / Confluence 都 render
|
|
10
|
+
- **Export**:可 export PNG / SVG / PDF 交付給不進 Storybook 的 stakeholder
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 基本語法
|
|
15
|
+
|
|
16
|
+
### flowchart(最常用)
|
|
17
|
+
|
|
18
|
+
```mermaid
|
|
19
|
+
flowchart TD
|
|
20
|
+
Start([使用者進入 checkout]) --> Cart[Cart Review]
|
|
21
|
+
Cart -->|修改| Edit[Edit Item Dialog]
|
|
22
|
+
Edit --> Cart
|
|
23
|
+
Cart -->|確認| Pay[Payment Step]
|
|
24
|
+
Pay -->|信用卡| Card[Card Form]
|
|
25
|
+
Pay -->|轉帳| Bank[Bank Info]
|
|
26
|
+
Card --> Confirm[Confirm Dialog]
|
|
27
|
+
Bank --> Confirm
|
|
28
|
+
Confirm -->|下單| Success([訂單成立])
|
|
29
|
+
Confirm -->|取消| Cart
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Nodes:
|
|
33
|
+
- `[Text]` = rectangle(主 screen / modal)
|
|
34
|
+
- `([Text])` = stadium(流程起點 / 終點)
|
|
35
|
+
- `{Text}` = rhombus(決策點)
|
|
36
|
+
- `((Text))` = circle(特殊節點,如 async operation)
|
|
37
|
+
|
|
38
|
+
Edges:
|
|
39
|
+
- `-->` arrow
|
|
40
|
+
- `-->|label|` arrow with label(e.g., 條件)
|
|
41
|
+
- `-.->` dashed(非主路徑 / optional)
|
|
42
|
+
- `==>` thick(強調 / primary 路徑)
|
|
43
|
+
|
|
44
|
+
### sequenceDiagram(互動時序)
|
|
45
|
+
|
|
46
|
+
```mermaid
|
|
47
|
+
sequenceDiagram
|
|
48
|
+
User->>UI: 點「套用」
|
|
49
|
+
UI->>API: POST /discount
|
|
50
|
+
API-->>UI: 200 + discount data
|
|
51
|
+
UI->>UI: 更新 state
|
|
52
|
+
UI-->>User: 顯示「已套用」
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
適合:非同步互動 / API 時序 / 多 actor 流程。
|
|
56
|
+
|
|
57
|
+
### stateDiagram(狀態機)
|
|
58
|
+
|
|
59
|
+
```mermaid
|
|
60
|
+
stateDiagram-v2
|
|
61
|
+
[*] --> Idle
|
|
62
|
+
Idle --> Loading: click apply
|
|
63
|
+
Loading --> Applied: 200
|
|
64
|
+
Loading --> Error: 4xx/5xx
|
|
65
|
+
Applied --> Idle: click clear
|
|
66
|
+
Error --> Idle: dismiss
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
適合:元件 / feature 的狀態機(idle / loading / success / error)。
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 世界級 reference
|
|
74
|
+
|
|
75
|
+
對標世界級設計 handoff 的 flow 品質:
|
|
76
|
+
|
|
77
|
+
- **Shopify Polaris Pattern pages**: 每 pattern 有 `flow` section 用 SVG,我們用 Mermaid
|
|
78
|
+
- **Material Design Guidelines**: 流程圖 + 截圖並列
|
|
79
|
+
- **Stripe Documentation**: Payment Flow 用 Mermaid + inline code
|
|
80
|
+
- **Figma Design Process blog posts**: Journey map + flow 混合
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 原則
|
|
85
|
+
|
|
86
|
+
### 1. 一張圖涵蓋一個 feature,不超過 20 個 nodes
|
|
87
|
+
|
|
88
|
+
> 20+ nodes → 拆成多個 sub-flow diagram。
|
|
89
|
+
|
|
90
|
+
### 2. 標示 **error path**(非 happy path)
|
|
91
|
+
|
|
92
|
+
> 只畫 happy path = handoff 失真。user 也要知道錯誤 / 邊界 case 流向何處。
|
|
93
|
+
|
|
94
|
+
### 3. 決策點標清楚
|
|
95
|
+
|
|
96
|
+
> 用 `-->|label|` 寫條件,避免邊無敘述。
|
|
97
|
+
|
|
98
|
+
### 4. Start / End 用 stadium node
|
|
99
|
+
|
|
100
|
+
> `([Start])` / `([End])` 讓讀者知道邊界。
|
|
101
|
+
|
|
102
|
+
### 5. 搭配 spec sheet 引用
|
|
103
|
+
|
|
104
|
+
> Node text 應對應 spec sheet 的 screen / modal 名稱,讀者一眼看出對應。
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 範本 — Checkout 完整 flow
|
|
109
|
+
|
|
110
|
+
```mermaid
|
|
111
|
+
flowchart TD
|
|
112
|
+
Start([進入 /checkout]) --> AuthCheck{已登入?}
|
|
113
|
+
AuthCheck -->|否| Login[Login Screen]
|
|
114
|
+
Login --> Start
|
|
115
|
+
AuthCheck -->|是| CartCheck{購物車有 item?}
|
|
116
|
+
CartCheck -->|否| Empty[Empty Cart Screen]
|
|
117
|
+
Empty -->|回去購物| End1([exit to /products])
|
|
118
|
+
CartCheck -->|是| Review[Cart Review Screen]
|
|
119
|
+
|
|
120
|
+
Review -->|點 item| Edit[Edit Item Dialog]
|
|
121
|
+
Edit -->|save| Review
|
|
122
|
+
Edit -->|cancel| Review
|
|
123
|
+
|
|
124
|
+
Review -->|輸入折扣| Discount{折扣有效?}
|
|
125
|
+
Discount -->|否| DiscountError[顯示 error]
|
|
126
|
+
DiscountError --> Review
|
|
127
|
+
Discount -->|是| Review
|
|
128
|
+
|
|
129
|
+
Review -->|下一步| Payment[Payment Selection]
|
|
130
|
+
Payment -->|信用卡| CardForm[Card Form]
|
|
131
|
+
Payment -->|轉帳| BankInfo[Bank Instructions]
|
|
132
|
+
Payment -->|超商| StoreInfo[Store Instructions]
|
|
133
|
+
|
|
134
|
+
CardForm --> Validate{valid?}
|
|
135
|
+
Validate -->|否| CardError[Inline errors]
|
|
136
|
+
CardError --> CardForm
|
|
137
|
+
Validate -->|是| Confirm[Confirm Dialog]
|
|
138
|
+
|
|
139
|
+
BankInfo --> Confirm
|
|
140
|
+
StoreInfo --> Confirm
|
|
141
|
+
|
|
142
|
+
Confirm -->|確認下單| Submit[POST /order]
|
|
143
|
+
Submit --> SubmitCheck{success?}
|
|
144
|
+
SubmitCheck -->|是| Success([訂單成立 / 跳 /orders/:id])
|
|
145
|
+
SubmitCheck -->|否| RetryToast[Toast: 請稍後再試]
|
|
146
|
+
RetryToast --> Confirm
|
|
147
|
+
|
|
148
|
+
Confirm -->|取消| Payment
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Edge case 節點命名慣例
|
|
154
|
+
|
|
155
|
+
- `XxxError` = 錯誤狀態(顯示 Alert / Notice)
|
|
156
|
+
- `XxxEmpty` = 空狀態(顯示 Empty 元件)
|
|
157
|
+
- `XxxLoading` = 載入中
|
|
158
|
+
- `XxxRetry` = 可重試狀態
|
|
159
|
+
- `XxxSkipped` = 跳過(optional flow)
|
|
160
|
+
|
|
161
|
+
讓讀者一眼看出節點是 happy 還是 edge。
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 集成 Storybook
|
|
166
|
+
|
|
167
|
+
Storybook 8+ 支援 MDX,可直接寫 mermaid code block:
|
|
168
|
+
|
|
169
|
+
````mdx
|
|
170
|
+
# Checkout Flow
|
|
171
|
+
|
|
172
|
+
```mermaid
|
|
173
|
+
flowchart TD
|
|
174
|
+
Start --> End
|
|
175
|
+
```
|
|
176
|
+
````
|
|
177
|
+
|
|
178
|
+
純 tsx story 可用 `<pre>{mermaidSource}</pre>` + 外部 render tool,或用 `mermaid.js` npm lib runtime render。
|
|
179
|
+
|
|
180
|
+
一般推薦 MDX 方式,Storybook 原生支援。
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Handoff Template — Storybook page + Markdown spec
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Storybook Handoff Page 結構
|
|
6
|
+
|
|
7
|
+
位置: `src/app/features/{feature-slug}/{feature-slug}.handoff.stories.tsx`
|
|
8
|
+
|
|
9
|
+
Title: `Features/{Feature Name}/Handoff`
|
|
10
|
+
|
|
11
|
+
每個 handoff page 5 個 story(5 tab):
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
const meta: Meta = {
|
|
15
|
+
title: 'Features/Checkout/Handoff',
|
|
16
|
+
parameters: { layout: 'fullscreen' },
|
|
17
|
+
}
|
|
18
|
+
export default meta
|
|
19
|
+
|
|
20
|
+
export const Overview: Story = {
|
|
21
|
+
name: '0. Overview',
|
|
22
|
+
render: () => <OverviewPage />,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const UIFlow: Story = {
|
|
26
|
+
name: '1. UI Flow',
|
|
27
|
+
render: () => <FlowDiagram />, // Mermaid render
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const Inventory: Story = {
|
|
31
|
+
name: '2. Inventory',
|
|
32
|
+
render: () => <InventoryTables />, // Component / Token / a11y
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const Screens: Story = {
|
|
36
|
+
name: '3. Screens',
|
|
37
|
+
render: () => <ScreenGrid />, // 每 screen 的 preview + link
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const SpecSheets: Story = {
|
|
41
|
+
name: '4. Spec Sheets',
|
|
42
|
+
render: () => <SpecTabs />, // per-screen detail
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Per-screen Markdown Spec 範本
|
|
49
|
+
|
|
50
|
+
每 screen 一份,組合為完整 feature 的 spec sheet:
|
|
51
|
+
|
|
52
|
+
```markdown
|
|
53
|
+
# Screen: {Name}
|
|
54
|
+
|
|
55
|
+
**Storybook**: `Features/{Feature}/{Screen}`
|
|
56
|
+
**Source**: `src/app/features/{slug}/{Screen}.tsx`
|
|
57
|
+
**Route**: `/{path}`
|
|
58
|
+
|
|
59
|
+
## 用途(Why)
|
|
60
|
+
|
|
61
|
+
{1-2 sentence 敘述 user 會在此頁做什麼}
|
|
62
|
+
|
|
63
|
+
## 進入條件(Entry conditions)
|
|
64
|
+
|
|
65
|
+
- {e.g., 已登入 + 購物車有 ≥1 item}
|
|
66
|
+
- {e.g., 付款方式已選擇}
|
|
67
|
+
|
|
68
|
+
## 主要元件(Components used)
|
|
69
|
+
|
|
70
|
+
| Component | Count | Purpose |
|
|
71
|
+
|-----------|-------|---------|
|
|
72
|
+
| Button | 3 | CTA + 次要 action |
|
|
73
|
+
| Input | 1 | 折扣碼輸入 |
|
|
74
|
+
| ... | | |
|
|
75
|
+
|
|
76
|
+
## 狀態(States)
|
|
77
|
+
|
|
78
|
+
### default
|
|
79
|
+
{正常載入後的畫面描述 + 截圖}
|
|
80
|
+
|
|
81
|
+
### empty
|
|
82
|
+
{無資料時的 fallback}
|
|
83
|
+
|
|
84
|
+
### error
|
|
85
|
+
{錯誤情境處理}
|
|
86
|
+
|
|
87
|
+
### loading
|
|
88
|
+
{載入中 skeleton / spinner}
|
|
89
|
+
|
|
90
|
+
## 互動(Interactions)
|
|
91
|
+
|
|
92
|
+
| Action | Element | Result |
|
|
93
|
+
|--------|---------|--------|
|
|
94
|
+
| 點 Apply | Button | POST /discount |
|
|
95
|
+
| 按 Esc | 任何 Dialog | 關閉 |
|
|
96
|
+
| ... | | |
|
|
97
|
+
|
|
98
|
+
## A11y
|
|
99
|
+
|
|
100
|
+
- ✓ icon-only 元件均有 aria-label
|
|
101
|
+
- ✓ Dialog 有 DialogTitle + DialogDescription
|
|
102
|
+
- ✓ keyboard tab order 正確
|
|
103
|
+
- ⚠ {如有未達標項,明列 + 說明}
|
|
104
|
+
|
|
105
|
+
## 邊界(Edge cases)
|
|
106
|
+
|
|
107
|
+
- {e.g., 折扣碼超過總額 → capped}
|
|
108
|
+
- {e.g., 網路斷線 → toast + retry}
|
|
109
|
+
- {e.g., 超過 N items → 分頁}
|
|
110
|
+
|
|
111
|
+
## 業務規則(Business rules)
|
|
112
|
+
|
|
113
|
+
- {e.g., VIP 折扣上限 30%}
|
|
114
|
+
- {e.g., 免運門檻 NT$1000}
|
|
115
|
+
|
|
116
|
+
## Related
|
|
117
|
+
|
|
118
|
+
- Next step: [Screen Y]
|
|
119
|
+
- Alternative: [Screen Z]
|
|
120
|
+
- Design source: [Explorations/ folder](...)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Overview story render 範本
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
function OverviewPage() {
|
|
129
|
+
return (
|
|
130
|
+
<div className="max-w-4xl mx-auto p-8 flex flex-col gap-6">
|
|
131
|
+
<h1 className="text-h1 font-medium">Checkout Feature Handoff</h1>
|
|
132
|
+
<p className="text-body-lg text-fg-secondary">
|
|
133
|
+
使用者從購物車到下單的完整結帳流程。包含 3 screens、4 modals、支援信用卡 / 銀行轉帳 /
|
|
134
|
+
超商付款 3 種付款方式。
|
|
135
|
+
</p>
|
|
136
|
+
|
|
137
|
+
<div className="border-t border-divider pt-6">
|
|
138
|
+
<h2 className="text-h2 font-medium mb-3">Audience</h2>
|
|
139
|
+
<ul className="list-disc pl-5 text-body">
|
|
140
|
+
<li>工程團隊:實作參考 + test case 來源</li>
|
|
141
|
+
<li>QA:邊界 case checklist</li>
|
|
142
|
+
<li>PM:業務規則確認</li>
|
|
143
|
+
</ul>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<div className="border-t border-divider pt-6">
|
|
147
|
+
<h2 className="text-h2 font-medium mb-3">Status</h2>
|
|
148
|
+
<div className="grid grid-cols-3 gap-3">
|
|
149
|
+
<StatCard label="元件消費" value="12" caption="既有 DS" />
|
|
150
|
+
<StatCard label="新元件" value="0" caption="零污染" />
|
|
151
|
+
<StatCard label="A11y" value="✓" caption="WCAG AA" />
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<div className="border-t border-divider pt-6">
|
|
156
|
+
<h2 className="text-h2 font-medium mb-3">Navigation</h2>
|
|
157
|
+
<ul className="list-disc pl-5 text-body">
|
|
158
|
+
<li>Tab 1: UI Flow — Mermaid diagram</li>
|
|
159
|
+
<li>Tab 2: Inventory — 元件 / token / a11y 報告</li>
|
|
160
|
+
<li>Tab 3: Screens — 每 screen preview + link</li>
|
|
161
|
+
<li>Tab 4: Spec Sheets — per-screen detail</li>
|
|
162
|
+
</ul>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 設計原則
|
|
172
|
+
|
|
173
|
+
1. **target audience driven**: 語氣深度因 audience 調整。工程語氣精準 / PM 語氣情境 / 設計語氣對標
|
|
174
|
+
2. **每段可獨立被引用**: per-screen spec 可單獨丟給 team member,不需看其他頁
|
|
175
|
+
3. **不重複 DS spec**: 元件的行為 / variant 由 `components/*/spec.md` owning,handoff 只寫 **feature-level** 使用
|
|
176
|
+
4. **截圖 / preview 是 Storybook render 即可**: 不要 mockup,直接看真實 code 的 output
|
|
177
|
+
5. **Edge case 必寫**: handoff 不寫 edge case = 實作 + QA 會踩坑
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Inventory Checklist — 元件 / token / a11y grep pattern
|
|
2
|
+
|
|
3
|
+
Phase 1 inventory 生成的具體 grep + 統計方法。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Component Inventory
|
|
8
|
+
|
|
9
|
+
### 步驟 1: grep 所有 import
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
grep -rhnE "^import.*@/design-system/components/" {target} | \
|
|
13
|
+
sed -E 's/.*components\/([A-Z][a-zA-Z]+)\/.*/\1/' | \
|
|
14
|
+
sort | uniq -c | sort -rn
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
輸出:每個 DS 元件被 import 幾次。
|
|
18
|
+
|
|
19
|
+
### 步驟 2: count JSX usage
|
|
20
|
+
|
|
21
|
+
每個 component 精確使用次數(非 import):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
for comp in Button Input Dialog Empty ScrollArea ...; do
|
|
25
|
+
count=$(grep -rhnE "<$comp\b" {target} | wc -l)
|
|
26
|
+
echo "$comp: $count"
|
|
27
|
+
done
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 步驟 3: 輸出 table
|
|
31
|
+
|
|
32
|
+
```markdown
|
|
33
|
+
## Components Used (12)
|
|
34
|
+
|
|
35
|
+
| Component | Count | Files |
|
|
36
|
+
|-----------|-------|-------|
|
|
37
|
+
| Button | 12 | Checkout.tsx, Summary.tsx, ... |
|
|
38
|
+
| Input | 3 | PaymentForm.tsx |
|
|
39
|
+
| Dialog | 2 | ConfirmDialog.tsx, EditDialog.tsx |
|
|
40
|
+
| Empty | 1 | EmptyCart.tsx |
|
|
41
|
+
| ProgressBar | 1 | UploadingBanner.tsx |
|
|
42
|
+
| ScrollArea | 1 | ItemList.tsx |
|
|
43
|
+
| ... | | |
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Token Inventory
|
|
49
|
+
|
|
50
|
+
### CSS variable usage
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
grep -rohnE 'var\(--[a-z-]+\)' {target} | \
|
|
54
|
+
sort | uniq -c | sort -rn
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Semantic token utility class
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
grep -rohnE '\b(bg|text|border|fill|stroke|ring)-(primary|primary-hover|primary-subtle|primary-text|info|info-hover|info-subtle|info-text|error|error-hover|error-subtle|error-text|success|success-hover|success-subtle|success-text|warning|warning-hover|warning-subtle|warning-text|foreground|fg-secondary|fg-muted|fg-disabled|neutral-hover|neutral-active|neutral-selected|surface|surface-raised|canvas|muted|secondary|border|border-hover|divider|overlay|tooltip|notification|chart-[1-5])\b' {target} | \
|
|
61
|
+
awk -F: '{print $NF}' | sort | uniq -c | sort -rn
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 輸出 table
|
|
65
|
+
|
|
66
|
+
```markdown
|
|
67
|
+
## Tokens Used (24)
|
|
68
|
+
|
|
69
|
+
| Token | Usage | Primary consumer |
|
|
70
|
+
|-------|-------|------------------|
|
|
71
|
+
| --primary | 8 | 主 CTA |
|
|
72
|
+
| --fg-secondary | 14 | 次要文字 |
|
|
73
|
+
| --error | 3 | 錯誤狀態 |
|
|
74
|
+
| --surface-raised | 5 | Dialog / Popover bg |
|
|
75
|
+
| ... | | |
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Layout primitives 消費報告
|
|
81
|
+
|
|
82
|
+
每類 primitive 用了幾次 + 哪些地方:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Empty
|
|
86
|
+
grep -rhnE '<Empty\b' {target} | wc -l
|
|
87
|
+
|
|
88
|
+
# ScrollArea
|
|
89
|
+
grep -rhnE '<ScrollArea\b' {target} | wc -l
|
|
90
|
+
|
|
91
|
+
# AspectRatio
|
|
92
|
+
grep -rhnE '<AspectRatio\b' {target} | wc -l
|
|
93
|
+
|
|
94
|
+
# item-layout (MenuItem etc.)
|
|
95
|
+
grep -rhnE '<(MenuItem|TreeItem|SidebarMenuButton|ItemIcon|ItemAvatar|ItemLabel|ItemSuffix)\b' {target} | wc -l
|
|
96
|
+
|
|
97
|
+
# overlay-surface (Dialog/Popover auto consume)
|
|
98
|
+
grep -rhnE '<(DialogHeader|DialogBody|DialogFooter|PopoverHeader|PopoverBody|PopoverFooter)\b' {target} | wc -l
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
輸出:
|
|
102
|
+
|
|
103
|
+
```markdown
|
|
104
|
+
## Layout primitives used
|
|
105
|
+
|
|
106
|
+
| Primitive | Count | Note |
|
|
107
|
+
|-----------|-------|------|
|
|
108
|
+
| Empty | 1 | EmptyCart.tsx |
|
|
109
|
+
| item-layout | 5 | via MenuItem(3) / TreeItem(2) |
|
|
110
|
+
| overlay-surface | 4 | via Dialog sub-components |
|
|
111
|
+
| ScrollArea | 1 | ItemList.tsx |
|
|
112
|
+
| AspectRatio | 0 | 本 feature 無 media container |
|
|
113
|
+
| Horizontal-overflow | 0 | 本 feature 無水平溢出 |
|
|
114
|
+
| Field-wrapper | 3 | via Input(3) |
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## A11y Checklist
|
|
120
|
+
|
|
121
|
+
### 自動掃描(visible)
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# icon-only 無 aria-label
|
|
125
|
+
grep -rnE '(iconOnly|startIcon=\{)' {target} | \
|
|
126
|
+
xargs -I {} sh -c 'echo {} | grep -v "aria-label"'
|
|
127
|
+
|
|
128
|
+
# 非 button 綁 onClick
|
|
129
|
+
grep -rnE '<(div|span)[^>]*onClick=' {target}
|
|
130
|
+
|
|
131
|
+
# Dialog 是否有 DialogTitle
|
|
132
|
+
grep -rlE '<DialogContent>' {target} | \
|
|
133
|
+
xargs -I {} grep -L 'DialogTitle' {}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 人工 review(本 skill AI 無法判)
|
|
137
|
+
|
|
138
|
+
| Check | Status | Note |
|
|
139
|
+
|-------|--------|------|
|
|
140
|
+
| Color contrast WCAG AA | ? | 需 Storybook 視覺 + axe plugin |
|
|
141
|
+
| Keyboard navigation tab order | ? | 需實際操作 |
|
|
142
|
+
| Screen reader announce 正確 | ? | 需 VoiceOver / NVDA 測試 |
|
|
143
|
+
| Focus trap 在 Modal 內 | ✓ | Radix 自動處理 |
|
|
144
|
+
| Esc 關閉 Modal | ✓ | Radix 自動處理 |
|
|
145
|
+
|
|
146
|
+
輸出:
|
|
147
|
+
|
|
148
|
+
```markdown
|
|
149
|
+
## A11y Status
|
|
150
|
+
|
|
151
|
+
### Auto-scanned (visible issues)
|
|
152
|
+
|
|
153
|
+
| Check | Status |
|
|
154
|
+
|-------|--------|
|
|
155
|
+
| icon-only 有 aria-label | ✓ 全過(12/12) |
|
|
156
|
+
| 非 button 綁 onClick | ✓ 無 |
|
|
157
|
+
| Dialog 有 Title | ✓ 2/2 |
|
|
158
|
+
|
|
159
|
+
### Manual review needed
|
|
160
|
+
|
|
161
|
+
- [ ] Color contrast(run axe in Storybook)
|
|
162
|
+
- [ ] Keyboard navigation test
|
|
163
|
+
- [ ] Screen reader test
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 新增的元件 / token
|
|
169
|
+
|
|
170
|
+
若 feature 過程中**新增**到 design-system/,在 inventory 特別標示:
|
|
171
|
+
|
|
172
|
+
```markdown
|
|
173
|
+
## New additions to DS (本 feature 過程新增)
|
|
174
|
+
|
|
175
|
+
| Added | File | Motivation |
|
|
176
|
+
|-------|------|-----------|
|
|
177
|
+
| Coachmark | node_modules/@qijenchen/design-system/src/components/Coachmark/ | onboarding tour 需求 |
|
|
178
|
+
| --chart-accent | node_modules/@qijenchen/design-system/src/tokens/color/semantic.css | data viz 擴充 |
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
讓 stakeholder 看得出「這 feature 帶動了 DS 擴充」的成本。
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 範本輸出順序
|
|
186
|
+
|
|
187
|
+
inventory 結果編排:
|
|
188
|
+
|
|
189
|
+
1. **Overview**(feature 規模:X screens / Y modals)
|
|
190
|
+
2. **Components Used**(按 count 由高至低)
|
|
191
|
+
3. **Tokens Used**(按 count 由高至低,分色 / 字 / 間距 / shadow 四類)
|
|
192
|
+
4. **Layout primitives**(全表)
|
|
193
|
+
5. **A11y**(auto + manual two tables)
|
|
194
|
+
6. **New additions**(若有)
|
|
195
|
+
|
|
196
|
+
如此 stakeholder 一分鐘可掃完,三分鐘可讀懂 feature 全景。
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: performance-audit
|
|
3
|
+
description: Performance audit for design-system components and product UI. Checks render count, unnecessary re-renders, memoization gaps, bundle size impact, useEffect chains, context thrashing. Invoke when user says「這元件效能如何」「為什麼很卡」「bundle 變大」「re-render 太多」, auto-invoked by `/component-quality-gate` Phase 4.5 (advanced mode) and `/design-system-audit` Dimension D3.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Performance Audit — 元件效能稽核
|
|
7
|
+
|
|
8
|
+
## 存在意義
|
|
9
|
+
|
|
10
|
+
現有 `/design-system-audit`(全 dim per design-system-audit SSOT,code/spec 層)+ `/visual-audit`(pixel 層)**都不看效能**。render 次數過多、context 亂鋪、useEffect 鏈條過長這類 bug:
|
|
11
|
+
- tsc 過、eslint 過、視覺正常
|
|
12
|
+
- production 卡
|
|
13
|
+
- 日常 dev 看不出來,到 stakeholder demo 才爆
|
|
14
|
+
|
|
15
|
+
本 skill 作為稽核 6 維度的 **D3 元件效能** canonical home。
|
|
16
|
+
|
|
17
|
+
## 觸發時機(對齊 CLAUDE.md 稽核 canonical)
|
|
18
|
+
|
|
19
|
+
| 情境 | 模式 | 本 skill 跑什麼 |
|
|
20
|
+
|------|------|----------------|
|
|
21
|
+
| 新元件 merge 前 | 進階強制 | 全面(render count / memo / bundle) |
|
|
22
|
+
| 元件新功能 | 進階強制 | 全面 scoped to 新 prop / variant |
|
|
23
|
+
| 產品 demo 前 | 進階強制 | scoped to URL(常用頁 route) |
|
|
24
|
+
| 日常 dev | 高效 | tsc pass + bundle diff 門檻即可 |
|
|
25
|
+
| Release cut | 進階 + 全 DS scope | 全 DS render / memo / bundle 全跑 |
|
|
26
|
+
|
|
27
|
+
## Preconditions
|
|
28
|
+
|
|
29
|
+
- 元件 folder 存在於 `node_modules/@qijenchen/design-system/src/components/{Name}/`
|
|
30
|
+
- `node_modules` 已安裝
|
|
31
|
+
- Storybook 可啟動(用於 render-count 測量)
|
|
32
|
+
|
|
33
|
+
## Workflow
|
|
34
|
+
|
|
35
|
+
### Phase 0 — Scope 判定(一致性類必先全掃)
|
|
36
|
+
|
|
37
|
+
- 若 scope = 單元件 → 走 Phase 1-3 對該元件
|
|
38
|
+
- 若 scope = 全 DS / URL → **先全掃列出所有 hot path**(render 過多元件 / bundle 大元件 / context 亂鋪元件),Phase 1-3 按 impact 排序逐一 audit
|
|
39
|
+
|
|
40
|
+
### Phase 1 — Render & re-render
|
|
41
|
+
|
|
42
|
+
查 4 項:
|
|
43
|
+
1. **Unnecessary re-render**:consumer 改 prop / state 時,本元件是否 re-render?`React.memo` 是否需要?
|
|
44
|
+
2. **Inline 物件 / 函式 prop**:`style={{ ... }}` / `onClick={() => ...}` 每 render 造新 ref → child memo 失效
|
|
45
|
+
3. **Context 粒度**:`<ThemeProvider value={theme}>` 若含頻繁變動 field(e.g. `openMenuId`)→ 整個 subtree 重渲。Context 必切分粒度或用 selector
|
|
46
|
+
4. **Key 穩定性**:list items 用 `key={index}` 導致無意義 remount
|
|
47
|
+
|
|
48
|
+
**工具**:
|
|
49
|
+
- React DevTools Profiler record → 看 flame graph
|
|
50
|
+
- `why-did-you-render` dev dep 觸發警告(未來可加)
|
|
51
|
+
- 直接 grep pattern(inline style / arrow onClick)
|
|
52
|
+
|
|
53
|
+
### Phase 2 — Memoization / dependency
|
|
54
|
+
|
|
55
|
+
查 3 項:
|
|
56
|
+
1. **useMemo / useCallback dep array**:遺漏 dep(stale closure)/ 多 dep(無效 memo)
|
|
57
|
+
2. **useEffect dep array**:同上;特別注意 object / array dep(每 render 新 ref → 無限迴圈或無效 cleanup)
|
|
58
|
+
3. **Computed value in render**:重計算 heavy op(sort / filter / 轉換) → 必 `useMemo`
|
|
59
|
+
|
|
60
|
+
### Phase 3 — Bundle size
|
|
61
|
+
|
|
62
|
+
查 3 項:
|
|
63
|
+
1. **Direct heavy import**:`import * as Icons from 'lucide-react'`(全庫入 bundle) vs `import { Check } from 'lucide-react'`
|
|
64
|
+
2. **Lazy-loadable portion**:Dialog / Sheet / Coachmark 等 rare-use overlay,可 `React.lazy` 減首屏
|
|
65
|
+
3. **Duplicate dep**:`framer-motion` vs `motion/react` / 不同版本 react-day-picker 等
|
|
66
|
+
|
|
67
|
+
**工具**:
|
|
68
|
+
- `npx vite build --report`(vite bundle visualizer)
|
|
69
|
+
- bundle-size CI check(未來可加)
|
|
70
|
+
|
|
71
|
+
### Phase F — Report(必 STOP,對齊分權 canonical)
|
|
72
|
+
|
|
73
|
+
產出:
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
# Performance Audit — {Scope} — {YYYY-MM-DD}
|
|
77
|
+
|
|
78
|
+
## Summary
|
|
79
|
+
- Render issues: N
|
|
80
|
+
- Memoization gaps: M
|
|
81
|
+
- Bundle impact: K KB
|
|
82
|
+
|
|
83
|
+
## Findings(按 impact 排序)
|
|
84
|
+
### P0: {title}
|
|
85
|
+
- 位置: {file:line}
|
|
86
|
+
- 現況: {render count / bundle contribution}
|
|
87
|
+
- 建議: {具體修法}
|
|
88
|
+
- 是 canonical 修實作(auto),還是原則待討論(STOP)?
|
|
89
|
+
|
|
90
|
+
## 提議討論(待 user sign-off)
|
|
91
|
+
- {若發現 canonical 本身有問題,列於此,不自改}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**STOP 點**:report 寫完**不自動修**。分權對齊 CLAUDE.md `# 稽核 canonical`(內含「Audit-vs-execute 分權」inline rule)。
|
|
95
|
+
|
|
96
|
+
## Non-goals
|
|
97
|
+
|
|
98
|
+
- 不改 code / spec(純 read-only report)
|
|
99
|
+
- 不做 micro-benchmark(10ms 以下差異不 report,噪音太多)
|
|
100
|
+
- 不處理 network / backend(純前端 render / bundle)
|
|
101
|
+
|
|
102
|
+
## 相關
|
|
103
|
+
|
|
104
|
+
- `node_modules/@qijenchen/design-system/ds-canonical/skills/design-system-audit/SKILL.md` — 全 dim 統籌(per design-system-audit SSOT);本 skill 是 D3 補位
|
|
105
|
+
- `node_modules/@qijenchen/design-system/ds-canonical/skills/visual-audit/SKILL.md` — pixel 層(D5)
|
|
106
|
+
- `node_modules/@qijenchen/design-system/ds-canonical/skills/ux-audit/SKILL.md` — UX 行為層(D4)
|
|
107
|
+
- `node_modules/@qijenchen/design-system/ds-canonical/skills/component-quality-gate/SKILL.md` — Phase 4.5 進階模式 chain 本 skill
|