diff --git a/packages/ui/MIGRATION_STATUS.md b/packages/ui/MIGRATION_STATUS.md
new file mode 100644
index 0000000000..52ee2b6fea
--- /dev/null
+++ b/packages/ui/MIGRATION_STATUS.md
@@ -0,0 +1,104 @@
+# UI 组件库迁移状态
+
+## 使用示例
+
+```typescript
+// 从 @cherrystudio/ui 导入组件
+import { Spinner, DividerWithText, InfoTooltip } from '@cherrystudio/ui'
+
+// 在组件中使用
+function MyComponent() {
+ return (
+
+ )
+}
+```
+
+## 目录结构说明
+
+```
+@packages/ui/
+├── src/
+│ ├── components/ # 组件主目录
+│ │ ├── base/ # 基础组件(按钮、输入框、标签等)
+│ │ ├── display/ # 显示组件(卡片、列表、表格等)
+│ │ ├── layout/ # 布局组件(容器、网格、间距等)
+│ │ ├── icons/ # 图标组件
+│ │ ├── interactive/ # 交互组件(弹窗、提示、下拉等)
+│ │ └── composite/ # 复合组件(多个基础组件组合而成)
+│ ├── hooks/ # 自定义 React Hooks
+│ └── types/ # TypeScript 类型定义
+```
+
+### 组件分类指南
+
+提交 PR 时,请根据组件功能将其放入正确的目录:
+
+- **base**: 最基础的 UI 元素,如按钮、输入框、开关、标签等
+- **display**: 用于展示内容的组件,如卡片、列表、表格、标签页等
+- **layout**: 用于页面布局的组件,如容器、网格系统、分隔符等
+- **icons**: 所有图标相关的组件
+- **interactive**: 需要用户交互的组件,如模态框、抽屉、提示框、下拉菜单等
+- **composite**: 复合组件,由多个基础组件组合而成
+
+## 迁移概览
+
+- **总组件数**: 236
+- **已迁移**: 18
+- **已重构**: 0
+- **待迁移**: 218
+
+## 组件状态表
+
+| 组件名称 | 原路径 | 分类 | 迁移状态 | 重构状态 |
+|---------|--------|------|---------|---------|
+| 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 | ✅ | ❌ |
+
+## 迁移步骤
+
+### 第一阶段:复制迁移(当前阶段)
+- 将组件原样复制到 @packages/ui
+- 保留原有依赖(antd、styled-components 等)
+- 在文件顶部添加原路径注释
+
+### 第二阶段:重构优化
+- 移除 antd 依赖,替换为 HeroUI
+- 移除 styled-components,替换为 Tailwind CSS
+- 优化组件 API 和类型定义
+
+## 注意事项
+
+1. **不迁移**包含以下依赖的组件**(解耦后可迁移)**:
+ - window.api 调用
+ - Redux(useSelector、useDispatch 等)
+ - 其他外部数据源
+
+2. **可迁移**但需要后续解耦的组件:
+ - 使用 i18n 的组件(将 i18n 改为 props 传入)
+ - 使用 antd 的组件(后续替换为 HeroUI)
+
+3. **提交规范**:
+ - 每次 PR 专注于一个类别的组件
+ - 确保所有迁移的组件都有导出
+ - 更新此文档的迁移状态
\ No newline at end of file
diff --git a/packages/ui/MIGRATION_STATUS_EN.md b/packages/ui/MIGRATION_STATUS_EN.md
new file mode 100644
index 0000000000..fd5879e2ff
--- /dev/null
+++ b/packages/ui/MIGRATION_STATUS_EN.md
@@ -0,0 +1,106 @@
+# UI Component Library Migration Status
+
+## Usage Example
+
+```typescript
+// Import components from @cherrystudio/ui
+import { Spinner, DividerWithText, InfoTooltip } from '@cherrystudio/ui'
+
+// Use in components
+function MyComponent() {
+ return (
+
+ )
+}
+```
+
+## Directory Structure
+
+```
+@packages/ui/
+├── src/
+│ ├── components/ # Main components directory
+│ │ ├── base/ # Basic components (buttons, inputs, labels, etc.)
+│ │ ├── display/ # Display components (cards, lists, tables, etc.)
+│ │ ├── layout/ # Layout components (containers, grids, spacing, etc.)
+│ │ ├── icons/ # Icon components
+│ │ ├── interactive/ # Interactive components (modals, tooltips, dropdowns, etc.)
+│ │ └── composite/ # Composite components (made from multiple base components)
+│ ├── hooks/ # Custom React Hooks
+│ └── types/ # TypeScript type definitions
+```
+
+### Component Classification Guide
+
+When submitting PRs, please place components in the correct directory based on their function:
+
+- **base**: Most basic UI elements like buttons, inputs, switches, labels, etc.
+- **display**: Components for displaying content like cards, lists, tables, tabs, etc.
+- **layout**: Components for page layout like containers, grid systems, dividers, etc.
+- **icons**: All icon-related components
+- **interactive**: Components requiring user interaction like modals, drawers, tooltips, dropdowns, etc.
+- **composite**: Composite components made from multiple base components
+
+## Migration Overview
+
+- **Total Components**: 236
+- **Migrated**: 18
+- **Refactored**: 0
+- **Pending Migration**: 218
+
+## 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 | ✅ | ❌ |
+
+## Migration Steps
+
+### Phase 1: Copy Migration (Current Phase)
+
+- Copy components as-is to @packages/ui
+- Retain original dependencies (antd, styled-components, etc.)
+- Add original path comment at file top
+
+### Phase 2: Refactor and Optimize
+
+- Remove antd dependencies, replace with HeroUI
+- Remove styled-components, replace with Tailwind CSS
+- Optimize component APIs and type definitions
+
+## Notes
+
+1. **Do NOT migrate** components with these dependencies:
+ - window.api calls
+ - Redux (useSelector, useDispatch, etc.)
+ - Other external data sources
+
+2. **Can migrate** but need decoupling later:
+ - Components using i18n (change i18n to props)
+ - Components using antd (replace with HeroUI later)
+
+3. **Submission Guidelines**:
+ - Each PR should focus on one category of components
+ - Ensure all migrated components are exported
+ - Update migration status in this document
\ No newline at end of file
diff --git a/packages/ui/src/components/base/CopyButton/index.tsx b/packages/ui/src/components/base/CopyButton/index.tsx
new file mode 100644
index 0000000000..51e47cfc28
--- /dev/null
+++ b/packages/ui/src/components/base/CopyButton/index.tsx
@@ -0,0 +1,69 @@
+// Original path: src/renderer/src/components/CopyButton.tsx
+import { Tooltip } from 'antd'
+import { Copy } from 'lucide-react'
+import { FC } from 'react'
+import styled from 'styled-components'
+
+interface CopyButtonProps {
+ tooltip?: string
+ label?: string
+ color?: string
+ hoverColor?: string
+ size?: number
+}
+
+interface ButtonContainerProps {
+ $color: string
+ $hoverColor: string
+}
+
+const CopyButton: FC = ({
+ tooltip,
+ label,
+ color = 'var(--color-text-2)',
+ hoverColor = 'var(--color-primary)',
+ size = 14,
+ ...props
+}) => {
+ const button = (
+
+
+ {label && {label}}
+
+ )
+
+ if (tooltip) {
+ return {button}
+ }
+
+ return button
+}
+
+const ButtonContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 4px;
+ cursor: pointer;
+ color: ${(props) => props.$color};
+ transition: color 0.2s;
+
+ .copy-icon {
+ color: ${(props) => props.$color};
+ transition: color 0.2s;
+ }
+
+ &:hover {
+ color: ${(props) => props.$hoverColor};
+
+ .copy-icon {
+ color: ${(props) => props.$hoverColor};
+ }
+ }
+`
+
+const RightText = styled.span<{ size: number }>`
+ font-size: ${(props) => props.size}px;
+`
+
+export default CopyButton
diff --git a/packages/ui/src/components/base/DividerWithText.tsx b/packages/ui/src/components/base/DividerWithText/index.tsx
similarity index 100%
rename from packages/ui/src/components/base/DividerWithText.tsx
rename to packages/ui/src/components/base/DividerWithText/index.tsx
diff --git a/packages/ui/src/components/base/EmojiIcon/index.tsx b/packages/ui/src/components/base/EmojiIcon/index.tsx
new file mode 100644
index 0000000000..f20860bec3
--- /dev/null
+++ b/packages/ui/src/components/base/EmojiIcon/index.tsx
@@ -0,0 +1,49 @@
+// Original path: src/renderer/src/components/EmojiIcon.tsx
+import { FC } from 'react'
+import styled from 'styled-components'
+
+interface EmojiIconProps {
+ emoji: string
+ className?: string
+ size?: number
+ fontSize?: number
+}
+
+const EmojiIcon: FC = ({ emoji, className, size = 26, fontSize = 15 }) => {
+ return (
+
+ {emoji || '⭐️'}
+ {emoji}
+
+ )
+}
+
+const Container = styled.div<{ $size: number; $fontSize: number }>`
+ width: ${({ $size }) => $size}px;
+ height: ${({ $size }) => $size}px;
+ border-radius: ${({ $size }) => $size / 2}px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ font-size: ${({ $fontSize }) => $fontSize}px;
+ position: relative;
+ overflow: hidden;
+ margin-right: 3px;
+`
+
+const EmojiBackground = styled.div`
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ inset: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 200%;
+ transform: scale(1.5);
+ filter: blur(5px);
+ opacity: 0.4;
+`
+
+export default EmojiIcon
diff --git a/packages/ui/src/components/base/IndicatorLight.tsx b/packages/ui/src/components/base/IndicatorLight/index.tsx
similarity index 100%
rename from packages/ui/src/components/base/IndicatorLight.tsx
rename to packages/ui/src/components/base/IndicatorLight/index.tsx
diff --git a/packages/ui/src/components/base/Spinner.tsx b/packages/ui/src/components/base/Spinner/index.tsx
similarity index 100%
rename from packages/ui/src/components/base/Spinner.tsx
rename to packages/ui/src/components/base/Spinner/index.tsx
diff --git a/packages/ui/src/components/base/TextBadge.tsx b/packages/ui/src/components/base/TextBadge/index.tsx
similarity index 100%
rename from packages/ui/src/components/base/TextBadge.tsx
rename to packages/ui/src/components/base/TextBadge/index.tsx
diff --git a/packages/ui/src/components/display/Ellipsis.tsx b/packages/ui/src/components/display/Ellipsis/index.tsx
similarity index 100%
rename from packages/ui/src/components/display/Ellipsis.tsx
rename to packages/ui/src/components/display/Ellipsis/index.tsx
diff --git a/packages/ui/src/components/display/ExpandableText.tsx b/packages/ui/src/components/display/ExpandableText/index.tsx
similarity index 100%
rename from packages/ui/src/components/display/ExpandableText.tsx
rename to packages/ui/src/components/display/ExpandableText/index.tsx
diff --git a/packages/ui/src/components/display/ThinkingEffect/defaultVariants.ts b/packages/ui/src/components/display/ThinkingEffect/defaultVariants.ts
new file mode 100644
index 0000000000..73afaa6342
--- /dev/null
+++ b/packages/ui/src/components/display/ThinkingEffect/defaultVariants.ts
@@ -0,0 +1,38 @@
+import type { Variants } from 'motion/react'
+export const lightbulbVariants: Variants = {
+ active: {
+ opacity: [1, 0.2, 1],
+ transition: {
+ duration: 1.2,
+ ease: 'easeInOut',
+ times: [0, 0.5, 1],
+ repeat: Infinity
+ }
+ },
+ idle: {
+ opacity: 1,
+ transition: {
+ duration: 0.3,
+ ease: 'easeInOut'
+ }
+ }
+}
+
+export const lightbulbSoftVariants: Variants = {
+ active: {
+ opacity: [1, 0.5, 1],
+ transition: {
+ duration: 2,
+ ease: 'easeInOut',
+ times: [0, 0.5, 1],
+ repeat: Infinity
+ }
+ },
+ idle: {
+ opacity: 1,
+ transition: {
+ duration: 0.3,
+ ease: 'easeInOut'
+ }
+ }
+}
diff --git a/packages/ui/src/components/display/ThinkingEffect/index.tsx b/packages/ui/src/components/display/ThinkingEffect/index.tsx
new file mode 100644
index 0000000000..fca5e1bd8a
--- /dev/null
+++ b/packages/ui/src/components/display/ThinkingEffect/index.tsx
@@ -0,0 +1,190 @@
+// Original path: src/renderer/src/components/ThinkingEffect.tsx
+import { isEqual } from 'lodash'
+import { ChevronRight, Lightbulb } from 'lucide-react'
+import { motion } from 'motion/react'
+import React, { useEffect, useMemo, useState } from 'react'
+import styled from 'styled-components'
+
+import { lightbulbVariants } from './defaultVariants'
+
+interface Props {
+ isThinking: boolean
+ thinkingTimeText: React.ReactNode
+ content: string
+ expanded: boolean
+}
+
+const ThinkingEffect: React.FC = ({ isThinking, thinkingTimeText, content, expanded }) => {
+ const [messages, setMessages] = useState([])
+
+ useEffect(() => {
+ const allLines = (content || '').split('\n')
+ const newMessages = isThinking ? allLines.slice(0, -1) : allLines
+ const validMessages = newMessages.filter((line) => line.trim() !== '')
+
+ if (!isEqual(messages, validMessages)) {
+ setMessages(validMessages)
+ }
+ }, [content, isThinking, messages])
+
+ const showThinking = useMemo(() => {
+ return isThinking && !expanded
+ }, [expanded, isThinking])
+
+ const LINE_HEIGHT = 14
+
+ const containerHeight = useMemo(() => {
+ if (!showThinking || messages.length < 1) return 38
+ return Math.min(75, Math.max(messages.length + 1, 2) * LINE_HEIGHT + 25)
+ }, [showThinking, messages.length])
+
+ return (
+
+
+
+
+
+
+
+
+ {thinkingTimeText}
+
+ {showThinking && (
+
+
+ {messages.map((message, index) => {
+ if (index < messages.length - 5) return null
+
+ return {message}
+ })}
+
+
+ )}
+
+
+
+
+
+ )
+}
+
+const ThinkingContainer = styled.div`
+ width: 100%;
+ border-radius: 10px;
+ overflow: hidden;
+ position: relative;
+ display: flex;
+ align-items: center;
+ border: 0.5px solid var(--color-border);
+ transition: height, border-radius, 150ms;
+ pointer-events: none;
+ user-select: none;
+ &.expanded {
+ border-radius: 10px 10px 0 0;
+ }
+`
+
+const Title = styled.div`
+ position: absolute;
+ inset: 0 0 auto 0;
+ font-size: 14px;
+ line-height: 14px;
+ font-weight: 500;
+ padding: 10px 0;
+ z-index: 99;
+ transition: padding-top 150ms;
+ &.showThinking {
+ padding-top: 12px;
+ }
+`
+
+const LoadingContainer = styled.div`
+ width: 50px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ flex-shrink: 0;
+ position: relative;
+ padding-left: 5px;
+ transition: width 150ms;
+ > div {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+`
+
+const TextContainer = styled.div`
+ flex: 1;
+ height: 100%;
+ padding: 5px 0;
+ overflow: hidden;
+ position: relative;
+`
+
+const Content = styled.div`
+ width: 100%;
+ height: 100%;
+ mask: linear-gradient(
+ to bottom,
+ rgb(0 0 0 / 0%) 0%,
+ rgb(0 0 0 / 0%) 35%,
+ rgb(0 0 0 / 25%) 40%,
+ rgb(0 0 0 / 100%) 90%,
+ rgb(0 0 0 / 100%) 100%
+ );
+ position: relative;
+`
+
+const Messages = styled(motion.div)`
+ width: 100%;
+ position: absolute;
+ top: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+`
+
+const Message = styled.div`
+ width: 100%;
+ line-height: 14px;
+ font-size: 11px;
+ color: var(--color-text-2);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+`
+
+const ArrowContainer = styled.div`
+ width: 40px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ flex-shrink: 0;
+ position: relative;
+ color: var(--color-border);
+ transition: transform 150ms;
+ &.expanded {
+ transform: rotate(90deg);
+ }
+`
+
+export default ThinkingEffect
diff --git a/packages/ui/src/components/icons/FileIcons/index.tsx b/packages/ui/src/components/icons/FileIcons/index.tsx
new file mode 100644
index 0000000000..dd5885e172
--- /dev/null
+++ b/packages/ui/src/components/icons/FileIcons/index.tsx
@@ -0,0 +1,71 @@
+// Original path: src/renderer/src/components/Icons/FileIcons.tsx
+import { CSSProperties, SVGProps } from 'react'
+
+interface BaseFileIconProps extends SVGProps {
+ size?: string | number
+ text?: string
+}
+
+const textStyle: CSSProperties = {
+ fontStyle: 'italic',
+ fontSize: '7.70985px',
+ lineHeight: 0.8,
+ fontFamily: "'Times New Roman'",
+ textAlign: 'center',
+ writingMode: 'horizontal-tb',
+ direction: 'ltr',
+ textAnchor: 'middle',
+ fill: 'none',
+ stroke: '#000000',
+ strokeWidth: '0.289119',
+ strokeLinejoin: 'round',
+ strokeDasharray: 'none'
+}
+
+const tspanStyle: CSSProperties = {
+ fontStyle: 'normal',
+ fontVariant: 'normal',
+ fontWeight: 'normal',
+ fontStretch: 'condensed',
+ fontSize: '7.70985px',
+ lineHeight: 0.8,
+ fontFamily: 'Arial',
+ fill: '#000000',
+ fillOpacity: 1,
+ strokeWidth: '0.289119',
+ strokeDasharray: 'none'
+}
+
+const BaseFileIcon = ({ size = '1.1em', text = 'SVG', ...props }: BaseFileIconProps) => (
+
+)
+
+export const FileSvgIcon = (props: Omit) =>
+export const FilePngIcon = (props: Omit) =>
diff --git a/packages/ui/src/components/icons/ReasoningIcon/index.tsx b/packages/ui/src/components/icons/ReasoningIcon/index.tsx
new file mode 100644
index 0000000000..5bbd296f2f
--- /dev/null
+++ b/packages/ui/src/components/icons/ReasoningIcon/index.tsx
@@ -0,0 +1,31 @@
+// Original path: src/renderer/src/components/Icons/ReasoningIcon.tsx
+import { Tooltip } from 'antd'
+import React, { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import styled from 'styled-components'
+
+const ReasoningIcon: FC, HTMLElement>> = (props) => {
+ const { t } = useTranslation()
+
+ return (
+
+
+
+
+
+ )
+}
+
+const Container = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+`
+
+const Icon = styled.i`
+ color: var(--color-link);
+ font-size: 16px;
+ margin-right: 6px;
+`
+
+export default ReasoningIcon
diff --git a/packages/ui/src/components/icons/SvgSpinners180Ring/index.tsx b/packages/ui/src/components/icons/SvgSpinners180Ring/index.tsx
new file mode 100644
index 0000000000..c0b3abbfca
--- /dev/null
+++ b/packages/ui/src/components/icons/SvgSpinners180Ring/index.tsx
@@ -0,0 +1,22 @@
+// Original path: src/renderer/src/components/Icons/SvgSpinners180Ring.tsx
+import { SVGProps } from 'react'
+
+export function SvgSpinners180Ring(props: SVGProps & { size?: number | string }) {
+ const { size = '1em', ...svgProps } = props
+
+ return (
+
+ )
+}
+export default SvgSpinners180Ring
diff --git a/packages/ui/src/components/icons/ToolsCallingIcon.tsx b/packages/ui/src/components/icons/ToolsCallingIcon/index.tsx
similarity index 100%
rename from packages/ui/src/components/icons/ToolsCallingIcon.tsx
rename to packages/ui/src/components/icons/ToolsCallingIcon/index.tsx
diff --git a/packages/ui/src/components/icons/VisionIcon.tsx b/packages/ui/src/components/icons/VisionIcon/index.tsx
similarity index 100%
rename from packages/ui/src/components/icons/VisionIcon.tsx
rename to packages/ui/src/components/icons/VisionIcon/index.tsx
diff --git a/packages/ui/src/components/icons/WebSearchIcon.tsx b/packages/ui/src/components/icons/WebSearchIcon/index.tsx
similarity index 100%
rename from packages/ui/src/components/icons/WebSearchIcon.tsx
rename to packages/ui/src/components/icons/WebSearchIcon/index.tsx
diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts
index 97104d11af..8b0f624dd4 100644
--- a/packages/ui/src/components/index.ts
+++ b/packages/ui/src/components/index.ts
@@ -1,5 +1,7 @@
// Base Components
+export { default as CopyButton } from './base/CopyButton'
export { default as DividerWithText } from './base/DividerWithText'
+export { default as EmojiIcon } from './base/EmojiIcon'
export { default as IndicatorLight } from './base/IndicatorLight'
export { default as Spinner } from './base/Spinner'
export { default as TextBadge } from './base/TextBadge'
@@ -7,15 +9,22 @@ export { default as TextBadge } from './base/TextBadge'
// Display Components
export { default as Ellipsis } from './display/Ellipsis'
export { default as ExpandableText } from './display/ExpandableText'
+export { default as ThinkingEffect } from './display/ThinkingEffect'
// Layout Components
export { default as HorizontalScrollContainer } from './layout/HorizontalScrollContainer'
export { default as Scrollbar } from './layout/Scrollbar'
// Icon Components
+export { FilePngIcon, FileSvgIcon } from './icons/FileIcons'
+export { default as ReasoningIcon } from './icons/ReasoningIcon'
+export { default as SvgSpinners180Ring } from './icons/SvgSpinners180Ring'
export { default as ToolsCallingIcon } from './icons/ToolsCallingIcon'
export { default as VisionIcon } from './icons/VisionIcon'
export { default as WebSearchIcon } from './icons/WebSearchIcon'
// Interactive Components
export { default as InfoTooltip } from './interactive/InfoTooltip'
+
+// Composite Components (复合组件)
+// 暂无复合组件
diff --git a/packages/ui/src/components/interactive/InfoTooltip.tsx b/packages/ui/src/components/interactive/InfoTooltip/index.tsx
similarity index 95%
rename from packages/ui/src/components/interactive/InfoTooltip.tsx
rename to packages/ui/src/components/interactive/InfoTooltip/index.tsx
index 53aa0c2a85..dee06bdd02 100644
--- a/packages/ui/src/components/interactive/InfoTooltip.tsx
+++ b/packages/ui/src/components/interactive/InfoTooltip/index.tsx
@@ -18,4 +18,4 @@ const InfoTooltip = ({ iconColor = 'var(--color-text-2)', iconSize = 14, iconSty
)
}
-export default InfoTooltip
\ No newline at end of file
+export default InfoTooltip
diff --git a/packages/ui/src/components/layout/HorizontalScrollContainer.tsx b/packages/ui/src/components/layout/HorizontalScrollContainer/index.tsx
similarity index 99%
rename from packages/ui/src/components/layout/HorizontalScrollContainer.tsx
rename to packages/ui/src/components/layout/HorizontalScrollContainer/index.tsx
index 78b45481d6..1d1875c3a0 100644
--- a/packages/ui/src/components/layout/HorizontalScrollContainer.tsx
+++ b/packages/ui/src/components/layout/HorizontalScrollContainer/index.tsx
@@ -3,7 +3,7 @@ import { ChevronRight } from 'lucide-react'
import { useEffect, useRef, useState } from 'react'
import styled from 'styled-components'
-import Scrollbar from './Scrollbar'
+import Scrollbar from '../Scrollbar'
/**
* 水平滚动容器
diff --git a/packages/ui/src/components/layout/Scrollbar.tsx b/packages/ui/src/components/layout/Scrollbar/index.tsx
similarity index 100%
rename from packages/ui/src/components/layout/Scrollbar.tsx
rename to packages/ui/src/components/layout/Scrollbar/index.tsx