# 客户端 UI/UX 整改执行计划

> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** 基于当前客户端代码事实，把 renderer 收敛成更稳定、更专业、更易维护的 AI 桌面工作台。

**Architecture:** 不重写业务链路，不改 Electron IPC 合约。先固化事实基线和样式边界，再逐步压薄 `App.tsx`、收敛 CSS 覆盖、补齐工作台交互和可访问性。

**Tech Stack:** Electron renderer, Vite, React 19, TypeScript, plain CSS modules via `apps/ui/src/styles.css`, existing smoke hooks.

---

## 1. 当前事实基线

### 代码结构

- `apps/ui/src/App.tsx` 当前约 1674 行，仍承担顶层状态编排、视图切换、会话控制、设置 props 组装、smoke hooks 和启动遮罩。
- `apps/ui/src/styles.css` 已是入口文件，只 import `apps/ui/src/styles/*.css`。
- 主样式分散在 `base.css`、`components.css`、`shell.css`、`chat.css`、`settings.css`、`plugins.css`、`knowledge.css`、`tasks.css`、`automation.css`、`theme-openclaw.css`。
- 聊天主工作区已拆到 `features/chat/ConversationWorkspaceView.tsx`，但 props 数量过多，说明页面边界仍不够稳定。
- 通用 UI 组件已存在：`Button`、`IconButton`、`Panel`、`ScrollArea`、`StatusChip`、`Tabs`。

### UI/UX 基线

- 产品类型：AI 生产力桌面客户端，核心体验应接近运营工作台，而不是营销页或普通聊天 demo。
- 当前优势：两栏骨架稳定、聊天/附件/流式状态完整、部分 focus 和 `aria-live` 已存在。
- 当前风险：CSS 多层覆盖、视觉蓝紫/玻璃/渐变偏多、移动断点不完整、导航密集但缺少 skip link、部分页面仍有 emoji 或手写 SVG 图标。
- 重点约束：继续保留 `conversation-shell`、`conversation-main-layout`、`conversation-content-area`、`conversation-panel`，不得破坏 smoke helpers 依赖的 DOM 和 selector。

## 2. 执行原则

- 不做一次性重写，每个阶段必须独立通过 typecheck/build。
- 优先修维护风险，再修视觉观感。
- 不改 `packages/shared-types` IPC 契约，除非单独立项。
- 不删除或隐藏现有 UI 控件，除非先确认 smoke helpers 和 renderer test 不依赖。
- 修改 `App.tsx` 时只用小 patch，避免中文编码损坏；修改后检查无 UTF-8 BOM。
- 工作台视觉以灰白为主、蓝色为状态和关键操作辅助，减少紫色渐变、彩色发光和过强阴影。

## 3. Phase 1 - 建立 UI 回归基线

**目标:** 先形成可复测基线，避免后续 UI 调整凭主观判断推进。

**Files:**

- Modify: `docs/2026-05-25-client-ui-ux-execution-plan.md`
- Read-only reference: `apps/ui/src/App.tsx`
- Read-only reference: `apps/ui/src/styles.css`
- Read-only reference: `apps/ui/src/styles/*.css`
- Read-only reference: `apps/ui/test/*.test.ts`

- [ ] **Step 1: 记录当前核心文件规模**

  Run:

  ```sh
  wc -l apps/ui/src/App.tsx apps/ui/src/styles.css apps/ui/src/styles/*.css
  ```

  Expected:

  - 记录 `App.tsx` 行数。
  - 记录每个 CSS 文件行数。
  - 如果 `theme-openclaw.css`、`shell.css`、`components.css` 仍是最大样式文件，后续 CSS 收口优先从这三处开始。

- [ ] **Step 2: 记录核心布局类定义位置**

  Run:

  ```sh
  rg -n "^\\.(shell|sidebar|main-shell|content-area|conversation-panel|message-list|composer-shell)\\b|\\.conversation-shell \\." apps/ui/src/styles/*.css
  ```

  Expected:

  - 输出所有核心类定义位置。
  - 标出基础定义、聊天覆盖、主题覆盖三类来源。
  - 不在本阶段删除样式，只形成清单。

- [ ] **Step 3: 跑基础验证**

  Run:

  ```sh
  corepack pnpm --filter @qjclaw/ui typecheck
  corepack pnpm build
  ```

  Expected:

  - 两个命令通过。
  - 如果失败，先修复当前失败，不进入 Phase 2。

