Files
zclaw_openfang/docs/plans/cached-greeting-cocke.md
iven 0d4fa96b82
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
refactor: 统一项目名称从OpenFang到ZCLAW
重构所有代码和文档中的项目名称,将OpenFang统一更新为ZCLAW。包括:
- 配置文件中的项目名称
- 代码注释和文档引用
- 环境变量和路径
- 类型定义和接口名称
- 测试用例和模拟数据

同时优化部分代码结构,移除未使用的模块,并更新相关依赖项。
2026-03-27 07:36:03 +08:00

616 lines
15 KiB
Markdown

# ZCLAW UI/UX 全面优化计划
## 背景
ZCLAW 是基于 ZCLAW (Rust Agent OS) 的 AI Agent 桌面客户端。经过 Phase 1-8 的功能开发,系统已达到 93% API 覆盖率和 100% UI 组件完成度。现在需要对前端设计元素进行全面优化,提升用户操作效率与视觉体验。
## 当前状态分析
### 代码结构
- **框架**: React 18 + TypeScript + Tauri
- **样式**: Tailwind CSS v4.2.1
- **状态管理**: Zustand (gatewayStore, chatStore, teamStore)
- **图标**: lucide-react
- **组件数量**: 37 个组件
### 现有设计特点
- **主色调**: Orange (#f97316) 作为品牌色
- **布局**: 三栏式 (Sidebar w-64 | Main flex-1 | RightPanel w-80)
- **暗黑模式**: 部分支持 (部分组件有 `dark:` 变体)
- **动画**: 基础 CSS 动画 (animate-pulse, animate-spin)
---
## 发现的问题
### 1. 设计系统问题 (CRITICAL)
| 问题 | 位置 | 影响 |
|------|------|------|
| 无 UI 组件库 | 全局 | 一致性差,重复代码 |
| 颜色系统不完整 | index.css | 品牌识别度低 |
| 暗黑模式不完整 | 多个组件 | 用户体验不一致 |
| **使用 Emoji 作为 UI 图标** | ChatArea, App.tsx | 不专业,违反设计规范 |
### 2. 可访问性问题 (CRITICAL)
| 问题 | 位置 | 影响 |
|------|------|------|
| 缺少 aria-label | 图标按钮 | 屏幕阅读器无法识别 |
| 焦点状态不明显 | 多个交互元素 | 键盘导航困难 |
| 颜色对比度不足 | text-gray-400 类 | 可读性差 |
### 3. 交互与动画 (HIGH)
| 问题 | 位置 | 影响 |
|------|------|------|
| 无过渡动画库 | 全局 | 交互生硬 |
| 悬停状态不一致 | 多个组件 | 用户困惑 |
| 缺少骨架屏 | 数据加载 | 感知性能差 |
### 4. 视觉层次 (MEDIUM)
| 问题 | 位置 | 影响 |
|------|------|------|
| 卡片阴影过轻 | shadow-sm | 层次不明显 |
| 间距不一致 | padding/margin | 视觉混乱 |
| 字体过小 | text-xs | 可读性差 |
### 5. 用户体验 (MEDIUM)
| 问题 | 位置 | 影响 |
|------|------|------|
| 空状态设计简陋 | 多个列表 | 缺乏引导 |
| 错误提示不明显 | 表单等 | 用户困惑 |
| 加载反馈不足 | API 调用 | 用户焦虑 |
---
## 用户确认的优化方向
| 决策项 | 选择 |
|--------|------|
| 动画库 | ✅ 引入 Framer Motion |
| 暗黑模式 | ✅ 完整支持所有组件 |
| 组件库 | ✅ 创建 Button, Card, Input 等基础组件 |
---
## 优化方案
### Phase 1: 设计系统建立 (P0)
#### 1.1 CSS 变量系统
**文件**: `desktop/src/index.css`
```css
:root {
/* Brand Colors */
--color-primary: #f97316;
--color-primary-hover: #ea580c;
--color-primary-light: #fff7ed;
/* Semantic Colors */
--color-success: #22c55e;
--color-warning: #eab308;
--color-error: #ef4444;
--color-info: #3b82f6;
/* Neutral Colors */
--color-bg: #ffffff;
--color-bg-secondary: #f9fafb;
--color-border: #e5e7eb;
--color-text: #111827;
--color-text-secondary: #6b7280;
--color-text-muted: #9ca3af;
/* Spacing Scale */
--space-xs: 4px;
--space-sm: 8px;
--space-md: 16px;
--space-lg: 24px;
--space-xl: 32px;
/* Border Radius */
--radius-sm: 6px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--radius-full: 9999px;
/* Shadows */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
/* Transitions */
--transition-fast: 150ms ease;
--transition-normal: 200ms ease;
--transition-slow: 300ms ease;
}
.dark {
--color-bg: #0f172a;
--color-bg-secondary: #1e293b;
--color-border: #334155;
--color-text: #f1f5f9;
--color-text-secondary: #94a3b8;
--color-text-muted: #64748b;
}
```
#### 1.2 统一 Tailwind 配置
**文件**: `desktop/tailwind.config.js` (新建)
```javascript
export default {
theme: {
extend: {
colors: {
primary: {
DEFAULT: 'var(--color-primary)',
hover: 'var(--color-primary-hover)',
light: 'var(--color-primary-light)',
},
},
boxShadow: {
'card': 'var(--shadow-md)',
'hover': 'var(--shadow-lg)',
},
transitionDuration: {
'fast': '150ms',
'normal': '200ms',
},
},
},
}
```
### Phase 2: 基础组件库 (P0)
#### 2.1 Button 组件
**文件**: `desktop/src/components/ui/Button.tsx`
```tsx
import { forwardRef } from 'react';
import { motion } from 'framer-motion';
import { cn } from '../../lib/utils';
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
size?: 'sm' | 'md' | 'lg';
loading?: boolean;
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant = 'primary', size = 'md', loading, children, disabled, ...props }, ref) => {
return (
<motion.button
ref={ref}
whileTap={{ scale: 0.98 }}
className={cn(
'inline-flex items-center justify-center font-medium rounded-lg transition-colors',
'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2',
'disabled:opacity-50 disabled:cursor-not-allowed',
variants[variant],
sizes[size],
className
)}
disabled={disabled || loading}
{...props}
>
{loading && <Spinner className="mr-2" />}
{children}
</motion.button>
);
}
);
const variants = {
primary: 'bg-primary text-white hover:bg-primary-hover',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
ghost: 'text-gray-600 hover:bg-gray-100',
danger: 'bg-red-500 text-white hover:bg-red-600',
};
const sizes = {
sm: 'px-3 py-1.5 text-xs',
md: 'px-4 py-2 text-sm',
lg: 'px-6 py-3 text-base',
};
```
#### 2.2 Card 组件
**文件**: `desktop/src/components/ui/Card.tsx`
```tsx
import { motion } from 'framer-motion';
import { cn } from '../../lib/utils';
interface CardProps {
children: React.ReactNode;
className?: string;
hoverable?: boolean;
onClick?: () => void;
}
export function Card({ children, className, hoverable, onClick }: CardProps) {
const Component = hoverable ? motion.div : 'div';
return (
<Component
className={cn(
'rounded-xl border border-gray-200 bg-white p-4 shadow-sm',
'dark:border-gray-700 dark:bg-gray-800',
hoverable && 'cursor-pointer hover:shadow-md transition-shadow duration-200',
className
)}
{...(hoverable && {
whileHover: { y: -2 },
onClick,
})}
>
{children}
</Component>
);
}
```
#### 2.3 cn() 工具函数
**文件**: `desktop/src/lib/utils.ts`
```typescript
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
```
**原则**: 使用 SVG 图标 (lucide-react),不使用 emoji 作为 UI 元素
| 文件 | 当前 | 修改为 |
|------|------|--------|
| `ChatArea.tsx:79` | `🤖` | `<BotIcon className="w-10 h-10 text-gray-400" />` |
| `ChatArea.tsx:279` | `🦞` (消息气泡) | `<ZClawLogo className="w-6 h-6" />` (自定义图标) |
| `App.tsx:79` | `🤖` | `<BotIcon />` |
| `App.tsx:98` | `👥` | `<UsersIcon />` |
| `Sidebar.tsx:98` | 用户头像 emoji | 首字母 + 渐变背景 |
### Phase 3: 可访问性改进 (P0)
#### 3.1 添加 aria-label
**关键文件**:
- `Sidebar.tsx` - 设置按钮、tab 切换
- `ChatArea.tsx` - 发送按钮、附件按钮、模型选择器
- `RightPanel.tsx` - tab 切换、刷新按钮
- `SettingsLayout.tsx` - 返回按钮、菜单项
```tsx
// 示例修复
<button
onClick={onOpenSettings}
aria-label="打开设置"
className="..."
>
<Settings className="w-4 h-4" />
</button>
```
#### 3.2 焦点状态增强
```css
/* 全局焦点样式 */
:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
/* 按钮焦点 */
.btn:focus-visible {
ring: 2px;
ring-color: var(--color-primary);
ring-offset: 2px;
}
```
#### 3.3 颜色对比度修复
| 当前 | 对比度 | 修复 |
|------|--------|------|
| `text-gray-400` on white | 3.1:1 (FAIL) | 改为 `text-gray-500` (#6b7280) 4.6:1 |
| `text-gray-300` on white | 2.9:1 (FAIL) | 改为 `text-gray-600` (#4b5563) 7.0:1 |
### Phase 4: 交互与动画增强 (P1)
#### 4.1 Framer Motion 动画系统
**新文件**: `desktop/src/lib/animations.ts`
```typescript
import { Variants } from 'framer-motion';
// 页面切换动画
export const pageVariants: Variants = {
initial: { opacity: 0, y: 10 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -10 },
};
// 列表项交错动画
export const listItemVariants: Variants = {
hidden: { opacity: 0, x: -10 },
visible: { opacity: 1, x: 0 },
};
// 按钮点击动画
export const buttonTap = { scale: 0.98 };
// 卡片悬停动画
export const cardHover = { y: -2, boxShadow: '0 10px 25px -5px rgb(0 0 0 / 0.1)' };
// 默认过渡配置
export const defaultTransition = {
duration: 0.2,
ease: [0.4, 0, 0.2, 1],
};
```
**使用示例**:
```tsx
import { motion, AnimatePresence } from 'framer-motion';
import { pageVariants, defaultTransition } from '../lib/animations';
// 页面切换
<AnimatePresence mode="wait">
<motion.div
key={view}
variants={pageVariants}
initial="initial"
animate="animate"
exit="exit"
transition={defaultTransition}
>
{content}
</motion.div>
</AnimatePresence>
```
**新文件**: `desktop/src/components/ui/Skeleton.tsx`
```tsx
export function Skeleton({ className }: { className?: string }) {
return (
<div
className={cn(
"animate-pulse bg-gray-200 dark:bg-gray-700 rounded",
className
)}
/>
);
}
export function CardSkeleton() {
return (
<div className="rounded-xl border border-gray-200 p-4">
<Skeleton className="h-4 w-24 mb-3" />
<Skeleton className="h-3 w-full mb-2" />
<Skeleton className="h-3 w-3/4" />
</div>
);
}
```
#### 4.3 Toast 通知系统
**新文件**: `desktop/src/components/ui/Toast.tsx`
用于替代 `alert()` 和内联错误消息。
### Phase 5: 视觉层次优化 (P1)
#### 5.1 卡片阴影增强
```diff
- className="rounded-xl border border-gray-200 bg-white p-4 shadow-sm"
+ className="rounded-xl border border-gray-200 bg-white p-4 shadow-sm hover:shadow-md transition-shadow duration-200"
```
#### 5.2 间距标准化
| 区域 | 当前 | 标准 |
|------|------|------|
| 页面内边距 | 不一致 | `p-6` (24px) |
| 卡片内边距 | `p-3`/`p-4` | `p-4` (16px) |
| 列表项间距 | `space-y-1`/`space-y-2` | `space-y-2` (8px) |
| 区域间距 | `space-y-3`/`space-y-4` | `space-y-4` (16px) |
#### 5.3 字体大小优化
| 类型 | 当前 | 建议 |
|------|------|------|
| 正文 | `text-xs` (12px) | `text-sm` (14px) |
| 小标签 | `text-[10px]` | `text-xs` (12px) |
| 标题 | `text-lg` | 保持 |
### Phase 6: 用户体验改进 (P2)
#### 6.1 空状态设计
**新组件**: `EmptyState.tsx`
```tsx
interface EmptyStateProps {
icon: React.ReactNode;
title: string;
description: string;
action?: React.ReactNode;
}
export function EmptyState({ icon, title, description, action }: EmptyStateProps) {
return (
<div className="flex-1 flex items-center justify-center p-6">
<div className="text-center max-w-sm">
<div className="w-16 h-16 bg-gray-100 dark:bg-gray-800 rounded-full flex items-center justify-center mx-auto mb-4 text-gray-400">
{icon}
</div>
<h3 className="text-base font-semibold text-gray-700 dark:text-gray-300 mb-2">
{title}
</h3>
<p className="text-sm text-gray-500 dark:text-gray-400 mb-4">
{description}
</p>
{action}
</div>
</div>
);
}
```
#### 6.2 错误状态设计
- 使用红色边框和背景
- 显示错误图标
- 提供重试按钮
#### 6.3 加载状态改进
- 按钮加载时禁用并显示 spinner
- 列表加载时显示骨架屏
- 全局加载时显示顶部进度条
---
## 实施顺序
### 阶段 1: 基础设施 (2-3 天)
1. 安装依赖: `framer-motion clsx tailwind-merge`
2. 创建 CSS 变量系统 (含完整暗黑模式)
3. 创建 tailwind.config.js
4. 创建 utils.ts (cn 函数)
5. 创建 animations.ts (Framer Motion 预设)
### 阶段 2: 基础组件库 (2-3 天)
1. 创建 Button 组件 (含变体: primary, secondary, ghost)
2. 创建 Card 组件 (含悬停动画)
3. 创建 Input 组件 (含焦点状态)
4. 创建 Badge 组件
5. 创建 Skeleton 组件
6. 创建 EmptyState 组件
7. 创建 Toast 组件
### 阶段 3: 可访问性修复 (1-2 天)
1. 添加 aria-label 到所有图标按钮
2. 修复颜色对比度问题
3. 增强焦点状态
4. 添加键盘导航支持
### 阶段 4: 视觉优化 (2-3 天)
1. 移除所有 emoji 图标,替换为 SVG
2. 使用基础组件库重构现有组件
3. 标准化间距
4. 增强卡片阴影和悬停效果
5. 完善暗黑模式支持
### 阶段 5: 交互增强 (2-3 天)
1. 添加 Framer Motion 页面切换动画
2. 添加列表项动画 (stagger)
3. 添加按钮点击反馈
4. 实现骨架屏加载
5. 集成 Toast 通知系统
### 阶段 6: 组件重构 (2-3 天)
1. 重构 Sidebar 组件 (使用新组件库 + 动画)
2. 重构 ChatArea 组件
3. 重构 RightPanel 组件
4. 重构 SettingsLayout 组件
5. 完整暗黑模式测试
---
## 关键文件清单
### 需要修改的文件
| 文件 | 修改内容 |
|------|----------|
| `desktop/src/index.css` | 添加 CSS 变量系统 |
| `desktop/src/components/Sidebar.tsx` | aria-label, 动画, emoji 移除 |
| `desktop/src/components/ChatArea.tsx` | aria-label, emoji 移除, 空状态 |
| `desktop/src/components/RightPanel.tsx` | aria-label, 间距标准化 |
| `desktop/src/components/Settings/SettingsLayout.tsx` | aria-label, 间距标准化 |
| `desktop/src/App.tsx` | emoji 移除, 空状态组件 |
### 需要新建的文件
| 文件 | 用途 |
|------|------|
| `desktop/tailwind.config.js` | Tailwind 自定义配置 |
| `desktop/src/components/ui/Button.tsx` | 按钮组件 |
| `desktop/src/components/ui/Card.tsx` | 卡片组件 |
| `desktop/src/components/ui/Input.tsx` | 输入框组件 |
| `desktop/src/components/ui/Badge.tsx` | 标签组件 |
| `desktop/src/components/ui/Skeleton.tsx` | 骨架屏组件 |
| `desktop/src/components/ui/EmptyState.tsx` | 空状态组件 |
| `desktop/src/components/ui/Toast.tsx` | Toast 通知组件 |
| `desktop/src/lib/utils.ts` | cn() 工具函数 |
| `desktop/src/lib/animations.ts` | Framer Motion 动画预设 |
### 需要安装的依赖
```bash
cd desktop
pnpm add framer-motion clsx tailwind-merge
```
---
## 验证方法
### 1. 视觉验证
```bash
pnpm tauri:dev
```
- 检查所有页面在浅色/深色模式下的显示
- 检查所有交互元素的悬停状态
- 检查所有空状态的显示
### 2. 可访问性验证
- 使用 Chrome DevTools Lighthouse 进行可访问性审计
- 使用 Tab 键进行键盘导航测试
- 使用屏幕阅读器测试 (NVDA/JAWS)
### 3. 类型检查
```bash
cd desktop && pnpm tsc --noEmit
```
### 4. 构建验证
```bash
pnpm build
```
---
## 预期成果
1. **设计系统**: 完整的 CSS 变量和 Tailwind 配置
2. **组件库**: 7 个可复用 UI 组件 (Button, Card, Input, Badge, Skeleton, EmptyState, Toast)
3. **可访问性**: Lighthouse 可访问性分数 > 90
4. **暗黑模式**: 所有组件完整支持暗黑模式
5. **动画系统**: Framer Motion 动画预设和页面过渡
6. **视觉一致性**: 所有组件遵循统一设计规范
7. **无 Emoji**: 所有 UI 图标使用 SVG
---
*计划创建: 2026-03-15*
*预计完成: 11-17 个工作日*