- Add framer-motion page transitions and AnimatePresence support - Add dark mode support across all components - Create reusable UI components (Button, Badge, Card, EmptyState, Input, Toast, Skeleton) - Add CSS custom properties for consistent theming - Add animation variants and utility functions - Improve ChatArea, Sidebar, TriggersPanel with animations Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
128 lines
4.3 KiB
TypeScript
128 lines
4.3 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
import './index.css';
|
|
import { Sidebar, MainViewType } from './components/Sidebar';
|
|
import { ChatArea } from './components/ChatArea';
|
|
import { RightPanel } from './components/RightPanel';
|
|
import { SettingsLayout } from './components/Settings/SettingsLayout';
|
|
import { HandTaskPanel } from './components/HandTaskPanel';
|
|
import { SchedulerPanel } from './components/SchedulerPanel';
|
|
import { TeamCollaborationView } from './components/TeamCollaborationView';
|
|
import { useGatewayStore } from './store/gatewayStore';
|
|
import { useTeamStore } from './store/teamStore';
|
|
import { getStoredGatewayToken } from './lib/gateway-client';
|
|
import { pageVariants, defaultTransition, fadeInVariants } from './lib/animations';
|
|
import { Bot, Users } from 'lucide-react';
|
|
import { EmptyState } from './components/ui';
|
|
|
|
type View = 'main' | 'settings';
|
|
|
|
function App() {
|
|
const [view, setView] = useState<View>('main');
|
|
const [mainContentView, setMainContentView] = useState<MainViewType>('chat');
|
|
const [selectedHandId, setSelectedHandId] = useState<string | undefined>(undefined);
|
|
const [selectedTeamId, setSelectedTeamId] = useState<string | undefined>(undefined);
|
|
const { connect, connectionState } = useGatewayStore();
|
|
const { activeTeam, setActiveTeam, teams } = useTeamStore();
|
|
|
|
useEffect(() => {
|
|
document.title = 'ZCLAW';
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (connectionState === 'disconnected') {
|
|
const gatewayToken = getStoredGatewayToken();
|
|
connect(undefined, gatewayToken).catch(() => {});
|
|
}
|
|
}, [connect, connectionState]);
|
|
|
|
// 当切换到非 hands 视图时清除选中的 Hand
|
|
const handleMainViewChange = (view: MainViewType) => {
|
|
setMainContentView(view);
|
|
if (view !== 'hands') {
|
|
// 可选:清除选中的 Hand
|
|
// setSelectedHandId(undefined);
|
|
}
|
|
};
|
|
|
|
const handleSelectTeam = (teamId: string) => {
|
|
const team = teams.find(t => t.id === teamId);
|
|
if (team) {
|
|
setActiveTeam(team);
|
|
setSelectedTeamId(teamId);
|
|
}
|
|
};
|
|
|
|
if (view === 'settings') {
|
|
return <SettingsLayout onBack={() => setView('main')} />;
|
|
}
|
|
|
|
return (
|
|
<div className="h-screen flex overflow-hidden text-gray-800 text-sm">
|
|
{/* 左侧边栏 */}
|
|
<Sidebar
|
|
onOpenSettings={() => setView('settings')}
|
|
onMainViewChange={handleMainViewChange}
|
|
selectedHandId={selectedHandId}
|
|
onSelectHand={setSelectedHandId}
|
|
selectedTeamId={selectedTeamId}
|
|
onSelectTeam={handleSelectTeam}
|
|
/>
|
|
|
|
{/* 中间区域 */}
|
|
<AnimatePresence mode="wait">
|
|
<motion.main
|
|
key={mainContentView}
|
|
variants={pageVariants}
|
|
initial="initial"
|
|
animate="animate"
|
|
exit="exit"
|
|
transition={defaultTransition}
|
|
className="flex-1 flex flex-col bg-white relative overflow-hidden"
|
|
>
|
|
{mainContentView === 'hands' && selectedHandId ? (
|
|
<HandTaskPanel
|
|
handId={selectedHandId}
|
|
onBack={() => setSelectedHandId(undefined)}
|
|
/>
|
|
) : mainContentView === 'hands' ? (
|
|
<EmptyState
|
|
icon={<Bot className="w-8 h-8" />}
|
|
title="Select a Hand"
|
|
description="Choose an autonomous capability package from the list on the left to view its task list and execution results."
|
|
/>
|
|
) : mainContentView === 'workflow' ? (
|
|
<motion.div
|
|
variants={fadeInVariants}
|
|
initial="initial"
|
|
animate="animate"
|
|
className="flex-1 overflow-y-auto"
|
|
>
|
|
<SchedulerPanel />
|
|
</motion.div>
|
|
) : mainContentView === 'team' ? (
|
|
activeTeam ? (
|
|
<TeamCollaborationView teamId={activeTeam.id} />
|
|
) : (
|
|
<EmptyState
|
|
icon={<Users className="w-8 h-8" />}
|
|
title="Select or Create a Team"
|
|
description="Choose a team from the list on the left, or click + to create a new multi-Agent collaboration team."
|
|
/>
|
|
)
|
|
) : (
|
|
<ChatArea />
|
|
)}
|
|
</motion.main>
|
|
</AnimatePresence>
|
|
|
|
{/* 右侧边栏 */}
|
|
<RightPanel />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default App;
|
|
|
|
|