- [ ] **Step 4: 保存基线截图**

  Start app:

  ```sh
  corepack pnpm dev
  ```

  Capture these views manually or with Playwright:

  - Chat home
  - Expert chat
  - Task panel
  - Automation tasks
  - Knowledge
  - Settings

  Expected:

  - 每个页面有桌面宽度截图。
  - 至少补一张窄宽度截图，确认 `min-width: 960px` 的实际行为。

## 4. Phase 2 - 收敛 CSS 骨架和视觉 token

**目标:** 让核心布局类只有清晰的基础层和主题层，减少后续 UI 回归。

**Files:**

- Modify: `apps/ui/src/styles/base.css`
- Modify: `apps/ui/src/styles/components.css`
- Modify: `apps/ui/src/styles/shell.css`
- Modify: `apps/ui/src/styles/chat.css`
- Modify: `apps/ui/src/styles/theme-openclaw.css`

- [ ] **Step 1: 建立 token 边界**

  In `apps/ui/src/styles/theme-openclaw.css`, keep all product-level theme variables under:

  ```css
  .shell.openclaw-theme {
    --revamp-canvas: #f5f7fa;
    --revamp-surface: #ffffff;
    --revamp-surface-soft: #f8fafc;
    --revamp-text: #0f172a;
    --revamp-text-muted: #475569;
    --revamp-text-soft: #64748b;
    --revamp-blue: #2563eb;
    --revamp-blue-strong: #1d4ed8;
    --revamp-blue-soft: #eff6ff;
    --revamp-border: rgba(148, 163, 184, 0.24);
    --revamp-border-strong: rgba(148, 163, 184, 0.38);
    --revamp-shadow: 0 14px 32px rgba(15, 23, 42, 0.06);
    --revamp-shadow-soft: 0 8px 18px rgba(15, 23, 42, 0.04);
  }
  ```

  Expected:

  - Purple variables may remain only where still referenced by legacy expert-specific styles.
  - New or touched styles use the gray/blue token set above.

- [ ] **Step 2: Reduce duplicate core layout definitions**

  Keep responsibilities:

  - `base.css`: reset, root tokens, font, body.
  - `components.css`: generic reusable components only.
  - `shell.css`: base shell layout and non-theme structural behavior.
  - `chat.css`: conversation-specific structure only under `.conversation-shell`.
  - `theme-openclaw.css`: final product skin and current gray/blue visual theme.

  Expected:

  - No new global `.message-list` or `.composer-shell` visual overrides outside the intended layer.
  - Conversation-only changes remain scoped under `.conversation-shell ...`.

- [ ] **Step 3: Remove obvious visual noise**

  In touched rules:

  - Replace heavy color shadows with `var(--revamp-shadow-soft)` or border-only states.
  - Avoid new `translateY` hover movement.
  - Keep card radius at or below existing app norms unless the rule already requires larger panels.
  - Do not add decorative orbs, bokeh, or unrelated gradients.

  Expected:

  - Left sidebar and workspace feel calmer.
  - Active/hover/focus states remain visible.

- [ ] **Step 4: Validate after CSS edits**

  Run:

  ```sh
  corepack pnpm --filter @qjclaw/ui typecheck
  corepack pnpm build
  ```

  Expected:

  - Both pass.
  - `git diff -- apps/ui/src/styles.css apps/ui/src/styles/*.css` shows targeted CSS changes only.

## 5. Phase 3 - 压薄 App.tsx 的 UI 编排

**目标:** 降低 `App.tsx` 的维护风险，但不碰 stream 主链路和 smoke action 协议。

**Files:**

- Modify: `apps/ui/src/App.tsx`
- Modify: `apps/ui/src/features/chat/ConversationWorkspaceView.tsx`
- Modify: `apps/ui/src/features/settings/SettingsPanels.tsx`
- Create or modify focused hooks only under existing `apps/ui/src/features/*`

- [ ] **Step 1: 拆出纯 props 组装**

  Move only pure prop-building logic from `App.tsx` into focused helpers or hooks when all inputs are already available.

  Candidate boundaries:

  - Conversation workspace props.
  - Settings panel props.
  - Sidebar derived labels and entries.

  Expected:

  - No behavior change.
  - No IPC calls move across ownership boundaries in this step.
  - `App.tsx` line count decreases, but line count is not the success metric; clearer ownership is.

