/** * Cosmo - Deep Space Explorer * Main application component */ import { useState, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { useSpaceData } from './hooks/useSpaceData'; import { useHistoricalData } from './hooks/useHistoricalData'; import { useTrajectory } from './hooks/useTrajectory'; import { useScreenshot } from './hooks/useScreenshot'; import { Header } from './components/Header'; import { Scene } from './components/Scene'; import { ProbeList } from './components/ProbeList'; import { TimelineController } from './components/TimelineController'; import { Loading } from './components/Loading'; import { InterstellarTicker } from './components/InterstellarTicker'; import { ControlPanel } from './components/ControlPanel'; import type { CelestialBody } from './types'; // Timeline configuration - will be fetched from backend later const TIMELINE_DAYS = 30; // Total days in timeline range function App() { const navigate = useNavigate(); const [selectedDate, setSelectedDate] = useState(null); const [isTimelineMode, setIsTimelineMode] = useState(false); const [showOrbits, setShowOrbits] = useState(true); const [isSoundOn, setIsSoundOn] = useState(false); const [showDanmaku, setShowDanmaku] = useState(true); const { takeScreenshot } = useScreenshot(); // Use real-time data or historical data based on mode const { bodies: realTimeBodies, loading: realTimeLoading, error: realTimeError } = useSpaceData(); const { bodies: historicalBodies, loading: historicalLoading, error: historicalError } = useHistoricalData(selectedDate); const bodies = isTimelineMode ? historicalBodies : realTimeBodies; const loading = isTimelineMode ? historicalLoading : realTimeLoading; const error = isTimelineMode ? historicalError : realTimeError; const [selectedBody, setSelectedBody] = useState(null); const { trajectoryPositions } = useTrajectory(selectedBody); // Handle time change from timeline controller const handleTimeChange = useCallback((date: Date) => { setSelectedDate(date); }, []); // Toggle timeline mode const toggleTimelineMode = useCallback(() => { setIsTimelineMode((prev) => !prev); if (!isTimelineMode) { // Entering timeline mode, set initial date to now (will play backward) setSelectedDate(new Date()); } else { setSelectedDate(null); } }, [isTimelineMode]); // Filter probes and planets from all bodies const probes = bodies.filter((b) => b.type === 'probe'); const planets = bodies.filter((b) => b.type === 'planet' || b.type === 'dwarf_planet' || b.type === 'satellite' ); const handleBodySelect = (body: CelestialBody | null) => { setSelectedBody(body); }; // Only show full screen loading when we have no data // This prevents flashing when timeline is playing and fetching new data if (loading && bodies.length === 0) { return ; } if (error) { return (

数据加载失败

{error}

请确保后端 API 运行在 http://localhost:8000

); } return (
{/* Header with simplified branding */}
{/* Right Control Panel */} setShowOrbits(!showOrbits)} isSoundOn={isSoundOn} onToggleSound={() => setIsSoundOn(!isSoundOn)} showDanmaku={showDanmaku} onToggleDanmaku={() => setShowDanmaku(!showDanmaku)} onLogin={() => navigate('/login')} onScreenshot={takeScreenshot} /> {/* Probe List Sidebar */} {/* 3D Scene */} {/* Timeline Controller */} {isTimelineMode && ( )} {/* Interstellar Ticker Sound (Controlled) */} {/* Instructions overlay (Only show when exploring freely) */} {!selectedBody && (
左键 旋转
右键 平移
滚轮 缩放
)}
); } export default App;