visionA/docs/autoflow/03-design/components.md
jim800121chen fb7da5d180 chore(autoflow): migrate .autoflow/ 共享層文件至 docs/autoflow/
依 autoflow-agent workspace v2 設計把 PRD / 設計 / 架構 / 交付類
共享文件從個人層 .autoflow/(ignored)搬到 docs/autoflow/(進 git),
讓團隊可共享產品與架構文件,個人層只留 progress / review / testing 等
per-branch 筆記。

- 02-prd/        21 個檔(PRD、features、market-analysis 等)
- 03-design/     18 個檔(design-spec、wireframes、flows 等)
- 04-architecture/ 31 個檔(TDD、design-doc、ADR×14、API 規格等)
- 07-delivery/   3 個檔(project-summary、phase-0.6-handover、stage-deployment-setup)

合計 73 檔。原檔已從 .autoflow/ 移除(migration 工具執行 git mv,
但因 .autoflow/ 在 .gitignore 中、git 將此操作視為新增、無 rename history)。
2026-05-04 16:55:55 +08:00

453 lines
20 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.

# 元件庫清單與規格 — visionA Cloud
> **本元件庫 100% 沿用 `local-tool/frontend/src/components/`**Frontend Agent 實作時直接搬(或整併到 monorepo shared package。本文件整理既有元件清單與用途並定義雲端版**新增的 4 個元件**。
---
## 1. 元件分類總覽
| 類別 | 數量 | 來源 | 狀態 |
|------|------|------|------|
| 基礎 UIShadcn 風)| 22 | `src/components/ui/` | 沿用 |
| Layout | 4 | `src/components/layout/` | 沿用Sidebar 需擴充) |
| Dashboard | 3 | `src/components/dashboard/` | 沿用 |
| Devices | 8 | `src/components/devices/` | 沿用(需擴充遠端狀態) |
| Models | 6 | `src/components/models/` | 沿用 |
| Inference | 5 | `src/components/inference/` | 沿用 |
| Camera | 多個 | `src/components/camera/` | 沿用 |
| 特殊 | 7 | 根目錄 | 沿用(部分可能棄用) |
| **雲端版新增** | 4 | `src/components/cloud/`(建議)| 本次新增 |
---
## 2. 基礎 UI 元件(沿用 Shadcn 風)
來源:`local-tool/frontend/src/components/ui/`
| 元件 | 檔案 | 用途 |
|------|------|------|
| `Button` | `button.tsx` | 6 variantsdefault / destructive / outline / secondary / ghost / link8 sizesxs / sm / default / lg / icon*3|
| `Card` | `card.tsx` | 資訊容器(含 Header / Title / Description / Content / Footer / Action 子元件)|
| `Dialog` | `dialog.tsx` | Modal 對話框Radix Dialog 封裝)|
| `AlertDialog` | `alert-dialog.tsx` | 確認危險操作的專用 Dialog無法 ESC 關閉)|
| `Tabs` | `tabs.tsx` | 分頁切換Radix Tabs 封裝)|
| `Input` | `input.tsx` | 單行文字輸入框h-9 |
| `Select` | `select.tsx` | 下拉選單Radix Select 封裝)|
| `Badge` | `badge.tsx` | 標籤徽章6 variants |
| `Slider` | `slider.tsx` | 滑桿Radix Slider 封裝,用於 confidence threshold|
| `Progress` | `progress.tsx` | 進度條Radix Progress |
| `Checkbox` | `checkbox.tsx` | 多選框Radix Checkbox |
| `Label` | `label.tsx` | 表單標籤Radix Label |
| `Separator` | `separator.tsx` | 分隔線 |
| `ScrollArea` | `scroll-area.tsx` | 自訂滾動條Radix ScrollArea |
| `Sonner` | `sonner.tsx` | Toast 通知Sonner 封裝) |
| `EmptyState` | `empty-state.tsx` | 空狀態頁面Icon + Title + Description + Action |
**狀態覆蓋(所有互動元件都需具備):**
- Default / Hover / Active / Focus-visible / Disabled / Loading
- Focus-visible 使用 shadcn 預設 `ring-[3px]`(符合 WCAG AA
- Disabled 統一 `disabled:pointer-events-none disabled:opacity-50`
---
## 3. Layout 元件(沿用 + 擴充)
來源:`local-tool/frontend/src/components/layout/`
| 元件 | 檔案 | 用途 | 雲端版變更 |
|------|------|------|-----------|
| `Header` | `header.tsx` | 頂部列:平台標題 + HelpButton + ConnectionStatus | 平台標題改「visionA Cloud」ConnectionStatus 語義變更(見下) |
| `Sidebar` | `sidebar.tsx` | 左側導航Dashboard / Models / Devices / Workspace / Settings | **新增**:底部 UserMenu**新增**`/clusters` 導航項 |
| `ConnectionStatus` | `connection-status.tsx` | 伺服器連線狀態徽章(綠 / 紅點)| 語義變更local-tool 指「本機 server」Cloud 指「雲端 API Server」|
| `HelpButton` | `help-button.tsx` | 開啟引導driver.js tour| Phase 0 保留Phase 1 重寫內容為雲端版 |
### 3.1 Sidebar 變更規格(雲端版)
```
┌────────────────────────┐
│ [Logo] visionA Cloud │ ← h-14border-b
├────────────────────────┤
│ ▸ Dashboard │
│ ▸ Models │
│ ▸ Devices │
│ ▸ Clusters (new) │ ← 新增
│ ▸ Workspace │
│ ▸ Settings │
│ │
│ (flex-1) │
│ │
├────────────────────────┤
│ [avatar] username ▾ │ ← 新增 UserMenu點開展示 Account / Sign out
├────────────────────────┤
│ v0.1.0 │
└────────────────────────┘
```
**導航項目(繁中 / English**
| i18n key | 繁中 | English | icon |
|---------|------|---------|------|
| `nav.dashboard` | 儀表板 | Dashboard | `LayoutDashboard` |
| `nav.modelLibrary` | 模型庫 | Models | `Boxes` |
| `nav.devices` | 裝置 | Devices | `Cable` |
| `nav.clusters` | 叢集 | Clusters | `Network` |
| `nav.workspace` | 工作區 | Workspace | `Play` |
| `nav.settings` | 設定 | Settings | `Settings` |
> **改動說明**local-tool 目前用 `{ icon: 'H' }` 這種單字母佔位(見 `sidebar.tsx:13-18`設計上不理想。Design Review 列為 **Minor**。**雲端版建議改用 Lucide Icon**,與產品視覺語言一致。
### 3.2 ConnectionStatus 語義變更
原 local-tool 的 `ConnectionStatus` 檢查 `fetch('/system/health')`,顯示「伺服器已連線」。
**雲端版需要區分兩層連線:**
| 層級 | 顯示位置 | 含義 | 綠 / 紅 / 黃 |
|------|---------|------|-------------|
| 雲端 API | Header 右側(現有位置)| 前端能不能打雲端 API Server | 綠OK / 紅API 不可達 |
| 遠端 Agent | 個別裝置卡片 / 詳情頁 | 該使用者的 local agent 有沒有連上雲端 | 綠:在線 / 灰:離線 / 黃:連線中 |
**Cloud 版 `ConnectionStatus` 行為:**
- 綠點 + 「已連線」→ 可以正常使用
- 紅點 + 「連線失敗,重試中」→ 整個服務不可用,顯示全域 `NetworkErrorBanner`
- 不再顯示 local-tool 的「伺服器未連線」— 雲端 API 應該永遠可達,失敗應觸發明顯警告
---
## 4. Dashboard 元件(沿用)
來源:`local-tool/frontend/src/components/dashboard/`
| 元件 | 用途 | 雲端版變更 |
|------|------|-----------|
| `StatCard` | 統計卡片(標題 + 數字 + icon | 無 |
| `ActivityTimeline` | 近期活動時間軸 | 無(但資料來源從 local store 改為雲端事件)|
| `ConnectedDevicesList` | 已連線裝置列表Dashboard 上的)| **小改動**:裝置項目要顯示「最後心跳 X 秒前」|
---
## 5. Devices 元件(沿用 + 擴充)
來源:`local-tool/frontend/src/components/devices/`
| 元件 | 用途 | 雲端版變更 |
|------|------|-----------|
| `DeviceList` | 裝置卡片網格 | 無 |
| `DeviceCard` | 單一裝置卡片(名稱、狀態、類型、韌體、已燒錄模型、操作按鈕)| **擴充**:右上角新增 `RemoteDeviceBadge`(見第 10 節)|
| `DeviceStatus` / `DeviceStatusBadge` | 狀態點 + 文字徽章 | **新增狀態**`offline`(遠端掉線)、`reconnecting`(重連中) |
| `DeviceHealthCard` | 健康狀態(運行時間、韌體版本、最後活動)| **擴充**新增「Pairing Token」、「最後心跳」欄位 |
| `DeviceConnectionLog` | 連線歷史紀錄 | 無(但雲端版 log 應包含 tunnel 事件) |
| `DeviceSettingsCard` | 裝置別名、備註 | 無 |
| `FlashDialog` | 燒錄模型對話框 | 無(行為透過 tunnel 傳到 local agent |
| `FlashProgress` | 燒錄進度 | 無WebSocket 透過雲端中繼) |
### 5.1 DeviceStatusBadge 擴充
**新增狀態(雲端版):**
| 狀態 | 顏色 | i18n key | 文字(繁中)|
|------|------|---------|-----------|
| `offline` | `bg-gray-400` | `devices.status.offline` | 離線 |
| `reconnecting` | `bg-yellow-400 animate-pulse` | `devices.status.reconnecting` | 重新連線中 |
> 既有的 `detected` / `disconnected` 狀態在雲端版可能用不到使用者不會直接「scan」遠端裝置。雛形不刪除但 UI 上會以 Pairing 流程取代 scan。
---
## 6. Models 元件(沿用,無變更)
來源:`local-tool/frontend/src/components/models/`
- `ModelCard` / `ModelGrid` / `ModelFilters` / `ModelDetail` / `ModelUploadDialog` / `ModelComparisonDialog`
雲端版行為差異:上傳 `.nef` 檔案走雲端儲存S3-compat但 UI 不變。
---
## 7. Inference 元件(沿用,無變更)
來源:`local-tool/frontend/src/components/inference/`
- `InferencePanel` / `PerformanceMetrics` / `ClassificationResult` / `VideoProgress` / `ConfidenceSlider`
雲端版行為差異:推論結果透過 WebSocket 從 local agent → 雲端 → 瀏覽器。UI 不變。
---
## 8. Camera 元件(沿用,無變更)
來源:`local-tool/frontend/src/components/camera/`
- `CameraInferenceView` / `CameraControls` / `SourceSelector` / `BatchImageThumbnails`
**雲端版注意:**
- Camera stream 仍然走 local agent硬體存取
- MJPEG stream 透過 tunnel 從 local agent → 雲端 → 瀏覽器顯示
- Image / Video 上傳Phase 0 仍走 local agent 處理Phase 1+ 考慮直上雲端
---
## 9. 特殊元件(部分調整)
來源:`local-tool/frontend/src/components/`
| 元件 | 用途 | 雲端版變更 |
|------|------|-----------|
| `OnboardingDialog` | 首次訪問引導 Dialog | **Phase 0 暫時保留**Phase 1 重寫(現版本假設「插 USB Dongle」雲端不適用|
| `GuidedTour` | driver.js 步驟引導 | **Phase 0 暫時保留**Phase 1 重寫為 Cloud Tour |
| `ServerStatusDashboard` | 後端 Go runtime 狀態 | **Phase 0 可移除 or 隱藏**(使用者看不到雲端 runtime留供 Phase 1 重新定位 |
| `ServerLogViewer` | 伺服器即時日誌 | 同上 |
| `LangSync` | 語言狀態同步 | 無變更 |
| `ThemeSync` | 主題跟隨系統 | 無變更 |
| `StoreHydration` | Zustand store hydration | 無變更 |
---
## 10. 雲端版新增元件
**建議路徑**`visionA-frontend/src/components/cloud/`
### 10.1 `UserMenu`
**用途**Sidebar 底部的使用者選單,雲端版必備。
**視覺**
```
┌──────────────────────────┐
│ [avatar] jim@example.com ▾ │ ← trigger
└──────────────────────────┘
↓ click
┌──────────────────────────┐
│ 帳號設定 (Account) │
│ 語言切換 (Language) │
│ ─────────────── │
│ 登出 (Sign out) │
└──────────────────────────┘
```
**規格:**
- 基底元件Radix DropdownMenushadcn 封裝)
- TriggerButton variant=ghostsize=default
- Avatar40px 圓形(`rounded-full`),顯示使用者 Email 首字母 or GravatarURL
- 下拉位置:`side="top" align="start"`(展開往上)
- 項目圖示Lucide `UserCog` / `Globe` / `LogOut`
**i18n key**
- `account.menu.accountSettings`
- `account.menu.language`
- `account.menu.signOut`
**雛形簡化**Phase 0 `signOut` 直接跳回 `/login`(不接 API`account.menu.accountSettings``/account` stub 頁。
**無障礙:**
- Trigger 可 Tab 聚焦、Enter / Space 展開
- 下拉內容鍵盤可 Arrow 導航
- `aria-label` = 使用者 Email
---
### 10.2 `PairingTokenCard`
**用途**`/devices/pair` 頁面的主要卡片,展示 Pairing Token 並提供複製功能。
**視覺**
```
┌────────────────────────────────────────────────┐
│ 🔗 Pairing Token │
│ │
│ 使用這組 token 讓你的 local agent 連上雲端 │
│ ─────────────────────────────────────── │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ vAc_a1b2c3d4e5f6a7b8 │ │
│ │ c9d0e1f2a3b4c5d6e7f8 │ │
│ │ (vAc_ + 32 hex視覺切兩行 │ │
│ │ 複製為完整 36 字元無空格) │ │
│ └────────────────────────────────────────┘ │
│ │
│ [📋 複製] [🔄 重新產生] │
│ │
│ ⏱ 剩餘 14:52 ──────────────── │
│ (進度條 bg-primary → amber(≤10:00) │
│ → red(≤3:00);過期轉灰 disabled) │
│ 📅 產生時間14:30 │
└────────────────────────────────────────────────┘
```
**規格:**
- 基底:`Card` + CardHeader + CardContent + CardFooter
- Token 格式:`vAc_` + 32 字元 hex總長 36TTL **15 分鐘**,一次性使用
- Token 顯示區:`bg-muted font-mono text-xl tracking-wider p-4 rounded-md select-all`
- 視覺切兩行(第 1 行 `vAc_` + 16 hex第 2 行 16 hexMobile 降為 `text-lg`
- 複製到剪貼簿永遠是**完整 36 字元無空格無換行**
- 過期狀態:`text-muted-foreground line-through`
- 複製按鈕:`variant=default` + Lucide `Copy` icon按下後暫態改為「已複製 ✓」2 秒,伴隨 toast過期時 disabled
- 重新產生:`variant=outline` + Lucide `RefreshCw`;點擊後 AlertDialog 確認「重新產生會讓舊 token 失效,新 token 有效期 15 分鐘」
- 倒數計時器15 分鐘 TTL 必備):
- 格式 `mm:ss`1 秒更新一次
- 進度條 `h-1.5 w-full`,初始 `bg-primary`,≤ 10:00 → `bg-amber-500`,≤ 3:00 → `bg-red-500` 且卡片加 `ring-1 ring-red-300`
- ≤ 0:30 發一次 Toast「Token 即將過期」
- 0:00 自動切過期狀態;主 CTA 變「重新產生 token」
**互動:**
- 按複製:`navigator.clipboard.writeText(token)` + `showSuccess(t('pairing.copied'))`
- 按重新產生:開 AlertDialog確認後呼叫 API → 更新 token + 重置計時
**i18n key**
- `pairing.tokenTitle`
- `pairing.tokenDescription`
- `pairing.copy` / `pairing.copied` / `pairing.regenerate`
- `pairing.expiresIn` / `pairing.generatedAt`
- `pairing.regenerateConfirm` / `pairing.regenerateWarning`
**無障礙:**
- Token 區塊:`aria-label="Pairing token"``role="text"`
- 複製按鈕Enter / Space 可觸發
- 重新產生AlertDialog 的焦點陷阱shadcn 內建)
---
### 10.3 `RemoteDeviceBadge`
**用途**:在雲端場景下顯示單一遠端裝置的連線狀態,取代 / 擴充既有 `DeviceStatusBadge`
**視覺變體:**
```
🟢 在線 ← bg-green-500 + 文字
🟡 重新連線中 (pulse) ← bg-yellow-400 animate-pulse
⚪ 離線・最後心跳 2 分鐘前 ← bg-gray-400 + 文字 + 次要文字timestamp
🔴 錯誤・無法建立 tunnel ← bg-red-500 + 文字 + tooltip 顯示錯誤詳情
```
**規格:**
- 基底:`div.flex.items-center.gap-2`
- 狀態點:`h-2.5 w-2.5 rounded-full`(沿用 `DeviceStatusBadge` 樣式)
- 狀態文字:`text-sm`
- 次要資訊(最後心跳):`text-xs text-muted-foreground`
- `pulse` 狀態:`animate-pulse` class
**Props**
```tsx
interface RemoteDeviceBadgeProps {
status: 'online' | 'offline' | 'reconnecting' | 'error';
lastSeenAt?: string; // ISO 8601 timestamp
errorMessage?: string; // tooltip 顯示
size?: 'sm' | 'md'; // 預設 md
}
```
**使用情境:**
- `/devices` 裝置卡片右上角(取代 `DeviceStatusBadge`
- `/devices/[id]` 裝置詳情頁的大型狀態顯示size=md
- Dashboard `ConnectedDevicesList` 的每個項目右側
- `/workspace/[deviceId]` 頂部(裝置掉線時要能即時看到)
**i18n key新增**
- `remote.status.online` → 在線
- `remote.status.offline` → 離線
- `remote.status.reconnecting` → 重新連線中
- `remote.status.error` → 連線錯誤
- `remote.lastSeen` → 最後心跳 {time}
- `remote.lastSeenNever` → 從未連線
**無障礙:**
- 角色:`role="status"` + `aria-live="polite"`(狀態改變時通知 SR
- 不只靠顏色:圓點 + 文字雙保險
- 錯誤狀態提供 `aria-describedby` 指向 tooltip 的完整訊息
**時間格式化(建議用 `date-fns` 或輕量 util**
- < 60 剛剛
- < 60 X 分鐘前
- < 24 X 小時前
- 24 絕對時間04/20 14:30
---
### 10.4 `NetworkErrorBanner`
**用途**全域警告橫幅當雲端 API 不可達時顯示於 Header 下方
**視覺**
```
┌────────────────────────────────────────────────────────┐
│ ⚠ 連線中斷 — 無法連上雲端服務。正在重試... [立即重試] │
└────────────────────────────────────────────────────────┘
```
**規格:**
- 背景`bg-amber-50 dark:bg-amber-950/30`
- 邊框`border-b border-amber-300 dark:border-amber-700`
- 文字`text-amber-800 dark:text-amber-200 text-sm`
- 圖示Lucide `AlertTriangle``text-amber-600`
- 位置Header 下方 sticky`sticky top-14 z-40`
- 右側按鈕`Button variant=outline size=sm`
**狀態變化:**
- API 正常 不顯示
- API 失敗 > 3 次連續 → 顯示 banner
- API 恢復 → banner 切換為「已恢復連線」短暫顯示 3 秒後消失
**i18n key**
- `network.disconnected.title` → 連線中斷
- `network.disconnected.description` → 無法連上雲端服務。正在重試...
- `network.disconnected.retryButton` → 立即重試
- `network.restored` → 已恢復連線 ✓
**無障礙:**
- `role="alert"` + `aria-live="assertive"`(重要警告)
- 重試按鈕:`aria-label="重試連線"`
---
## 11. 元件狀態覆蓋檢查表(給 Frontend QA 與 Design QA
每個互動元件都應有以下狀態:
| 狀態 | 所有按鈕 / Input | 卡片列表 | 頁面 | 資料載入 |
|------|-----------------|---------|------|---------|
| Default | ✅ | ✅ | ✅ | — |
| Hover | ✅ | ✅(整個卡片)| — | — |
| Active / Pressed | ✅ | — | — | — |
| Focus-visible | ✅ | ✅ | — | — |
| Disabled | ✅ | — | — | — |
| Loading | ✅Loader2 icon| ✅skeleton| ✅skeleton| ✅skeleton|
| Empty | — | ✅EmptyState| ✅EmptyState| — |
| Error | — | ✅error banner| ✅error page| ✅retry|
| Success | ✅toast| — | — | — |
---
## 12. UX Writing 規範(簡版,完整版見 Flow 子檔)
**產品語調:**
- 對象是開發者可用技術術語如「Pairing Token」、「tunnel」、「session」但不濫用
- 錯誤訊息要**說清楚發生什麼事 + 使用者能做什麼**
- 避免過度客氣(不需要「請」「您」滿天飛)
- 繁中台灣用語(不用「鏈接」用「連結」;不用「您」頻繁出現)
**常用文案(整合到 i18n**
| 場景 | 繁中 | English |
|------|------|---------|
| 載入中 | 載入中... | Loading... |
| 儲存成功 | 已儲存 | Saved |
| 儲存失敗 | 儲存失敗,請重試 | Save failed, please retry |
| 刪除確認 | 確定要刪除「{name}」嗎?此操作無法復原。 | Delete "{name}"? This cannot be undone. |
| 空列表 | 還沒有任何紀錄 | Nothing here yet |
| API 錯誤 | 連線失敗,請檢查網路或稍後再試 | Connection failed, check network or try later |
| 權限不足 | 沒有權限進行此操作 | No permission for this action |
| Session 過期 | 登入已過期,請重新登入 | Session expired, please sign in |
---
## 13. 實作建議(給 Frontend Agent
1. **Monorepo 結構**:若 `visionA-frontend``local-tool` 之後都在同 repo可抽出 `packages/ui/``packages/i18n/` 共用避免重複。Phase 0 不需要,直接複製即可。
2. **新元件檔案放 `src/components/cloud/`**,命名清晰,不要與既有元件混放。
3. **測試**:新增的元件(`UserMenu``PairingTokenCard``RemoteDeviceBadge``NetworkErrorBanner`)都要有對應 Vitest 測試。
4. **Storybook / Playground**Phase 0 不要求Phase 1 考慮引入 Storybook。