- [ ] **Step 2: Keep high-risk flows in place**

  Do not move these during this phase:

  - stream request lifecycle
  - `__QJC_SMOKE__`
  - `__QJC_SMOKE_ACTIONS__`
  - composer submit/cancel
  - session creation/closing
  - startup overlay retry/export actions

  Expected:

  - Existing smoke tests do not need selector or action rewrites.

- [ ] **Step 3: Reduce oversized component props**

  For `ConversationWorkspaceView`, group related props into typed objects only when ownership is obvious:

  - `status`
  - `emptyState`
  - `messages`
  - `composer`
  - `actions`

  Expected:

  - Component call site becomes easier to read.
  - Existing child component props stay unchanged unless required.

- [ ] **Step 4: Validate App.tsx encoding and tests**

  Run:

  ```sh
  /usr/bin/python3 -c "from pathlib import Path; p=Path('apps/ui/src/App.tsx'); b=p.read_bytes(); print(b[:3]); assert b[:3] != b'\\xef\\xbb\\xbf'"
  git diff -- apps/ui/src/App.tsx
  corepack pnpm --filter @qjclaw/ui typecheck
  ```

  Expected:

  - First command prints bytes that are not UTF-8 BOM.
  - Diff contains no mojibake and no unrelated Chinese copy changes.
  - UI typecheck passes.

## 6. Phase 4 - 修正核心工作流 UI/UX

**目标:** 优先改善用户每天会反复使用的界面：聊天、任务、自动化、设置。

**Files:**

- Modify: `apps/ui/src/features/chat/ChatComposer.tsx`
- Modify: `apps/ui/src/features/chat/MessageList.tsx`
- Modify: `apps/ui/src/features/tasks/TaskPanelView.tsx`
- Modify: `apps/ui/src/features/automation/AutomationTasksView.tsx`
- Modify: `apps/ui/src/features/settings/SettingsPanels.tsx`
- Modify: matching CSS files under `apps/ui/src/styles/`

- [ ] **Step 1: Chat composer**

  Requirements:

  - Keep Enter send and Shift+Enter newline behavior.
  - Keep attachment upload button and drag-drop.
  - Keep resize handle.
  - Ensure disabled state remains readable.
  - Ensure focus state uses one consistent blue ring.

  Expected:

  - Composer does not resize the main shell unexpectedly.
  - Attachment chip text truncates cleanly.
  - Submit button remains icon-first with accessible label.

- [ ] **Step 2: Message list**

  Requirements:

  - Keep user messages right-aligned and assistant messages left-aligned.
  - Keep assistant markdown card readable at long line lengths.
  - Keep copy/delete action buttons keyboard reachable.
  - Keep streaming trace `aria-live` behavior.

  Expected:

  - Long Chinese, English, URLs, and code blocks do not break layout.
  - Message actions do not shift message height when appearing.

- [ ] **Step 3: Task panel icon cleanup**

  Replace visible emoji used as UI icons with existing icon components or local SVG components.

  Known target:

  - `apps/ui/src/features/tasks/TaskPanelView.tsx`: package icon in the content output heading.

  Expected:

  - No visible emoji icons remain in primary tool controls or headings.
  - Existing Chinese text remains unchanged except for necessary label updates.

- [ ] **Step 4: Automation tasks density**

  Requirements:

  - Keep list, detail, form, and run history usable without window-level scroll confusion.
  - Filter buttons and edit/create actions must have clear active and disabled states.
  - Error state must use `role="alert"` or visible announced equivalent.

  Expected:

  - The page reads as an operational tool, not a card-heavy marketing layout.
  - Long task prompts truncate or wrap predictably.

- [ ] **Step 5: Settings hierarchy**

  Requirements:

  - Keep config source toggle visible and keyboard reachable.
  - Secret reveal and copy controls must stay accessible.
  - Save/reset/edit buttons must communicate disabled state clearly.
  - Tabs must preserve `aria` semantics from existing `Tabs` component.

  Expected:

  - Users can scan required vs optional config groups quickly.
  - Editing one section does not visually imply other sections are editing.

