116 lines
4.6 KiB
TypeScript
116 lines
4.6 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { Routes, Route, Navigate, useLocation, useNavigate } from 'react-router-dom';
|
|
import { Button, Drawer, Spin } from 'antd';
|
|
import { MenuOutlined, SearchOutlined } from '@ant-design/icons';
|
|
import Sidebar from './components/Sidebar';
|
|
import CommandPalette from './components/CommandPalette';
|
|
import AgentList from './pages/AgentList';
|
|
import AgentEditor from './pages/AgentEditor';
|
|
import ChatPage from './pages/ChatPage';
|
|
import LoginPage from './pages/LoginPage';
|
|
import MarketplacePage from './pages/MarketplacePage';
|
|
import PointsMallPage from './pages/PointsMallPage';
|
|
import TeamsPage from './pages/TeamsPage';
|
|
import PromptLibraryPage from './pages/PromptLibraryPage';
|
|
import StatsPage from './pages/StatsPage';
|
|
import SharedSessionPage from './pages/SharedSessionPage';
|
|
import WorkflowsPage from './pages/WorkflowsPage';
|
|
import { useAuth } from './store/auth';
|
|
import { AgentAPI } from './api';
|
|
|
|
function HomeRedirect() {
|
|
return <Navigate to="/chat" replace />;
|
|
}
|
|
|
|
export default function App() {
|
|
const { user } = useAuth();
|
|
const location = useLocation();
|
|
const [paletteOpen, setPaletteOpen] = useState(false);
|
|
const [mobileNavOpen, setMobileNavOpen] = useState(false);
|
|
const [isMobile, setIsMobile] = useState(() => (typeof window === 'undefined' ? false : window.innerWidth < 768));
|
|
|
|
// 全局快捷键 Ctrl/⌘ + K
|
|
useEffect(() => {
|
|
if (!user) return;
|
|
const handler = (e: KeyboardEvent) => {
|
|
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k') {
|
|
e.preventDefault();
|
|
setPaletteOpen((v) => !v);
|
|
}
|
|
};
|
|
window.addEventListener('keydown', handler);
|
|
return () => window.removeEventListener('keydown', handler);
|
|
}, [user]);
|
|
|
|
useEffect(() => {
|
|
const onResize = () => setIsMobile(window.innerWidth < 768);
|
|
window.addEventListener('resize', onResize);
|
|
return () => window.removeEventListener('resize', onResize);
|
|
}, []);
|
|
|
|
const mainContent = (
|
|
<Routes>
|
|
<Route path="/" element={<HomeRedirect />} />
|
|
<Route path="/chat" element={<ChatPage />} />
|
|
<Route path="/chat/:id" element={<ChatPage />} />
|
|
<Route path="/agents" element={<AgentList />} />
|
|
<Route path="/agents/new" element={<AgentEditor />} />
|
|
<Route path="/agents/:id" element={<AgentEditor />} />
|
|
<Route path="/agents/:id/chat" element={<Navigate to="/chat" replace />} />
|
|
<Route path="/marketplace" element={<MarketplacePage />} />
|
|
<Route path="/points-mall" element={<PointsMallPage />} />
|
|
<Route path="/teams" element={<TeamsPage />} />
|
|
<Route path="/prompts" element={<PromptLibraryPage />} />
|
|
<Route path="/stats" element={<StatsPage />} />
|
|
<Route path="/workflows" element={<WorkflowsPage />} />
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
);
|
|
|
|
return (
|
|
<>
|
|
{/* 公开分享会话页:跳过 AuthGuard */}
|
|
{location.pathname.startsWith('/shared/') ? (
|
|
<Routes>
|
|
<Route path="/shared/:token" element={<SharedSessionPage />} />
|
|
</Routes>
|
|
) : !user ? (
|
|
<Routes>
|
|
<Route path="/login" element={<LoginPage />} />
|
|
<Route path="*" element={<LoginPage />} />
|
|
</Routes>
|
|
) : (
|
|
<div className="layout-shell">
|
|
{/* 只有编辑器全屏显示,其他页面均保留侧边栏 */}
|
|
{!isMobile && (!location.pathname.startsWith('/agents/') || location.pathname.includes('/chat')) ? (
|
|
<Sidebar onOpenPalette={() => setPaletteOpen(true)} />
|
|
) : null}
|
|
<main className="main">
|
|
{isMobile && (
|
|
<div className="mobile-topbar">
|
|
<Button type="text" icon={<MenuOutlined />} onClick={() => setMobileNavOpen(true)} />
|
|
<div className="mobile-topbar-title">Agent Studio</div>
|
|
<Button type="text" icon={<SearchOutlined />} onClick={() => setPaletteOpen(true)} />
|
|
</div>
|
|
)}
|
|
<div className="main-content">{mainContent}</div>
|
|
</main>
|
|
<CommandPalette open={paletteOpen} onClose={() => setPaletteOpen(false)} />
|
|
{isMobile && (
|
|
<Drawer
|
|
title="导航"
|
|
placement="left"
|
|
open={mobileNavOpen}
|
|
onClose={() => setMobileNavOpen(false)}
|
|
width={280}
|
|
styles={{ body: { padding: 0 } }}
|
|
>
|
|
<Sidebar onOpenPalette={() => setPaletteOpen(true)} onNavigate={() => setMobileNavOpen(false)} />
|
|
</Drawer>
|
|
)}
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|