導入真正的設計系統
最常見的 AI 程式碼生成失敗之一是元件重複 - AI 建立新的 UI 元件而非重用現有的。這是因為現有元件分散、未文件化、命名不一致。真正的設計系統透過提供 UI 元件的單一事實來源來解決這個問題。
核心洞察: AI 無法「發現」未組織的元件。如果元件不在預期位置且沒有清晰文件,它們對 AI 而言等於不存在。
問題陳述
當前狀態:元件混亂
團隊回饋的證據
| 團隊 | 問題 | 影響 |
|---|---|---|
| Android | UI 元件分散,無統一管理 | AI 重新實作現有元件 |
| Web | models 目錄 28,476 行,60+ 服務類別 | AI context window 超出 |
| iOS | design-spec 沒有元件對應 | AI 不知道該用哪個元件 |
| 全部 | 設計 tokens 未系統化 | AI 硬編碼樣式值 |
提案:統一設計系統
目標狀態
設計系統架構
design-system/
├── README.md # 設計系統概覽 & AI 指引
├── COMPONENT_INDEX.md # 可搜尋的元件目錄
│
├── tokens/
│ ├── colors.md # 調色盤定義
│ ├── typography.md # 字型樣式和大小
│ ├── spacing.md # 間距比例
│ └── shadows.md # 陰影定義
│
├── components/
│ ├── buttons/
│ │ ├── README.md # 按鈕變體和用法
│ │ ├── Button.vue # Web 實作
│ │ ├── Button.swift # iOS 實作
│ │ └── Button.kt # Android 實作
│ │
│ ├── cards/
│ │ ├── README.md
│ │ ├── DeviceCard.vue
│ │ ├── DeviceCard.swift
│ │ └── DeviceCard.kt
│ │
│ └── lists/
│ ├── README.md
│ ├── DeviceList.vue
│ └── SiteList.vue
│
├── patterns/
│ ├── error-handling.md # 錯誤顯示模式
│ ├── loading-states.md # 載入指示器模式
│ └── empty-states.md # 空狀態設計
│
└── cross-platform/
└── component-mapping.md # 跨平台對應跨平台元件對應
元件對應表
markdown
# 跨平台元件對應
| 元件 | Web | iOS | Android | 備註 |
|------|-----|-----|---------|------|
| **導航** |
| TabBar | `TabBar.vue` | `TabView` | `BottomNavigation` | 平台原生 |
| NavHeader | `NavHeader.vue` | `NavigationBar` | `TopAppBar` | 自訂樣式 |
| **內容** |
| DeviceCard | `DeviceCard.vue` | `DeviceCard.swift` | `DeviceCard.kt` | 統一設計 |
| DeviceList | `DeviceList.vue` | `DeviceListView.swift` | `DeviceListComposable.kt` | 虛擬捲動 |
| **表單** |
| Input | `Input.vue` | `TextField` | `OutlinedTextField` | 平台原生基礎 |
| Button | `Button.vue` | `Button.swift` | `Button.kt` | 設計系統 |
| **回饋** |
| Toast | `Toast.vue` | `Toast.swift` | `Snackbar` | 平台慣例 |
| LoadingSpinner | `Loading.vue` | `ProgressView` | `CircularProgressIndicator` | 一致時間 |元件文件標準
元件 README 模板
markdown
# DeviceCard
用於顯示裝置資訊和狀態指示器的卡片元件。
## 預覽
[截圖或 Figma 連結]
## 使用時機
### 何時使用
- 在列表中顯示個別裝置
- 裝置詳情摘要
- 裝置選擇介面
### 何時不使用
- 純文字裝置引用(使用 DeviceLabel)
- 緊湊列表視圖(使用 DeviceListItem)
## 變體
| 變體 | 使用情境 | Props |
|------|----------|-------|
| `default` | 標準裝置顯示 | `device`, `onClick` |
| `compact` | 空間受限視圖 | `device`, `hideStatus` |
| `selectable` | 多選介面 | `device`, `selected`, `onSelect` |
## AI 指引
@ai-hint 顯示裝置時使用此元件。不要自己實作裝置卡片。
@ai-hint 顯示多個裝置時,與 DeviceList 元件搭配使用。
@see DeviceList 顯示多個裝置
@see DeviceListItem 緊湊列表行實施路線圖
階段 1:盤點(第 1-2 週)
目標: 記錄所有平台的現有元件。
交付物:
- [ ] 每個平台的現有 UI 元件清單
- [ ] 重複元件識別
- [ ] 初步跨平台對應表
階段 2:基礎(第 3-4 週)
目標: 建立設計 tokens 和核心元件。
交付物:
- [ ] 定義設計 tokens(顏色、字型、間距)
- [ ] 5 個核心元件文件化(Button, Input, Card, List, Modal)
- [ ] 建立元件 README 模板
- [ ] 建立 COMPONENT_INDEX.md
階段 3:遷移(第 5-8 週)
目標: 將現有元件整合到設計系統。
交付物:
- [ ] 將共用元件移至設計系統目錄
- [ ] 更新整個程式庫的 imports
- [ ] 在舊元件位置加入棄用通知
- [ ] 更新 CLAUDE.md 加入設計系統指引
階段 4:AI 整合(第 9-10 週)
目標: 確保 AI 一致使用設計系統。
交付物:
- [ ] 為所有元件文件加入 AI 提示
- [ ] 在 CLAUDE.md 建立設計系統搜尋指引
- [ ] 測試 AI 元件生成準確度
- [ ] 根據 AI 行為迭代文件
CLAUDE.md 整合
加入專案 CLAUDE.md:
markdown
## 設計系統
### 元件使用
- **務必檢查** `design-system/COMPONENT_INDEX.md` 再建立新元件
- **使用現有元件** 來自 `design-system/components/`
- **遵循模式** 來自 `design-system/patterns/`
### 搜尋策略
尋找 UI 元件時:
1. 先在 `design-system/components/` 搜尋
2. 檢查 `COMPONENT_INDEX.md` 取得元件名稱
3. 只有在沒有現有元件時才建立新的
### 禁止事項
- 不檢查設計系統就建立新元件
- 硬編碼顏色(使用 `design-system/tokens/` 的 tokens)
- 複製現有元件功能
- 當設計系統有對應元件時使用平台原生元件成功指標
| 指標 | 之前 | 目標 | 如何測量 |
|---|---|---|---|
| 元件重複 | 高 | 接近零 | 審計相似元件 |
| AI 元件重用率 | ~40% | >90% | 追蹤 AI 生成的 PR |
| 找到元件的時間 | 分鐘 | 秒 | 開發者調查 |
| 跨平台一致性 | 低 | 高 | 視覺比較審計 |
| 設計 token 採用率 | 部分 | 100% | grep 硬編碼值 |
參考實作:@vivotek/design-tokens
現有實作展示這些原則的實際應用。@vivotek/design-tokens 套件提供了一個真實世界的範例,說明如何建立同時支援 AI 理解和跨平台一致性的設計 token 系統。
主要實作特色
W3C DTCG 規範合規
Tokens 遵循 W3C Design Tokens Community Group 規範:
json
{
"colors": {
"$type": "color",
"$description": "VIVOTEK 品牌色彩 tokens - 原始色階",
"primary": {
"base": {
"$value": "#006bd6",
"$description": "主色 - 從 brand 500 加深以符合 WCAG AA 對比度"
},
"foreground": {
"$value": "{colors.white}",
"$description": "主色背景上的文字顏色"
}
}
}
}$description 屬性為人類和 AI 提供可讀的脈絡,而 $value 的引用語法({colors.white})支援 token 別名。
多格式輸出
使用 Style Dictionary v5,相同的 token 來源生成:
| 輸出格式 | 使用場景 | 檔案 |
|---|---|---|
| CSS 自訂屬性 | Web 應用程式 | tokens.css |
| TypeScript/JavaScript | 程式化存取 | index.ts |
| Tailwind CSS Preset | Utility-first CSS | tailwind-preset.js |
| iOS Swift | 原生 iOS 應用 | DesignTokens.swift |
| Android Compose | Jetpack Compose | Color.kt, Spacing.kt |
| Android XML | 舊版 Android | colors.xml, dimens.xml |
領域特定語意顏色
除了通用 UI 顏色,系統包含 VSaaS 功能的領域特定 tokens:
json
{
"colors": {
"status": {
"online": { "base": "{colors.success.base}" },
"offline": { "base": "{colors.secondary.base}" },
"recording": { "base": "{colors.info.base}" },
"error": { "base": "{colors.error.base}" }
},
"detection": {
"motion": { "base": "{colors.info.base}" },
"intrusion": { "base": "{colors.error.base}" },
"loitering": { "base": "{colors.warning.base}" }
},
"analytics": {
"human": { "base": "{colors.primary.base}" },
"vehicle": { "base": "{colors.warning.base}" },
"face": { "base": "{colors.primary.base}" }
}
}
}這讓 AI 能理解領域語意:
- 裝置狀態顏色對應運作狀態
- 偵測事件顏色指示嚴重程度
- 分析顏色區分物件類型
主題支援
明暗主題使用相同結構的分離 token 檔案:
tokens/vivotek/
├── colors.tokens.json # 原始顏色
├── colors-light.tokens.json # 淺色主題語意
├── colors-dark.tokens.json # 深色主題語意
├── colors-domain-light.tokens.json
└── colors-domain-dark.tokens.json生成的 CSS 自動處理主題切換:
css
:root {
--primary: #006bd6;
--status-online: #22c55e;
}
.dark {
--primary: #3d8fe8;
--status-online: #4ade80;
}驗證流程
自動驗證確保 token 品質:
bash
pnpm validate
# 驗證:
# 1. DTCG Schema - 所有 tokens 有必要屬性
# 2. Token 引用 - 所有別名指向現有 tokens
# 3. WCAG 對比度 - 語意顏色配對符合 AA 標準(4.5:1)這防止無障礙性退化,並確保使用這些 tokens 的 AI 生成程式碼符合規範。
AI 整合的經驗
- 描述性中繼資料:每個 token 包含
$description供 AI 理解 - 一致的結構:可預測的路徑(
colors.status.online.base)實現可靠的程式碼生成 - 基於引用的別名:語意 tokens 引用原始值,顯示關係
- 多平台對等:所有輸出格式相同的 token 名稱減少 AI 困惑
- 領域詞彙:領域特定顏色群組與通用語言對齊
相關: 以 shadcn/ui 作為基礎 | 返回: 提案概覽
參考資料
- W3C Design Tokens Community Group - 設計 token 規範標準
- Style Dictionary - Amazon 的設計 token 建置系統
- Claude Code 文件 - CLAUDE.md AI 指引檔案的官方文件