Files
zclaw_openfang/docs/plans/cached-greeting-cocke.md
iven 0eb30c0531 docs: reorganize documentation structure
- Create docs/README.md as documentation index
- Add WORK_SUMMARY_2026-03-16.md for today's work
- Move test reports to docs/test-reports/
- Move completed plans to docs/archive/completed-plans/
- Move research reports to docs/archive/research-reports/
- Move technical reference to docs/knowledge-base/
- Move all plans from root plans/ to docs/plans/

New structure:
docs/
├── README.md                         # Documentation index
├── DEVELOPMENT.md                    # Development guide
├── OPENVIKING_INTEGRATION.md         # OpenViking integration
├── USER_MANUAL.md                    # User manual
├── ZCLAW_AGENT_INTELLIGENCE_EVOLUTION.md
├── archive/                          # Archived documents
├── knowledge-base/                   # Technical knowledge
├── plans/                            # Execution plans
└── test-reports/                     # Test reports

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 08:21:01 +08:00

15 KiB

ZCLAW UI/UX 全面优化计划

背景

ZCLAW 是基于 OpenFang (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

: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 (新建)

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

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

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

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 - 返回按钮、菜单项
// 示例修复
<button
  onClick={onOpenSettings}
  aria-label="打开设置"
  className="..."
>
  <Settings className="w-4 h-4" />
</button>

3.2 焦点状态增强

/* 全局焦点样式 */
: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

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],
};

使用示例:

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

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 卡片阴影增强

- 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

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 动画预设

需要安装的依赖

cd desktop
pnpm add framer-motion clsx tailwind-merge

验证方法

1. 视觉验证

pnpm tauri:dev
  • 检查所有页面在浅色/深色模式下的显示
  • 检查所有交互元素的悬停状态
  • 检查所有空状态的显示

2. 可访问性验证

  • 使用 Chrome DevTools Lighthouse 进行可访问性审计
  • 使用 Tab 键进行键盘导航测试
  • 使用屏幕阅读器测试 (NVDA/JAWS)

3. 类型检查

cd desktop && pnpm tsc --noEmit

4. 构建验证

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 个工作日