/** * Sidebar Component * * 响应式侧边栏:桌面端固定显示,移动端抽屉式菜单 */ import { useState, useEffect } from 'react'; import { Plus, MessageSquare, Trash2, RefreshCw, Menu, X } from 'lucide-react'; import clsx from 'clsx'; import { listSessions, createSession, deleteSession, type Session } from '../api/client'; interface SidebarProps { currentSessionId: string | null; onSelectSession: (id: string) => void; onCreateSession: (session: Session) => void; } export function Sidebar({ currentSessionId, onSelectSession, onCreateSession }: SidebarProps) { const [sessions, setSessions] = useState([]); const [isLoading, setIsLoading] = useState(false); const [isOpen, setIsOpen] = useState(false); const loadSessions = async () => { setIsLoading(true); try { const { data } = await listSessions(); setSessions(data); } catch (error) { console.error('Failed to load sessions:', error); } finally { setIsLoading(false); } }; const handleCreate = async () => { try { const { data } = await createSession(); setSessions((prev) => [data, ...prev]); onCreateSession(data); setIsOpen(false); // 创建后关闭侧边栏 } catch (error) { console.error('Failed to create session:', error); } }; const handleDelete = async (id: string, e: React.MouseEvent) => { e.stopPropagation(); try { await deleteSession(id); setSessions((prev) => prev.filter((s) => s.id !== id)); if (currentSessionId === id) { const remaining = sessions.filter((s) => s.id !== id); if (remaining.length > 0) { onSelectSession(remaining[0].id); } } } catch (error) { console.error('Failed to delete session:', error); } }; const handleSelectSession = (id: string) => { onSelectSession(id); setIsOpen(false); // 选择后关闭侧边栏 }; useEffect(() => { loadSessions(); }, []); // 点击遮罩层关闭 const handleOverlayClick = () => { setIsOpen(false); }; return ( <> {/* 移动端菜单按钮 */} {/* 遮罩层 - 仅移动端 */} {isOpen && (
)} {/* 侧边栏 */}
{/* Header */}
Sessions
{/* Session List */}
{isLoading ? (
) : sessions.length === 0 ? (
No conversations yet
) : (
{sessions.map((session) => (
handleSelectSession(session.id)} className={clsx( 'flex items-center gap-2 p-3 rounded-lg cursor-pointer group', 'hover:bg-gray-700 transition-colors', 'active:bg-gray-600', // 触摸反馈 currentSessionId === session.id && 'bg-gray-700' )} >
{session.name || `Chat ${session.id.slice(0, 8)}`}
{session.messageCount} messages
))}
)}
{/* Footer */}
AI Assistant v1.0
); }