visionA/local-tool/.autoflow/03-design/spec/07-design-tokens.md
jim800121chen c54f16fca0 Initial commit: visionA monorepo with local-tool subproject
local-tool/: visionA-local desktop app
- M1: Wails shell + Go server + Next.js UI + Mock mode (macOS dmg ready)
- M2: i18n (zh-TW/en) + Settings 4-tab refactor
- M3: Embedded Python 3.12 runtime (python-build-standalone) + KneronPLUS wheels
- M4: Windows Inno Setup script (build on Windows runner)
- M5: Linux AppImage script + udev rule (build on Linux runner)
- M6: ffmpeg (GPL, pending legal review) + yt-dlp bundled
- Lifecycle: watchServer health check, fatal native dialog,
            Wails IPC raise endpoint, stale process cleanup

.autoflow/: full PRD / Design Spec / Architecture / Testing docs
            (4 rounds tri-party discussion + cross review)
.github/workflows/: macOS / Windows / Linux build CI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:10:38 +08:00

246 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 07 — Design Tokens
## 7.1 策略
**完全沿用 edge-ai-platform 的 tokens**(來源:`frontend/src/app/globals.css`),僅補 desktop 專用項目。理由:
- 原專案採 shadcn + oklch 中性色盤,已經過調教
- Logo 沿用(決策 Q14色系一致
- 減少 local 版的設計負擔,聚焦桌面 app 獨有課題
所有 token 來源以下列註記標示:
- **[沿用]** = 直接從 edge-ai-platform 抄過來,不改
- **[新增]** = visionA-local 補的 desktop 專用 token
- **[微調]** = 沿用但數值略改(需說明原因)
## 7.2 Reference Tokens原始值
### Colors — Light Mode [沿用]
| Token | Value (oklch) | 對應原專案變數 |
|-------|---------------|---------------|
| `color.background` | `oklch(1 0 0)` | `--background` |
| `color.foreground` | `oklch(0.145 0 0)` | `--foreground` |
| `color.card` | `oklch(1 0 0)` | `--card` |
| `color.card-foreground` | `oklch(0.145 0 0)` | `--card-foreground` |
| `color.popover` | `oklch(1 0 0)` | `--popover` |
| `color.primary` | `oklch(0.205 0 0)` | `--primary` |
| `color.primary-foreground` | `oklch(0.985 0 0)` | `--primary-foreground` |
| `color.secondary` | `oklch(0.97 0 0)` | `--secondary` |
| `color.muted` | `oklch(0.97 0 0)` | `--muted` |
| `color.muted-foreground` | `oklch(0.556 0 0)` | `--muted-foreground` |
| `color.accent` | `oklch(0.97 0 0)` | `--accent` |
| `color.destructive` | `oklch(0.577 0.245 27.325)` | `--destructive` |
| `color.border` | `oklch(0.922 0 0)` | `--border` |
| `color.input` | `oklch(0.922 0 0)` | `--input` |
| `color.ring` | `oklch(0.708 0 0)` | `--ring` |
### Colors — Dark Mode [沿用]
| Token | Value (oklch) |
|-------|---------------|
| `color.background` | `oklch(0.145 0 0)` |
| `color.foreground` | `oklch(0.985 0 0)` |
| `color.card` | `oklch(0.205 0 0)` |
| `color.primary` | `oklch(0.922 0 0)` |
| `color.primary-foreground` | `oklch(0.205 0 0)` |
| `color.secondary` | `oklch(0.269 0 0)` |
| `color.muted` | `oklch(0.269 0 0)` |
| `color.muted-foreground` | `oklch(0.708 0 0)` |
| `color.destructive` | `oklch(0.704 0.191 22.216)` |
| `color.border` | `oklch(1 0 0 / 10%)` |
| `color.input` | `oklch(1 0 0 / 15%)` |
| `color.ring` | `oklch(0.556 0 0)` |
### Semantic 擴充 [新增]
以下 semantic token 在原專案沒有明確定義local 版補齊供狀態顯示用:
| Token | Light | Dark | 用途 |
|-------|-------|------|------|
| `color.success` | `oklch(0.65 0.17 145)` | `oklch(0.75 0.17 145)` | 裝置 Ready、推論成功 |
| `color.warning` | `oklch(0.75 0.18 85)` | `oklch(0.80 0.18 85)` | Mock badge、警告訊息 |
| `color.info` | `oklch(0.60 0.15 240)` | `oklch(0.70 0.15 240)` | 資訊提示 |
| `color.mock-badge.bg` | `oklch(0.88 0.15 85)` | `oklch(0.35 0.15 85)` | Mock 模式 badge 背景 |
| `color.mock-badge.fg` | `oklch(0.30 0.18 85)` | `oklch(0.92 0.12 85)` | Mock 模式 badge 文字 |
### Typography [沿用 + 新增]
| Token | Value | 備註 |
|-------|-------|------|
| `font.family.sans` | 見 `06-cross-platform §6.5` | 跨平台 system font stack |
| `font.family.mono` | 見 `06-cross-platform §6.5` | Log viewer |
| `font.size.xs` | `12px` | [沿用] |
| `font.size.sm` | `13px` | [微調] 桌面 app 密度略高於 webbody 從 14 改 13 |
| `font.size.base` | `14px` | [微調] 原 16桌面常用 14 |
| `font.size.lg` | `16px` | [沿用] |
| `font.size.xl` | `18px` | [沿用] |
| `font.size.2xl` | `22px` | [沿用] |
| `font.size.3xl` | `28px` | [沿用] |
| `font.size.4xl` | `32px` | First-Run welcome |
| `font.weight.regular` | `400` | |
| `font.weight.medium` | `500` | |
| `font.weight.semibold` | `600` | |
| `font.weight.bold` | `700` | |
| `font.line-height.tight` | `1.2` | |
| `font.line-height.normal` | `1.5` | |
| `font.line-height.relaxed` | `1.75` | |
### Spacing [沿用 — tailwind 4 預設]
| Token | Value |
|-------|-------|
| `space.0` | `0` |
| `space.1` | `4px` |
| `space.2` | `8px` |
| `space.3` | `12px` |
| `space.4` | `16px` |
| `space.5` | `20px` |
| `space.6` | `24px` |
| `space.8` | `32px` |
| `space.10` | `40px` |
| `space.12` | `48px` |
| `space.16` | `64px` |
### Radius [沿用]
| Token | Value | 對應原變數 |
|-------|-------|-----------|
| `radius.sm` | `calc(var(--radius) - 4px)` = `6px` | `--radius-sm` |
| `radius.md` | `calc(var(--radius) - 2px)` = `8px` | `--radius-md` |
| `radius.lg` | `var(--radius)` = `10px` | `--radius-lg` |
| `radius.xl` | `calc(var(--radius) + 4px)` = `14px` | `--radius-xl` |
| `radius.2xl` | `calc(var(--radius) + 8px)` = `18px` | `--radius-2xl` |
| `radius.full` | `9999px` | 圓形 avatar、pill |
基礎 `--radius = 0.625rem (10px)`
### Elevation [新增]
桌面 app 需要比 web 更清晰的 z-depth
| Token | Light shadow | Dark shadow | 用途 |
|-------|-------------|-------------|------|
| `elevation.0` | `none` | `none` | Flat |
| `elevation.1` | `0 1px 2px rgba(0,0,0,0.06)` | `0 1px 2px rgba(0,0,0,0.4)` | Card |
| `elevation.2` | `0 2px 4px rgba(0,0,0,0.08)` | `0 2px 4px rgba(0,0,0,0.5)` | Hover card |
| `elevation.3` | `0 4px 12px rgba(0,0,0,0.10)` | `0 4px 12px rgba(0,0,0,0.55)` | Dropdown、popover |
| `elevation.4` | `0 8px 24px rgba(0,0,0,0.15)` | `0 8px 24px rgba(0,0,0,0.65)` | Modal、drawer |
### Motion [新增]
| Token | Value | 用途 |
|-------|-------|------|
| `motion.duration.instant` | `100ms` | Micro-feedback |
| `motion.duration.fast` | `150ms` | Button hover、tab switch |
| `motion.duration.normal` | `250ms` | Modal open、drawer slide |
| `motion.duration.slow` | `400ms` | Page transition |
| `motion.easing.standard` | `cubic-bezier(0.4, 0, 0.2, 1)` | 預設 |
| `motion.easing.decelerate` | `cubic-bezier(0, 0, 0.2, 1)` | 進入動畫 |
| `motion.easing.accelerate` | `cubic-bezier(0.4, 0, 1, 1)` | 離開動畫 |
遵守 `prefers-reduced-motion`:所有 duration > `instant` 都要在使用者開啟 reduced motion 時改為 `0ms``instant`
## 7.3 Component Tokens重點元件
### Sidebar
| Token | Value |
|-------|-------|
| `sidebar.width.expanded` | `240px` |
| `sidebar.width.collapsed` | `64px` |
| `sidebar.background` | `color.card` |
| `sidebar.border` | `1px solid color.border`(右邊) |
| `sidebar.item.height` | `44px` |
| `sidebar.item.padding` | `space.3 space.4` |
| `sidebar.item.radius` | `radius.md` |
| `sidebar.item.active.bg` | `color.primary` |
| `sidebar.item.active.fg` | `color.primary-foreground` |
| `sidebar.item.hover.bg` | `color.accent` |
### Header
| Token | Value |
|-------|-------|
| `header.height` | `56px` |
| `header.background` | `color.background` |
| `header.border` | `1px solid color.border`(下邊) |
| `header.padding` | `space.4 space.6` |
### Card
| Token | Value |
|-------|-------|
| `card.background` | `color.card` |
| `card.border` | `1px solid color.border` |
| `card.radius` | `radius.lg` |
| `card.padding` | `space.5` |
| `card.shadow` | `elevation.1` |
| `card.hover.shadow` | `elevation.2` |
### Button
| Size | Height | Padding | Font size | Radius |
|------|--------|---------|-----------|--------|
| `sm` | `32px` | `space.2 space.3` | `font.size.sm` | `radius.md` |
| `md` | `40px` | `space.2 space.4` | `font.size.base` | `radius.md` |
| `lg` | `48px` | `space.3 space.6` | `font.size.lg` | `radius.lg` |
Variants`primary``secondary``ghost``destructive``outline`(沿用 shadcn 定義)。
### Mock Badge [新增]
| Token | Value |
|-------|-------|
| `badge.mock.bg` | `color.mock-badge.bg` |
| `badge.mock.fg` | `color.mock-badge.fg` |
| `badge.mock.padding` | `space.1 space.2` |
| `badge.mock.radius` | `radius.full` |
| `badge.mock.font-size` | `font.size.xs` |
| `badge.mock.font-weight` | `font.weight.semibold` |
| `badge.mock.border` | `1px solid currentColor` |
## 7.4 與原專案 tokens 的差異摘要
| 項目 | 改動 | 原因 |
|------|------|------|
| body font size | 16 → 14 | 桌面 app 資訊密度要求 |
| 新增 `color.success/warning/info` | — | 原專案沒有明確 semantic color |
| 新增 `color.mock-badge.*` | — | Mock 模式專用視覺 |
| 新增 `elevation.*` | — | 原專案 shadow 只用 tailwind 預設 |
| 新增 `motion.*` | — | 統一動畫語言 |
| 其他 | 完全沿用 | shadcn 架構已足夠 |
## 7.5 Token 落地檔案建議
```
frontend/
├─ src/styles/tokens.css ← 所有 CSS variables
├─ src/styles/globals.css ← import tokens.css
└─ tailwind.config.ts ← extend theme 引用 tokens
```
沿用原專案的 CSS variable 命名(`--primary` 等),不做全面改名,以減少沿用原元件的改動成本。
## 7.6 深色模式切換(第四輪定案)
深色模式的切換**完全靠 CSS `prefers-color-scheme` media query****不需要 JS / Wails emit event**。三平台 WebViewmacOS WKWebView、Windows WebView2、Linux WebKit2GTK皆原生支援系統主題即時同步。
實作方式:
```css
/* tokens.css */
:root {
--background: oklch(1 0 0);
/* ...其他 light tokens */
}
@media (prefers-color-scheme: dark) {
:root {
--background: oklch(0.145 0 0);
/* ...其他 dark tokens */
}
}
```
或用 Tailwind `dark:` variant需設定 `darkMode: 'media'` 而非 `'class'`)。
細節見 `06-cross-platform.md §6.8`