Files
ai-write/docs/COMPONENT_REDESIGN_EXAMPLES.md
empty 219da2b134 feat: 添加 SVG 图标系统替代 emoji
**新增内容**:
- BaseIcon.vue: 基础图标组件
- IconLibrary.vue: 图标库组件,包含 40+ 常用图标
- ICON_SYSTEM.md: 图标系统使用指南
- COMPONENT_REDESIGN_EXAMPLES.md: 组件重设计示例文档

**图标覆盖范围** (40+ 图标):
- 写作相关: edit, file-text, document, article
- 数据素材: database, folder, chart
- 设置工具: settings, gear
- 操作: save, copy, trash, delete, close, check
- 导航: home, menu, sidebar
- 搜索筛选: search, filter
- 状态通知: warning, error, info, success
- 分析比较: compare, analysis, sparkles
- 时间历史: history, clock
- 添加移除: add, plus, minus, expand, collapse
- 其他: download, upload, refresh, loading, list

**设计原则**:
- 使用 SVG stroke 图标,统一视觉风格
- 图标继承父元素颜色 (currentColor)
- 支持 16-48px 尺寸范围
- 完全替代 emoji,提升专业性

**使用方式**:
```vue
<IconLibrary name="save" :size="20" />
```

**后续任务**:
- [ ] 逐个组件迁移,移除 61 处 emoji
- [ ] 应用统一的按钮样式
- [ ] 优化交互反馈
- [ ] 测试响应式布局

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-12 01:54:33 +08:00