- [ ] **Step 6: Validate key workflows**

  Run:

  ```sh
  corepack pnpm --filter @qjclaw/ui typecheck
  corepack pnpm build
  ```

  If touched flow has existing source tests, also run:

  ```sh
  node --test apps/ui/test/taskPanelViewSource.test.ts
  node --test apps/ui/test/settingsPanelsSource.test.ts
  node --test apps/ui/test/chatCancelSource.test.ts
  ```

  Expected:

  - Typecheck and build pass.
  - Relevant source tests pass.

## 7. Phase 5 - 可访问性和响应式补齐

**目标:** 解决 UI-ux-pro-max 指出的高优先级问题：键盘导航、skip link、错误提示、图片 alt、响应式边界。

**Files:**

- Modify: `apps/ui/src/App.tsx`
- Modify: `apps/ui/src/features/shell/AppSidebar.tsx`
- Modify: `apps/ui/src/features/shell/Sidebar.tsx`
- Modify: `apps/ui/src/styles/base.css`
- Modify: `apps/ui/src/styles/shell.css`
- Modify: `apps/ui/src/styles/theme-openclaw.css`

- [ ] **Step 1: Add skip link**

  Add a visually hidden but focus-visible skip link near the top of the shell:

  ```tsx
  <a className="skip-link" href="#main-content">跳到主内容</a>
  ```

  Add id to main content:

  ```tsx
  <main id="main-content" className={...}>
  ```

  Expected:

  - First Tab focuses skip link.
  - Pressing Enter moves focus target to main content.

- [ ] **Step 2: Add skip link styles**

  Add CSS:

  ```css
  .skip-link {
    position: fixed;
    top: 10px;
    left: 10px;
    z-index: 10000;
    padding: 8px 12px;
    border-radius: 8px;
    background: #ffffff;
    color: #1d4ed8;
    border: 1px solid rgba(37, 99, 235, 0.38);
    transform: translateY(-140%);
  }

  .skip-link:focus-visible {
    transform: translateY(0);
    outline: 2px solid rgba(37, 99, 235, 0.56);
    outline-offset: 2px;
  }
  ```

  Expected:

  - Hidden by default.
  - Visible only when focused.

- [ ] **Step 3: Confirm nav tab order**

  Manual validation:

  - Tab order starts at skip link.
  - Then window controls if focusable.
  - Then sidebar primary navigation.
  - Then page/workspace content.
  - Then composer or page actions.

  Expected:

  - No keyboard trap.
  - No hidden active control receives focus unless intentionally screen-reader-only.

- [ ] **Step 4: Define desktop responsive contract**

  Current shell uses `min-width: 960px`. Keep that if the product is desktop-only, but document it in CSS comments and acceptance notes.

  Expected:

  - At widths below 960px, behavior is intentional: either horizontal app viewport constraint or a later mobile-specific plan.
  - Do not pretend mobile is supported unless the shell actually supports it.

- [ ] **Step 5: Validate accessibility basics**

  Manual checks:

  - Error messages announce via `role="alert"` or `aria-live`.
  - Meaningful images have alt text; decorative images use `alt=""`.
  - Buttons with icon-only visuals have `aria-label`.
  - Heading hierarchy per page starts with one clear `h1` or equivalent page title.

  Expected:

  - No obvious keyboard-only blocker in chat, settings, task panel, automation tasks.

## 8. Final Acceptance Checklist

- [ ] `corepack pnpm --filter @qjclaw/ui typecheck` passes.
- [ ] `corepack pnpm build` passes.
- [ ] Relevant source tests pass for touched views.
- [ ] `App.tsx` has no UTF-8 BOM.
- [ ] `git diff -- apps/ui/src/App.tsx` shows no Chinese mojibake.
- [ ] Chat, experts, tasks, automation, knowledge, settings render with correct height and scrolling.
- [ ] Left sidebar remains left column; right workspace remains full work area.
- [ ] No core smoke selector or `__QJC_SMOKE_ACTIONS__` contract is removed.
- [ ] No visible emoji remains in primary tool controls after Phase 4.
- [ ] Focus-visible states are visible in sidebar, composer, tabs, settings controls, and message actions.

## 9. Suggested Commit Sequence

1. `docs(ui): add client ui ux execution plan`
2. `refactor(ui): document and reduce shell style overlap`
3. `refactor(ui): reduce app renderer prop assembly`
4. `fix(ui): polish chat workspace interactions`
5. `fix(ui): align task automation settings workbench ui`
6. `fix(ui): add renderer keyboard navigation affordances`

Each commit should include the validation commands run in the commit body or PR description.
