依 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)。
453 lines
20 KiB
Markdown
453 lines
20 KiB
Markdown
# 元件庫清單與規格 — visionA Cloud
|
||
|
||
> **本元件庫 100% 沿用 `local-tool/frontend/src/components/`**,Frontend Agent 實作時直接搬(或整併到 monorepo shared package)。本文件整理既有元件清單與用途,並定義雲端版**新增的 4 個元件**。
|
||
|
||
---
|
||
|
||
## 1. 元件分類總覽
|
||
|
||
| 類別 | 數量 | 來源 | 狀態 |
|
||
|------|------|------|------|
|
||
| 基礎 UI(Shadcn 風)| 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 variants(default / destructive / outline / secondary / ghost / link),8 sizes(xs / 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-14,border-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 DropdownMenu(shadcn 封裝)
|
||
- Trigger:Button variant=ghost,size=default
|
||
- Avatar:40px 圓形(`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(總長 36),TTL **15 分鐘**,一次性使用
|
||
- Token 顯示區:`bg-muted font-mono text-xl tracking-wider p-4 rounded-md select-all`
|
||
- 視覺切兩行(第 1 行 `vAc_` + 16 hex,第 2 行 16 hex);Mobile 降為 `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。
|