feat: update migration status and add new UI components

- Updated migration status documentation to reflect the migration of 26 components, with 210 pending.
- Enhanced the component status table with detailed descriptions and categorized components.
- Introduced new components: CustomTag, ErrorTag, SuccessTag, WarnTag, CopyIcon, DeleteIcon, EditIcon, and RefreshIcon.
- Updated index.ts to export the newly added components for improved accessibility.
This commit is contained in:
MyPrototypeWhat 2025-09-15 14:59:47 +08:00
parent a6e19f7757
commit 1c27481813
11 changed files with 346 additions and 50 deletions

View File

@ -4,7 +4,7 @@
```typescript
// 从 @cherrystudio/ui 导入组件
import { Spinner, DividerWithText, InfoTooltip } from '@cherrystudio/ui'
import { Spinner, DividerWithText, InfoTooltip, CustomTag } from '@cherrystudio/ui'
// 在组件中使用
function MyComponent() {
@ -13,6 +13,7 @@ function MyComponent() {
<Spinner size={24} />
<DividerWithText text="分隔文本" />
<InfoTooltip content="提示信息" />
<CustomTag color="var(--color-primary)">标签</CustomTag>
</div>
)
}
@ -20,7 +21,7 @@ function MyComponent() {
## 目录结构说明
```
```text
@packages/ui/
├── src/
│ ├── components/ # 组件主目录
@ -48,48 +49,95 @@ function MyComponent() {
## 迁移概览
- **总组件数**: 236
- **已迁移**: 18
- **已迁移**: 26
- **已重构**: 0
- **待迁移**: 218
- **待迁移**: 210
## 组件状态表
| 组件名称 | 原路径 | 分类 | 迁移状态 | 重构状态 |
|---------|--------|------|---------|---------|
| CopyButton | src/renderer/src/components/CopyButton.tsx | base | ✅ | ❌ |
| DividerWithText | src/renderer/src/components/DividerWithText.tsx | base | ✅ | ❌ |
| EmojiIcon | src/renderer/src/components/EmojiIcon.tsx | base | ✅ | ❌ |
| IndicatorLight | src/renderer/src/components/IndicatorLight.tsx | base | ✅ | ❌ |
| Spinner | src/renderer/src/components/Spinner.tsx | base | ✅ | ❌ |
| TextBadge | src/renderer/src/components/TextBadge.tsx | base | ✅ | ❌ |
| Ellipsis | src/renderer/src/components/Ellipsis/index.tsx | display | ✅ | ❌ |
| ExpandableText | src/renderer/src/components/ExpandableText.tsx | display | ✅ | ❌ |
| ThinkingEffect | src/renderer/src/components/ThinkingEffect.tsx | display | ✅ | ❌ |
| HorizontalScrollContainer | src/renderer/src/components/HorizontalScrollContainer/index.tsx | layout | ✅ | ❌ |
| Scrollbar | src/renderer/src/components/Scrollbar/index.tsx | layout | ✅ | ❌ |
| VisionIcon | src/renderer/src/components/Icons/VisionIcon.tsx | icons | ✅ | ❌ |
| WebSearchIcon | src/renderer/src/components/Icons/WebSearchIcon.tsx | icons | ✅ | ❌ |
| ToolsCallingIcon | src/renderer/src/components/Icons/ToolsCallingIcon.tsx | icons | ✅ | ❌ |
| FileIcons | src/renderer/src/components/Icons/FileIcons.tsx | icons | ✅ | ❌ |
| SvgSpinners180Ring | src/renderer/src/components/Icons/SvgSpinners180Ring.tsx | icons | ✅ | ❌ |
| ReasoningIcon | src/renderer/src/components/Icons/ReasoningIcon.tsx | icons | ✅ | ❌ |
| InfoTooltip | src/renderer/src/components/TooltipIcons/InfoTooltip.tsx | interactive | ✅ | ❌ |
| Category | Component Name | Migration Status | Refactoring Status | Description |
|----------|----------------|------------------|--------------------|-------------|
| **base** | | | | 基础组件 |
| | CopyButton | ✅ | ❌ | 复制按钮 |
| | CustomTag | ✅ | ❌ | 自定义标签 |
| | DividerWithText | ✅ | ❌ | 带文本的分隔线 |
| | EmojiIcon | ✅ | ❌ | 表情图标 |
| | ErrorTag | ✅ | ❌ | 错误标签 |
| | IndicatorLight | ✅ | ❌ | 指示灯 |
| | Spinner | ✅ | ❌ | 加载动画 |
| | SuccessTag | ✅ | ❌ | 成功标签 |
| | TextBadge | ✅ | ❌ | 文本徽标 |
| | WarnTag | ✅ | ❌ | 警告标签 |
| | CustomCollapse | ❌ | ❌ | 自定义折叠面板 |
| **display** | | | | 显示组件 |
| | Ellipsis | ✅ | ❌ | 文本省略 |
| | ExpandableText | ✅ | ❌ | 可展开文本 |
| | ThinkingEffect | ✅ | ❌ | 思考效果动画 |
| | CodeViewer | ❌ | ❌ | 代码查看器 (外部依赖) |
| | OGCard | ❌ | ❌ | OG 卡片 |
| | MarkdownShadowDOMRenderer | ❌ | ❌ | Markdown 渲染器 |
| | Preview/* | ❌ | ❌ | 预览组件 |
| **layout** | | | | 布局组件 |
| | HorizontalScrollContainer | ✅ | ❌ | 水平滚动容器 |
| | Scrollbar | ✅ | ❌ | 滚动条 |
| | Layout/* | ❌ | ❌ | 布局组件 |
| | Tab/* | ❌ | ❌ | 标签页 (Redux 依赖) |
| | TopView | ❌ | ❌ | 顶部视图 (window.api 依赖) |
| **icons** | | | | 图标组件 |
| | CopyIcon | ✅ | ❌ | 复制图标 |
| | DeleteIcon | ✅ | ❌ | 删除图标 |
| | EditIcon | ✅ | ❌ | 编辑图标 |
| | FileIcons | ✅ | ❌ | 文件图标 (包含 FileSvgIcon、FilePngIcon) |
| | ReasoningIcon | ✅ | ❌ | 推理图标 |
| | RefreshIcon | ✅ | ❌ | 刷新图标 |
| | SvgSpinners180Ring | ✅ | ❌ | 旋转加载图标 |
| | ToolsCallingIcon | ✅ | ❌ | 工具调用图标 |
| | VisionIcon | ✅ | ❌ | 视觉图标 |
| | WebSearchIcon | ✅ | ❌ | 网页搜索图标 |
| | Other icons | ❌ | ❌ | 其他图标文件 |
| **interactive** | | | | 交互组件 |
| | InfoTooltip | ✅ | ❌ | 信息提示 |
| | HelpTooltip | ❌ | ❌ | 帮助提示 |
| | WarnTooltip | ❌ | ❌ | 警告提示 |
| | DraggableList | ❌ | ❌ | 可拖拽列表 |
| | EditableNumber | ❌ | ❌ | 可编辑数字 |
| | EmojiPicker | ❌ | ❌ | 表情选择器 |
| | Selector | ❌ | ❌ | 选择器 |
| | ModelSelector | ❌ | ❌ | 模型选择器 (Redux 依赖) |
| | LanguageSelect | ❌ | ❌ | 语言选择 |
| | TranslateButton | ❌ | ❌ | 翻译按钮 (window.api 依赖) |
| **composite** | | | | 复合组件 |
| | - | - | - | 暂无复合组件 |
| **未分类** | | | | 需要分类的组件 |
| | Popups/* (16+ 文件) | ❌ | ❌ | 弹窗组件 (业务耦合) |
| | RichEditor/* (30+ 文件) | ❌ | ❌ | 富文本编辑器 |
| | CodeEditor/* | ❌ | ❌ | 代码编辑器 |
| | MarkdownEditor/* | ❌ | ❌ | Markdown 编辑器 |
| | MinApp/* | ❌ | ❌ | 迷你应用 (Redux 依赖) |
| | Avatar/* | ❌ | ❌ | 头像组件 |
| | ActionTools/* | ❌ | ❌ | 操作工具 |
| | CodeBlockView/* | ❌ | ❌ | 代码块视图 (window.api 依赖) |
| | ContextMenu | ❌ | ❌ | 右键菜单 (Electron API) |
| | WindowControls | ❌ | ❌ | 窗口控制 (Electron API) |
| | ErrorBoundary | ❌ | ❌ | 错误边界 (window.api 依赖) |
## 迁移步骤
### 第一阶段:复制迁移(当前阶段)
- 将组件原样复制到 @packages/ui
- 保留原有依赖antd、styled-components 等)
- 在文件顶部添加原路径注释
### 第二阶段:重构优化
- 移除 antd 依赖,替换为 HeroUI
- 移除 styled-components替换为 Tailwind CSS
- 优化组件 API 和类型定义
## 注意事项
1. **不迁移**包含以下依赖的组件**(解耦后可迁移)**
1. **不迁移**包含以下依赖的组件(解耦后可迁移)
- window.api 调用
- ReduxuseSelector、useDispatch 等)
- 其他外部数据源

View File

@ -20,7 +20,7 @@ function MyComponent() {
## Directory Structure
```
```text
@packages/ui/
├── src/
│ ├── components/ # Main components directory
@ -48,32 +48,77 @@ When submitting PRs, please place components in the correct directory based on t
## Migration Overview
- **Total Components**: 236
- **Migrated**: 18
- **Migrated**: 26
- **Refactored**: 0
- **Pending Migration**: 218
- **Pending Migration**: 210
## Component Status Table
| Component Name | Original Path | Category | Migration Status | Refactoring Status |
|---------------|---------------|----------|------------------|-------------------|
| CopyButton | src/renderer/src/components/CopyButton.tsx | base | ✅ | ❌ |
| DividerWithText | src/renderer/src/components/DividerWithText.tsx | base | ✅ | ❌ |
| EmojiIcon | src/renderer/src/components/EmojiIcon.tsx | base | ✅ | ❌ |
| IndicatorLight | src/renderer/src/components/IndicatorLight.tsx | base | ✅ | ❌ |
| Spinner | src/renderer/src/components/Spinner.tsx | base | ✅ | ❌ |
| TextBadge | src/renderer/src/components/TextBadge.tsx | base | ✅ | ❌ |
| Ellipsis | src/renderer/src/components/Ellipsis/index.tsx | display | ✅ | ❌ |
| ExpandableText | src/renderer/src/components/ExpandableText.tsx | display | ✅ | ❌ |
| ThinkingEffect | src/renderer/src/components/ThinkingEffect.tsx | display | ✅ | ❌ |
| HorizontalScrollContainer | src/renderer/src/components/HorizontalScrollContainer/index.tsx | layout | ✅ | ❌ |
| Scrollbar | src/renderer/src/components/Scrollbar/index.tsx | layout | ✅ | ❌ |
| VisionIcon | src/renderer/src/components/Icons/VisionIcon.tsx | icons | ✅ | ❌ |
| WebSearchIcon | src/renderer/src/components/Icons/WebSearchIcon.tsx | icons | ✅ | ❌ |
| ToolsCallingIcon | src/renderer/src/components/Icons/ToolsCallingIcon.tsx | icons | ✅ | ❌ |
| FileIcons | src/renderer/src/components/Icons/FileIcons.tsx | icons | ✅ | ❌ |
| SvgSpinners180Ring | src/renderer/src/components/Icons/SvgSpinners180Ring.tsx | icons | ✅ | ❌ |
| ReasoningIcon | src/renderer/src/components/Icons/ReasoningIcon.tsx | icons | ✅ | ❌ |
| InfoTooltip | src/renderer/src/components/TooltipIcons/InfoTooltip.tsx | interactive | ✅ | ❌ |
| Category | Component Name | Migration Status | Refactoring Status | Description |
|----------|----------------|------------------|--------------------|-------------|
| **base** | | | | Base components |
| | CopyButton | ✅ | ❌ | Copy button |
| | CustomTag | ✅ | ❌ | Custom tag |
| | DividerWithText | ✅ | ❌ | Divider with text |
| | EmojiIcon | ✅ | ❌ | Emoji icon |
| | ErrorTag | ✅ | ❌ | Error tag |
| | IndicatorLight | ✅ | ❌ | Indicator light |
| | Spinner | ✅ | ❌ | Loading spinner |
| | SuccessTag | ✅ | ❌ | Success tag |
| | TextBadge | ✅ | ❌ | Text badge |
| | WarnTag | ✅ | ❌ | Warning tag |
| | CustomCollapse | ❌ | ❌ | Custom collapse panel |
| **display** | | | | Display components |
| | Ellipsis | ✅ | ❌ | Text ellipsis |
| | ExpandableText | ✅ | ❌ | Expandable text |
| | ThinkingEffect | ✅ | ❌ | Thinking effect animation |
| | CodeViewer | ❌ | ❌ | Code viewer (external deps) |
| | OGCard | ❌ | ❌ | OG card |
| | MarkdownShadowDOMRenderer | ❌ | ❌ | Markdown renderer |
| | Preview/* | ❌ | ❌ | Preview components |
| **layout** | | | | Layout components |
| | HorizontalScrollContainer | ✅ | ❌ | Horizontal scroll container |
| | Scrollbar | ✅ | ❌ | Scrollbar |
| | Layout/* | ❌ | ❌ | Layout components |
| | Tab/* | ❌ | ❌ | Tab (Redux dependency) |
| | TopView | ❌ | ❌ | Top view (window.api dependency) |
| **icons** | | | | Icon components |
| | CopyIcon | ✅ | ❌ | Copy icon |
| | DeleteIcon | ✅ | ❌ | Delete icon |
| | EditIcon | ✅ | ❌ | Edit icon |
| | FileIcons | ✅ | ❌ | File icons (includes FileSvgIcon, FilePngIcon) |
| | ReasoningIcon | ✅ | ❌ | Reasoning icon |
| | RefreshIcon | ✅ | ❌ | Refresh icon |
| | SvgSpinners180Ring | ✅ | ❌ | Spinners icon |
| | ToolsCallingIcon | ✅ | ❌ | Tools calling icon |
| | VisionIcon | ✅ | ❌ | Vision icon |
| | WebSearchIcon | ✅ | ❌ | Web search icon |
| | Other icons | ❌ | ❌ | Other icon files |
| **interactive** | | | | Interactive components |
| | InfoTooltip | ✅ | ❌ | Info tooltip |
| | HelpTooltip | ❌ | ❌ | Help tooltip |
| | WarnTooltip | ❌ | ❌ | Warning tooltip |
| | DraggableList | ❌ | ❌ | Draggable list |
| | EditableNumber | ❌ | ❌ | Editable number |
| | EmojiPicker | ❌ | ❌ | Emoji picker |
| | Selector | ❌ | ❌ | Selector |
| | ModelSelector | ❌ | ❌ | Model selector (Redux dependency) |
| | LanguageSelect | ❌ | ❌ | Language select |
| | TranslateButton | ❌ | ❌ | Translate button (window.api dependency) |
| **composite** | | | | Composite components |
| | - | - | - | No composite components yet |
| **Uncategorized** | | | | Components needing categorization |
| | Popups/* (16+ files) | ❌ | ❌ | Popup components (business coupled) |
| | RichEditor/* (30+ files) | ❌ | ❌ | Rich text editor |
| | CodeEditor/* | ❌ | ❌ | Code editor |
| | MarkdownEditor/* | ❌ | ❌ | Markdown editor |
| | MinApp/* | ❌ | ❌ | Mini app (Redux dependency) |
| | Avatar/* | ❌ | ❌ | Avatar components |
| | ActionTools/* | ❌ | ❌ | Action tools |
| | CodeBlockView/* | ❌ | ❌ | Code block view (window.api dependency) |
| | ContextMenu | ❌ | ❌ | Context menu (Electron API) |
| | WindowControls | ❌ | ❌ | Window controls (Electron API) |
| | ErrorBoundary | ❌ | ❌ | Error boundary (window.api dependency) |
## Migration Steps
@ -91,7 +136,7 @@ When submitting PRs, please place components in the correct directory based on t
## Notes
1. **Do NOT migrate** components with these dependencies:
1. **Do NOT migrate** components with these dependencies (can be migrated after decoupling):
- window.api calls
- Redux (useSelector, useDispatch, etc.)
- Other external data sources

View File

@ -0,0 +1,118 @@
// Original path: src/renderer/src/components/Tags/CustomTag.tsx
import { CloseOutlined } from '@ant-design/icons'
import { Tooltip } from 'antd'
import { CSSProperties, FC, memo, MouseEventHandler, useMemo } from 'react'
import styled from 'styled-components'
export interface CustomTagProps {
icon?: React.ReactNode
children?: React.ReactNode | string
color: string
size?: number
style?: CSSProperties
tooltip?: string
closable?: boolean
onClose?: () => void
onClick?: MouseEventHandler<HTMLDivElement>
disabled?: boolean
inactive?: boolean
}
const CustomTag: FC<CustomTagProps> = ({
children,
icon,
color,
size = 12,
style,
tooltip,
closable = false,
onClose,
onClick,
disabled,
inactive
}) => {
const actualColor = inactive ? '#aaaaaa' : color
const tagContent = useMemo(
() => (
<Tag
$color={actualColor}
$size={size}
$closable={closable}
$clickable={!disabled && !!onClick}
onClick={disabled ? undefined : onClick}
style={{
...(disabled && { cursor: 'not-allowed' }),
...style
}}>
{icon && icon} {children}
{closable && (
<CloseIcon
$size={size}
$color={actualColor}
onClick={(e) => {
e.stopPropagation()
onClose?.()
}}
/>
)}
</Tag>
),
[actualColor, children, closable, disabled, icon, onClick, onClose, size, style]
)
return tooltip ? (
<Tooltip title={tooltip} placement="top" mouseEnterDelay={0.3}>
{tagContent}
</Tooltip>
) : (
tagContent
)
}
export default memo(CustomTag)
const Tag = styled.div<{ $color: string; $size: number; $closable: boolean; $clickable: boolean }>`
display: inline-flex;
align-items: center;
gap: 4px;
padding: ${({ $size }) => $size / 3}px ${({ $size }) => $size * 0.8}px;
padding-right: ${({ $closable, $size }) => ($closable ? $size * 1.8 : $size * 0.8)}px;
border-radius: 99px;
color: ${({ $color }) => $color};
background-color: ${({ $color }) => $color + '20'};
font-size: ${({ $size }) => $size}px;
line-height: 1;
white-space: nowrap;
position: relative;
cursor: ${({ $clickable }) => ($clickable ? 'pointer' : 'auto')};
.iconfont {
font-size: ${({ $size }) => $size}px;
color: ${({ $color }) => $color};
}
transition: opacity 0.2s ease;
&:hover {
opacity: ${({ $clickable }) => ($clickable ? 0.8 : 1)};
}
`
const CloseIcon = styled(CloseOutlined)<{ $size: number; $color: string }>`
cursor: pointer;
font-size: ${({ $size }) => $size * 0.8}px;
color: ${({ $color }) => $color};
display: flex;
align-items: center;
justify-content: center;
position: absolute;
right: ${({ $size }) => $size * 0.2}px;
top: ${({ $size }) => $size * 0.2}px;
bottom: ${({ $size }) => $size * 0.2}px;
border-radius: 99px;
transition: all 0.2s ease;
aspect-ratio: 1;
line-height: 1;
&:hover {
background-color: #da8a8a;
color: #ffffff;
}
`

View File

@ -0,0 +1,17 @@
// Original path: src/renderer/src/components/Tags/ErrorTag.tsx
import { CircleXIcon } from 'lucide-react'
import CustomTag from '../CustomTag'
type Props = {
iconSize?: number
message: string
}
export const ErrorTag = ({ iconSize: size = 14, message }: Props) => {
return (
<CustomTag icon={<CircleXIcon size={size} color="var(--color-status-error)" />} color="var(--color-status-error)">
{message}
</CustomTag>
)
}

View File

@ -0,0 +1,17 @@
// Original path: src/renderer/src/components/Tags/SuccessTag.tsx
import { CheckIcon } from 'lucide-react'
import CustomTag from '../CustomTag'
type Props = {
iconSize?: number
message: string
}
export const SuccessTag = ({ iconSize: size = 14, message }: Props) => {
return (
<CustomTag icon={<CheckIcon size={size} color="var(--color-status-success)" />} color="var(--color-status-success)">
{message}
</CustomTag>
)
}

View File

@ -0,0 +1,19 @@
// Original path: src/renderer/src/components/Tags/WarnTag.tsx
import { AlertTriangleIcon } from 'lucide-react'
import CustomTag from '../CustomTag'
type Props = {
iconSize?: number
message: string
}
export const WarnTag = ({ iconSize: size = 14, message }: Props) => {
return (
<CustomTag
icon={<AlertTriangleIcon size={size} color="var(--color-status-warning)" />}
color="var(--color-status-warning)">
{message}
</CustomTag>
)
}

View File

@ -0,0 +1,6 @@
// Original path: src/renderer/src/components/Icons/CopyIcon.tsx
import { Copy } from 'lucide-react'
const CopyIcon = (props: React.ComponentProps<typeof Copy>) => <Copy size="1rem" {...props} />
export default CopyIcon

View File

@ -0,0 +1,6 @@
// Original path: src/renderer/src/components/Icons/DeleteIcon.tsx
import { Trash } from 'lucide-react'
const DeleteIcon = (props: React.ComponentProps<typeof Trash>) => <Trash size="1rem" {...props} />
export default DeleteIcon

View File

@ -0,0 +1,6 @@
// Original path: src/renderer/src/components/Icons/EditIcon.tsx
import { Pencil } from 'lucide-react'
const EditIcon = (props: React.ComponentProps<typeof Pencil>) => <Pencil size="1rem" {...props} />
export default EditIcon

View File

@ -0,0 +1,6 @@
// Original path: src/renderer/src/components/Icons/RefreshIcon.tsx
import { RefreshCw } from 'lucide-react'
const RefreshIcon = (props: React.ComponentProps<typeof RefreshCw>) => <RefreshCw size="1rem" {...props} />
export default RefreshIcon

View File

@ -1,10 +1,14 @@
// Base Components
export { default as CopyButton } from './base/CopyButton'
export { default as CustomTag } from './base/CustomTag'
export { default as DividerWithText } from './base/DividerWithText'
export { default as EmojiIcon } from './base/EmojiIcon'
export { ErrorTag } from './base/ErrorTag'
export { default as IndicatorLight } from './base/IndicatorLight'
export { default as Spinner } from './base/Spinner'
export { SuccessTag } from './base/SuccessTag'
export { default as TextBadge } from './base/TextBadge'
export { WarnTag } from './base/WarnTag'
// Display Components
export { default as Ellipsis } from './display/Ellipsis'
@ -16,8 +20,12 @@ export { default as HorizontalScrollContainer } from './layout/HorizontalScrollC
export { default as Scrollbar } from './layout/Scrollbar'
// Icon Components
export { default as CopyIcon } from './icons/CopyIcon'
export { default as DeleteIcon } from './icons/DeleteIcon'
export { default as EditIcon } from './icons/EditIcon'
export { FilePngIcon, FileSvgIcon } from './icons/FileIcons'
export { default as ReasoningIcon } from './icons/ReasoningIcon'
export { default as RefreshIcon } from './icons/RefreshIcon'
export { default as SvgSpinners180Ring } from './icons/SvgSpinners180Ring'
export { default as ToolsCallingIcon } from './icons/ToolsCallingIcon'
export { default as VisionIcon } from './icons/VisionIcon'