425 lines
7.9 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 组件 UI 重新设计示例
本文档展示如何将现有组件中的 emoji 替换为 SVG 图标,并应用更专业的设计风格。
## 示例 1: GlobalSidebar.vue
### Before
```vue
<template>
<div class="sidebar-item" :class="{ active: isActive }">
<span class="icon"></span>
<span class="label">AI 写作</span>
</div>
</template>
<style scoped>
.sidebar-item {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3);
}
.icon {
font-size: 20px;
}
</style>
```
### After
```vue
<script setup>
import IconLibrary from './icons/IconLibrary.vue'
</script>
<template>
<div class="sidebar-item" :class="{ active: isActive }">
<IconLibrary name="edit" :size="18" class="icon" />
<span class="label">AI 写作</span>
</div>
</template>
<style scoped>
.sidebar-item {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3) var(--space-4);
border-radius: var(--radius-md);
transition: all var(--transition-fast);
}
.sidebar-item:hover {
background: var(--bg-elevated);
}
.sidebar-item.active {
background: var(--info-bg);
color: var(--accent-primary);
}
.icon {
flex-shrink: 0;
opacity: 0.9;
}
</style>
```
## 示例 2: DocumentsPanel.vue
### Before
```vue
<template>
<div class="header">
<span>📂</span>
<h2>文稿库</h2>
</div>
<button class="btn-save">
💾 保存
</button>
<button class="btn-delete">
🗑
</button>
</template>
```
### After
```vue
<script setup>
import IconLibrary from './icons/IconLibrary.vue'
</script>
<template>
<div class="header">
<IconLibrary name="folder" :size="20" />
<h2>文稿库</h2>
</div>
<button class="btn btn-primary">
<IconLibrary name="save" :size="16" />
<span>保存</span>
</button>
<button class="btn btn-icon btn-danger" aria-label="删除文档">
<IconLibrary name="trash" :size="18" />
</button>
</template>
<style scoped>
.header {
display: flex;
align-items: center;
gap: var(--space-3);
margin-bottom: var(--space-6);
}
.header h2 {
font-size: var(--text-xl);
font-weight: var(--font-semibold);
color: var(--text-primary);
}
/* 按钮样式 */
.btn {
display: inline-flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-2) var(--space-4);
border-radius: var(--radius-md);
font-size: var(--text-sm);
font-weight: var(--font-medium);
transition: all var(--transition-fast);
border: none;
cursor: pointer;
}
.btn-primary {
background: var(--accent-primary);
color: var(--text-inverse);
}
.btn-primary:hover {
background: var(--accent-primary-hover);
}
.btn-icon {
padding: var(--space-2);
}
.btn-danger {
color: var(--accent-danger);
}
.btn-danger:hover {
background: var(--danger-bg);
}
</style>
```
## 示例 3: MainContent.vue 工具栏
### Before
```vue
<template>
<div class="toolbar">
<button @click="copyContent">
📋 复制 Markdown
</button>
<button @click="clearContent">
🗑 清空
</button>
</div>
</template>
```
### After
```vue
<script setup>
import IconLibrary from './icons/IconLibrary.vue'
</script>
<template>
<div class="toolbar">
<button class="toolbar-btn" @click="copyContent">
<IconLibrary name="copy" :size="16" />
<span>复制 Markdown</span>
</button>
<button class="toolbar-btn toolbar-btn-danger" @click="clearContent">
<IconLibrary name="trash" :size="16" />
<span>清空</span>
</button>
</div>
</template>
<style scoped>
.toolbar {
display: flex;
gap: var(--space-3);
}
.toolbar-btn {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-2) var(--space-3);
background: transparent;
border: 1px solid var(--border-default);
border-radius: var(--radius-md);
color: var(--text-secondary);
font-size: var(--text-xs);
transition: all var(--transition-fast);
cursor: pointer;
}
.toolbar-btn:hover {
border-color: var(--border-strong);
color: var(--text-primary);
background: var(--bg-elevated);
}
.toolbar-btn-danger:hover {
border-color: var(--accent-danger);
color: var(--accent-danger);
background: var(--danger-bg);
}
</style>
```
## 示例 4: 状态指示器
### Before
```vue
<template>
<div class="status">
警告信息
</div>
<div class="status">
操作成功
</div>
<div class="status">
发生错误
</div>
</template>
```
### After
```vue
<script setup>
import IconLibrary from './icons/IconLibrary.vue'
</script>
<template>
<div class="status status-warning">
<IconLibrary name="warning" :size="16" />
<span>警告信息</span>
</div>
<div class="status status-success">
<IconLibrary name="check" :size="16" />
<span>操作成功</span>
</div>
<div class="status status-error">
<IconLibrary name="error" :size="16" />
<span>发生错误</span>
</div>
</template>
<style scoped>
.status {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-3) var(--space-4);
border-radius: var(--radius-md);
font-size: var(--text-sm);
}
.status-warning {
background: var(--warning-bg);
color: var(--accent-warning);
border: 1px solid rgba(251, 191, 36, 0.2);
}
.status-success {
background: var(--success-bg);
color: var(--accent-success);
border: 1px solid rgba(52, 211, 153, 0.2);
}
.status-error {
background: var(--danger-bg);
color: var(--accent-danger);
border: 1px solid rgba(248, 113, 113, 0.2);
}
</style>
```
## 示例 5: 空状态提示
### Before
```vue
<template>
<div class="empty-state">
<div class="empty-icon">📄</div>
<p>暂无文稿</p>
</div>
</template>
<style scoped>
.empty-icon {
font-size: 48px;
margin-bottom: var(--space-4);
opacity: 0.5;
}
</style>
```
### After
```vue
<script setup>
import IconLibrary from './icons/IconLibrary.vue'
</script>
<template>
<div class="empty-state">
<div class="empty-icon-wrapper">
<IconLibrary name="document" :size="48" />
</div>
<p class="empty-title">暂无文稿</p>
<p class="empty-desc">在左侧创建或选择文稿开始写作</p>
</div>
</template>
<style scoped>
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: var(--space-20) var(--space-6);
text-align: center;
}
.empty-icon-wrapper {
width: 80px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
background: var(--bg-secondary);
border: 1px dashed var(--border-default);
border-radius: var(--radius-xl);
margin-bottom: var(--space-6);
color: var(--text-muted);
}
.empty-title {
font-size: var(--text-base);
font-weight: var(--font-medium);
color: var(--text-secondary);
margin-bottom: var(--space-2);
}
.empty-desc {
font-size: var(--text-sm);
color: var(--text-muted);
}
</style>
```
## 设计原则总结
### 1. 一致的间距系统
- 使用 `gap` 属性设置图标和文字的间距
- 推荐间距:`var(--space-2)` (8px)
### 2. 语义化颜色
- 主要操作:`var(--accent-primary)`
- 成功状态:`var(--accent-success)`
- 警告状态:`var(--accent-warning)`
- 危险操作:`var(--accent-danger)`
### 3. 交互反馈
- 所有可点击元素添加 `transition`
- hover 状态使用 `var(--bg-elevated)` 背景变化
- 添加适当的 `border-radius`
### 4. 图标尺寸规范
- 按钮内图标16px
- 标题/标签图标18-20px
- 大型展示图标24-48px
### 5. 对齐方式
- 使用 `display: flex`
- `align-items: center` 确保垂直居中
- 图标添加 `flex-shrink: 0` 防止被压缩
## 迁移检查清单
在完成每个组件的迁移后,请确认:
- [ ] 移除所有 emoji 字符
- [ ] 导入 `IconLibrary` 组件
- [ ] 图标名称符合语义
- [ ] 图标尺寸合适
- [ ] 图标和文字正确对齐
- [ ] hover 状态有视觉反馈
- [ ] 颜色使用设计令牌
- [ ] 间距符合设计系统
- [ ] 添加必要的 `aria-label`
- [ ] 测试响应式布局