# Loading 元素精简优化计划 ## 一、当前 Loading 元素汇总 | 位置 | 文件 | 当前样式 | 展示时机 | |------|------|----------|----------| | 同步横幅 | `SyncingBanner.tsx` | 顶部固定横幅 + 旋转符号 | `isSyncing && isOnline` | | 权限按钮 | `PermissionFooter.tsx:66-73` | SVG SpinnerIcon | `loading` 状态 | | 认证加载 | `App.tsx:132-146` | 纯文本 "Loading…" / "Authorizing…" | `isAuthSourceLoading` / `isAuthLoading` | | 会话加载 | `router.tsx:100-106` | 纯文本 "Loading session…" | `!session` | | 消息加载 | `HappyThread.tsx:235-258` | 纯文本 "Loading..." + 按钮文本 | `isLoadingMessages` / `isLoadingMoreMessages` | | Git 状态 | `files.tsx:313-318` | 纯文本 "Loading Git status..." / "Loading files..." | `gitLoading` / `searchResults.isLoading` | | 文件内容 | `file.tsx:231-232` | 纯文本 "Loading file..." | `diffQuery.isLoading \|\| fileQuery.isLoading` | | 登录按钮 | `LoginPrompt.tsx:77` | 按钮文本 "Signing in..." | `isLoading` | | 创建会话 | `NewSession.tsx:119-122, 216` | "Loading machines..." / "Creating..." | `isPending` | | 问卷提交 | `AskUserQuestionFooter.tsx:385` | 按钮文本 "Submitting…" | `loading` | ## 二、问题 1. **样式不统一** - 纯文本 vs SpinnerIcon vs 旋转符号 2. **SpinnerIcon 无法复用** - 定义在 PermissionFooter 内部 3. **省略号不一致** - "..." vs "…" ## 三、精简方案 **核心原则:Spinner 做基础元件,LoadingState 负责语义化加载** ### 创建唯一的 Spinner 组件(可访问性就绪) ```tsx // web/src/components/Spinner.tsx export function Spinner({ size = 'md', className, label = 'Loading', }: { size?: 'sm' | 'md' | 'lg' className?: string label?: string }) { const sizeClasses = { sm: 'h-4 w-4', md: 'h-5 w-5', lg: 'h-6 w-6' } return ( ) } ``` ### 新增 LoadingState(Spinner + 可选文案) ```tsx // web/src/components/LoadingState.tsx export function LoadingState({ label = 'Loading…', className, spinnerSize = 'md', }: { label?: string className?: string spinnerSize?: 'sm' | 'md' | 'lg' }) { return (