feat(页面): 重构聊天页面头部并集成标签管理

- 重构 Header 布局为两行结构
- 第一行:标题 + 操作按钮(思考、摘要、分享、导出)
- 第二行:助手信息 + 标签管理器
- 添加渐变分隔线增强视觉层次
- 优化操作按钮样式统一为圆角方形
- 菜单文字汉化(Rename -> 重命名,Delete -> 删除)
This commit is contained in:
gaoziman 2025-12-28 17:29:08 +08:00
parent bbe07e203e
commit e7de47d0d9

View File

@ -14,6 +14,7 @@ import { LinkPreviewModal } from '@/components/features/LinkPreviewModal';
import { ExportDropdown } from '@/components/features/ExportDropdown'; import { ExportDropdown } from '@/components/features/ExportDropdown';
import { ShareModal } from '@/components/features/ShareModal'; import { ShareModal } from '@/components/features/ShareModal';
import { SummaryButton } from '@/components/features/SummaryGenerator'; import { SummaryButton } from '@/components/features/SummaryGenerator';
import { TagManager } from '@/components/features/Tags';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { useConversation, useConversations } from '@/hooks/useConversations'; import { useConversation, useConversations } from '@/hooks/useConversations';
import { useStreamChat, type ChatMessage } from '@/hooks/useStreamChat'; import { useStreamChat, type ChatMessage } from '@/hooks/useStreamChat';
@ -457,10 +458,10 @@ export default function ChatPage({ params }: PageProps) {
)} )}
> >
{/* 固定顶部 Header */} {/* 固定顶部 Header */}
<header className="px-4 py-2 flex flex-col gap-1 border-b border-[var(--color-border)] bg-[var(--color-bg-primary)] sticky top-0 z-10"> <header className="flex flex-col border-b border-[var(--color-border)] bg-[var(--color-bg-primary)] sticky top-0 z-10">
{/* 第一行:标题操作按钮 */} {/* 第一行:标题 + 操作按钮 */}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between gap-4 px-4 py-2">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3 flex-shrink-0">
<SidebarToggle onClick={() => setSidebarOpen(!sidebarOpen)} /> <SidebarToggle onClick={() => setSidebarOpen(!sidebarOpen)} />
{/* 标题区域 - 可点击显示下拉菜单 */} {/* 标题区域 - 可点击显示下拉菜单 */}
@ -509,7 +510,7 @@ export default function ChatPage({ params }: PageProps) {
<div className="relative" ref={titleMenuRef}> <div className="relative" ref={titleMenuRef}>
<button <button
onClick={() => setTitleMenuOpen(!titleMenuOpen)} onClick={() => setTitleMenuOpen(!titleMenuOpen)}
className="flex items-center gap-1 text-base font-medium text-[var(--color-text-primary)] hover:bg-[var(--color-bg-hover)] px-2 py-1 rounded-lg transition-colors max-w-[300px]" className="flex items-center gap-1 text-base font-medium text-[var(--color-text-primary)] hover:bg-[var(--color-bg-hover)] px-2 py-1 rounded-[4px] transition-colors max-w-[320px]"
> >
<span className="truncate">{conversation?.title || 'New Chat'}</span> <span className="truncate">{conversation?.title || 'New Chat'}</span>
<ChevronDown size={16} className={cn( <ChevronDown size={16} className={cn(
@ -520,76 +521,87 @@ export default function ChatPage({ params }: PageProps) {
{/* 下拉菜单 */} {/* 下拉菜单 */}
{titleMenuOpen && ( {titleMenuOpen && (
<div className="absolute left-0 top-full mt-1 bg-[var(--color-bg-primary)] border border-[var(--color-border)] rounded-lg shadow-lg py-1 z-20 min-w-[140px]"> <div className="absolute left-0 top-full mt-1 bg-[var(--color-bg-primary)] border border-[var(--color-border)] rounded-[4px] shadow-lg py-1 z-20 min-w-[140px]">
<button <button
onClick={handleStartRename} onClick={handleStartRename}
className="w-full px-3 py-2 text-left text-sm text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-hover)] flex items-center gap-2" className="w-full px-3 py-2 text-left text-sm text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-hover)] flex items-center gap-2"
> >
<Pencil size={14} /> <Pencil size={14} />
Rename
</button> </button>
<button <button
onClick={handleDeleteConversation} onClick={handleDeleteConversation}
className="w-full px-3 py-2 text-left text-sm text-red-500 hover:bg-[var(--color-bg-hover)] flex items-center gap-2" className="w-full px-3 py-2 text-left text-sm text-red-500 hover:bg-[var(--color-bg-hover)] flex items-center gap-2"
> >
<Trash2 size={14} /> <Trash2 size={14} />
Delete
</button> </button>
</div> </div>
)} )}
</div> </div>
)} )}
</div> </div>
<div className="flex items-center gap-2">
{/* 右侧操作按钮 */}
<div className="flex items-center gap-1 flex-shrink-0">
{/* 思考模式开关 - 只在非 Codex 模型时显示 */} {/* 思考模式开关 - 只在非 Codex 模型时显示 */}
{!selectedModelId.toLowerCase().includes('codex') && ( {!selectedModelId.toLowerCase().includes('codex') && (
<button
onClick={handleThinkingToggle}
className={cn(
'flex items-center gap-2 px-3 py-1.5 text-sm rounded-[4px] transition-colors',
enableThinking
? 'bg-[var(--color-primary-light)] text-[var(--color-primary)]'
: 'text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-hover)]'
)}
title={enableThinking ? '关闭思考模式' : '开启思考模式'}
>
<Clock size={16} />
<span></span>
</button>
)}
{/* 智能摘要按钮 */}
<SummaryButton
conversationId={chatId}
messages={messages.map(m => ({
role: m.role,
content: m.content,
}))}
hasSummary={!!conversation?.summary}
existingSummary={conversation?.summary}
/>
<button <button
onClick={handleThinkingToggle} onClick={() => setShareModalOpen(true)}
className={cn( className="flex items-center gap-2 px-3 py-1.5 text-sm text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-hover)] rounded-[4px] transition-colors"
'flex items-center gap-2 px-3 py-1.5 text-sm rounded-lg transition-colors', title="分享对话"
enableThinking
? 'bg-[var(--color-primary-light)] text-[var(--color-primary)]'
: 'text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-hover)]'
)}
title={enableThinking ? '关闭思考模式' : '开启思考模式'}
> >
<Clock size={16} /> <Share2 size={16} />
<span></span> <span></span>
</button> </button>
)} <ExportDropdown
conversationId={chatId}
{/* 智能摘要按钮 */} conversationTitle={conversation?.title || '新对话'}
<SummaryButton disabled={isStreaming}
conversationId={chatId} />
messages={messages.map(m => ({
role: m.role,
content: m.content,
}))}
hasSummary={!!conversation?.summary}
existingSummary={conversation?.summary}
/>
<button
onClick={() => setShareModalOpen(true)}
className="flex items-center gap-2 px-3 py-1.5 text-sm text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-hover)] rounded-lg transition-colors"
title="分享对话"
>
<Share2 size={16} />
<span></span>
</button>
<ExportDropdown
conversationId={chatId}
conversationTitle={conversation?.title || '新对话'}
disabled={isStreaming}
/>
</div> </div>
</div> </div>
{/* 第二行:助手信息 */} {/* 渐变分隔线 */}
<div className="pl-12"> <div className="h-px mx-4" style={{ background: 'linear-gradient(90deg, transparent, var(--color-border), transparent)' }} />
{/* 第二行:助手信息 + 标签管理 */}
<div className="flex items-center justify-between gap-4 px-4 py-2 pl-[60px]">
{/* 左侧:助手信息 */}
<ChatHeaderInfo <ChatHeaderInfo
assistant={conversation?.assistant || null} assistant={conversation?.assistant || null}
/> />
{/* 右侧:标签管理区域 */}
{conversation && !isNewChat && (
<TagManager conversationId={chatId} />
)}
</div> </div>
</header> </header>