127 lines
4.3 KiB
Markdown
127 lines
4.3 KiB
Markdown
# ChatHistory 侧边栏折叠功能迁移计划
|
||
|
||
## 参考来源
|
||
- **源文件**: `ClawX/src/components/layout/Sidebar.tsx:234-247`
|
||
- **目标文件**: `zn-ai/src/pages/home/ChatHistory.vue:6`
|
||
|
||
## 源实现思路分析
|
||
|
||
`Sidebar.tsx:234-247` 的核心实现逻辑:
|
||
|
||
1. **状态驱动**: 通过 `useSettingsStore` 获取 `sidebarCollapsed` 布尔值与 `setSidebarCollapsed` setter。
|
||
2. **图标切换**: 点击按钮时,根据当前状态切换图标:
|
||
- 展开状态 → 显示 `PanelLeftClose`(提示可收起)
|
||
- 收起状态 → 显示 `PanelLeft`(提示可展开)
|
||
3. **样式过渡**: 外层 `aside` 通过 `transition-all duration-300` 配合条件类名 `w-16` / `w-64` 实现宽度动画。
|
||
4. **内容显隐**: 内部文字/列表在收起时隐藏(`!sidebarCollapsed && ...`),只保留图标按钮可点。
|
||
|
||
## 迁移目标
|
||
|
||
将上述折叠/展开交互迁移到 `ChatHistory.vue`,使其第 6 行的 `RiSideBarLine` 图标具备切换侧边栏宽度的能力,并保持与现有 `zn-ai` 项目风格一致。
|
||
|
||
## 实现步骤
|
||
|
||
### 1. 状态定义(ChatHistory.vue 本地状态)
|
||
|
||
在 `<script setup>` 中新增响应式状态,无需引入全局 store(当前页面无对应 store,本地 ref 足够):
|
||
|
||
```ts
|
||
const sidebarCollapsed = ref(false)
|
||
```
|
||
|
||
### 2. 图标点击交互(对应目标文件第 6 行)
|
||
|
||
将现有静态图标改造为可点击切换状态:
|
||
|
||
```html
|
||
<!-- 修改前 -->
|
||
<RiSideBarLine class="ml-auto cursor-pointer" />
|
||
|
||
<!-- 修改后 -->
|
||
<RiSideBarLine
|
||
v-if="!sidebarCollapsed"
|
||
class="ml-auto cursor-pointer hover:text-[#2B7FFF]"
|
||
@click="sidebarCollapsed = true"
|
||
/>
|
||
<RiArrowRightSLine
|
||
v-else
|
||
class="ml-auto cursor-pointer hover:text-[#2B7FFF]"
|
||
@click="sidebarCollapsed = false"
|
||
/>
|
||
```
|
||
|
||
> 说明:
|
||
> - 展开时显示 `RiSideBarLine`(或 `RiSideBarFoldLine` 若项目已有),点击后收起。
|
||
> - 收起时显示 `RiArrowRightSLine`(或 `RiSideBarLine`),点击后展开。
|
||
> - 与源实现保持一致:图标根据状态互斥显示。
|
||
|
||
### 3. 容器宽度过渡动画
|
||
|
||
为 `<aside>` 根元素添加动态类名与过渡:
|
||
|
||
```html
|
||
<aside
|
||
:class="[
|
||
'h-full box-border flex flex-col transition-all duration-300',
|
||
sidebarCollapsed ? 'w-16' : 'w-50'
|
||
]"
|
||
>
|
||
```
|
||
|
||
- 展开宽度保持原设计 `w-50`(`200px`)。
|
||
- 收起宽度收缩为 `w-16`(`64px`),仅保留 Logo 与切换按钮空间。
|
||
- `transition-all duration-300` 保证宽度变化平滑。
|
||
|
||
### 4. 内部内容显隐控制
|
||
|
||
在 `sidebarCollapsed = true` 时,以下区域应隐藏:
|
||
|
||
- **YINIAN Logo 文字**(保留图片,隐藏文字,避免换行)
|
||
- **"新对话" 按钮文字**(可保留图标 `RiAddLine`,或整体隐藏按钮)
|
||
- **历史会话列表**(`groups` 循环区域整体隐藏,避免窄边栏内文字截断)
|
||
|
||
具体修改点:
|
||
|
||
```html
|
||
<!-- Logo 区域 -->
|
||
<div class="flex items-center m-2">
|
||
<img class="w-10 h-10 rounded-md" src="@assets/images/login/white_logo.png" />
|
||
<div v-if="!sidebarCollapsed" class="font-bold text-gray-80">YINIAN</div>
|
||
<!-- 图标切换按钮 -->
|
||
...
|
||
</div>
|
||
|
||
<!-- 新对话按钮 -->
|
||
<div
|
||
v-if="!sidebarCollapsed"
|
||
class="flex justify-center ..."
|
||
@click="addNewChat"
|
||
>
|
||
<RiAddLine /> 新对话
|
||
</div>
|
||
|
||
<!-- 历史会话列表 -->
|
||
<div v-if="!sidebarCollapsed" class="overflow-y-auto p-2">
|
||
...
|
||
</div>
|
||
```
|
||
|
||
### 5. 保持功能可用性
|
||
|
||
- **历史记录加载**:收起状态下仍可在后台通过 `onMounted` 正常加载列表数据,只是不渲染 DOM。
|
||
- **选中态同步**:展开后 `selectedConversationId` 与 `groups` 数据不丢失,用户可继续操作。
|
||
- **响应式恢复**:若窗口尺寸变化导致侧边栏过窄,可后续补充监听自动展开逻辑(本期非必须)。
|
||
|
||
## 涉及文件
|
||
|
||
| 文件 | 修改内容 |
|
||
|---|---|
|
||
| `zn-ai/src/pages/home/ChatHistory.vue` | 新增 `sidebarCollapsed` ref、改造第 6 行图标为状态切换按钮、为 `aside` 添加动态宽度与过渡、控制内部元素显隐 |
|
||
|
||
## 验收标准
|
||
|
||
- [ ] 点击 `RiSideBarLine` 后,侧边栏从 `w-50` 平滑过渡到 `w-16`。
|
||
- [ ] 收起状态下只显示 Logo 图片与展开图标按钮,其余文字/列表隐藏。
|
||
- [ ] 再次点击展开图标,侧边栏平滑恢复 `w-50`,历史列表与选中态保持。
|
||
- [ ] 不影响现有的新建对话、选择会话、重命名、删除功能。
|