diff --git a/src/app/chat/[id]/page.tsx b/src/app/chat/[id]/page.tsx index 5494e8d..9c5f11a 100644 --- a/src/app/chat/[id]/page.tsx +++ b/src/app/chat/[id]/page.tsx @@ -6,6 +6,7 @@ import { Share2, MoreHorizontal, Loader2, Square, Clock, ChevronDown, Pencil, Tr import { Sidebar, SidebarToggle } from '@/components/layout/Sidebar'; import { ChatInput } from '@/components/features/ChatInput'; import { MessageBubble } from '@/components/features/MessageBubble'; +import { ChatHeaderInfo } from '@/components/features/ChatHeader'; import { cn } from '@/lib/utils'; import { useConversation, useConversations } from '@/hooks/useConversations'; import { useStreamChat, type ChatMessage } from '@/hooks/useStreamChat'; @@ -263,6 +264,19 @@ export default function ChatPage({ params }: PageProps) { setEnableThinking(!enableThinking); }; + // 切换模型(持久化到数据库) + const handleModelChange = async (modelId: string) => { + if (!conversation || modelId === selectedModelId) return; + + try { + await updateConversation(chatId, { model: modelId }); + setSelectedModelId(modelId); + } catch (error) { + console.error('Failed to change model:', error); + throw error; + } + }; + // 转换模型格式 const modelOptions = models.map((m) => ({ id: m.modelId, @@ -305,89 +319,91 @@ export default function ChatPage({ params }: PageProps) { )} > {/* 固定顶部 Header */} -
-
- setSidebarOpen(!sidebarOpen)} /> +
+ {/* 第一行:标题和操作按钮 */} +
+
+ setSidebarOpen(!sidebarOpen)} /> - {/* 标题区域 - 可点击显示下拉菜单 */} - {isEditingTitle ? ( - // 编辑模式 -
- setEditingTitle(e.target.value)} - onKeyDown={handleTitleKeyDown} - onBlur={handleCancelRename} - className="px-2 py-1 text-base font-medium bg-[var(--color-bg-secondary)] border border-[var(--color-border)] rounded text-[var(--color-text-primary)] focus:outline-none focus:border-[var(--color-primary)] max-w-[300px]" - disabled={isSavingTitle} - /> - + +
+ ) : ( + // 正常模式 - 显示标题和下拉菜单 +
+ + + {/* 下拉菜单 */} + {titleMenuOpen && ( +
+ + +
)} - - -
- ) : ( - // 正常模式 - 显示标题和下拉菜单 -
- - - {/* 下拉菜单 */} - {titleMenuOpen && ( -
- - -
- )} -
- )} -
-
- {/* 思考模式开关 */} +
+ )} +
+
+ {/* 思考模式开关 */} +
+
+ + {/* 第二行:助手和模型信息 */} +
+
diff --git a/src/app/globals.css b/src/app/globals.css index da75f98..3c49cdc 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -258,6 +258,26 @@ body { animation: scaleInFast 0.15s ease-out; } +.animate-scale-in { + animation: scaleInFast 0.2s ease-out; +} + +/* 卡片淡入上浮动画 */ +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.animate-fade-in-up { + animation: fadeInUp 0.3s ease-out both; +} + /* ======================================== 响应式设计 ======================================== */ diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index 02d1061..7bd7ab9 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -2,11 +2,11 @@ import Link from 'next/link'; import { usePathname, useRouter } from 'next/navigation'; -import { Plus, PanelLeft, Trash2, MoreHorizontal, Loader2, Pencil, Check, X } from 'lucide-react'; +import { Plus, PanelLeft, Trash2, MoreHorizontal, Loader2, Pencil, Check, X, Bot } from 'lucide-react'; import { UserMenu } from '@/components/ui/UserMenu'; +import { NewChatModal } from '@/components/features/NewChatModal'; import { cn } from '@/lib/utils'; import { useConversations } from '@/hooks/useConversations'; -import { useSettings } from '@/hooks/useSettings'; import { useAuth } from '@/providers/AuthProvider'; import type { Conversation } from '@/drizzle/schema'; import { useState, useRef, useEffect } from 'react'; @@ -19,14 +19,13 @@ interface SidebarProps { export function Sidebar({ isOpen = true }: SidebarProps) { const pathname = usePathname(); const router = useRouter(); - const { conversations, loading, createConversation, deleteConversation, updateConversation } = useConversations(); - const { settings } = useSettings(); + const { conversations, loading, deleteConversation, updateConversation } = useConversations(); const { user } = useAuth(); - const [creatingChat, setCreatingChat] = useState(false); const [menuOpen, setMenuOpen] = useState(null); const [editingId, setEditingId] = useState(null); const [editingTitle, setEditingTitle] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); + const [showNewChatModal, setShowNewChatModal] = useState(false); const inputRef = useRef(null); const menuRef = useRef(null); @@ -53,23 +52,9 @@ export function Sidebar({ isOpen = true }: SidebarProps) { }; }, [menuOpen]); - // 创建新对话 - const handleNewChat = async () => { - if (creatingChat) return; - - try { - setCreatingChat(true); - const newConversation = await createConversation({ - model: settings?.defaultModel || 'claude-sonnet-4-20250514', - tools: settings?.defaultTools || [], - enableThinking: settings?.enableThinking || false, - }); - router.push(`/chat/${newConversation.conversationId}`); - } catch (error) { - console.error('Failed to create conversation:', error); - } finally { - setCreatingChat(false); - } + // 创建新对话 - 显示选择助手弹框 + const handleNewChat = () => { + setShowNewChatModal(true); }; // 删除对话 @@ -150,18 +135,29 @@ export function Sidebar({ isOpen = true }: SidebarProps) {
+ {/* 助手库入口 */} +
+ + + 助手库 + +
+ {/* 聊天列表 */}