import { useState, useEffect, useMemo } from 'react'; import { ChevronLeft, ChevronRight, ChevronDown, ChevronUp, Search, Globe, Rocket, Moon, Asterisk, Sparkles, Star, X } from 'lucide-react'; import type { CelestialBody } from '../types'; interface ProbeListProps { probes: CelestialBody[]; planets: CelestialBody[]; onBodySelect: (body: CelestialBody | null) => void; selectedBody: CelestialBody | null; onResetCamera: () => void; } export function ProbeList({ probes, planets, onBodySelect, selectedBody, onResetCamera }: ProbeListProps) { const [isCollapsed, setIsCollapsed] = useState(false); const [searchTerm, setSearchTerm] = useState(''); const [expandedGroup, setExpandedGroup] = useState('planet'); // Default expand planets // Auto-collapse when a body is selected (focus mode) useEffect(() => { if (selectedBody) { setIsCollapsed(true); } }, [selectedBody]); // Calculate distance for sorting const calculateDistance = (body: CelestialBody) => { if (!body.positions || body.positions.length === 0) { return Infinity; // Bodies without positions go to the end } const pos = body.positions[0]; return Math.sqrt(pos.x ** 2 + pos.y ** 2 + pos.z ** 2); }; // Process and sort bodies const allBodies = useMemo(() => { const list = [...planets, ...probes]; return list .filter(b => { // Filter out bodies without positions if (!b.positions || b.positions.length === 0) { return false; } // Filter by search term - include all types including stars if (!searchTerm) return true; return (b.name_zh || b.name).toLowerCase().includes(searchTerm.toLowerCase()); }) .map(body => ({ body, distance: calculateDistance(body) })) .sort((a, b) => a.distance - b.distance); }, [planets, probes, searchTerm]); // Group bodies by type const groups = useMemo(() => { const starList = allBodies.filter(({ body }) => body.type === 'star'); const planetList = allBodies.filter(({ body }) => body.type === 'planet'); const dwarfPlanetList = allBodies.filter(({ body }) => body.type === 'dwarf_planet'); const satelliteList = allBodies.filter(({ body }) => body.type === 'satellite'); const probeList = allBodies.filter(({ body }) => body.type === 'probe'); const cometList = allBodies.filter(({ body }) => body.type === 'comet'); return { star: starList, planet: planetList, dwarf_planet: dwarfPlanetList, satellite: satelliteList, probe: probeList, comet: cometList }; }, [allBodies]); const toggleGroup = (groupName: string) => { setExpandedGroup(prev => prev === groupName ? null : groupName); }; return (
{/* Toggle Button (Attached to the side or floating when collapsed) */} {/* Main Content Panel */}
{/* Header & Search */}

天体导航

{ setSearchTerm(e.target.value); if (e.target.value && !expandedGroup) setExpandedGroup('planet'); }} className="w-full bg-black/40 border border-white/10 rounded-lg pl-9 pr-8 py-2.5 text-xs text-gray-200 placeholder-gray-600 focus:outline-none focus:border-[#238636] focus:shadow-[0_0_15px_rgba(35,134,54,0.2)] transition-all duration-300 backdrop-blur-sm" /> {searchTerm && ( )}
{/* List Content */}
{/* Stars Group */} {groups.star.length > 0 && ( } count={groups.star.length} bodies={groups.star} isExpanded={expandedGroup === 'star'} onToggle={() => toggleGroup('star')} selectedBody={selectedBody} onBodySelect={onBodySelect} /> )} {/* Planets Group */} {groups.planet.length > 0 && ( } count={groups.planet.length} bodies={groups.planet} isExpanded={expandedGroup === 'planet'} onToggle={() => toggleGroup('planet')} selectedBody={selectedBody} onBodySelect={onBodySelect} /> )} {/* Dwarf Planets Group */} {groups.dwarf_planet.length > 0 && ( } count={groups.dwarf_planet.length} bodies={groups.dwarf_planet} isExpanded={expandedGroup === 'dwarf_planet'} onToggle={() => toggleGroup('dwarf_planet')} selectedBody={selectedBody} onBodySelect={onBodySelect} /> )} {/* Satellites Group */} {groups.satellite.length > 0 && ( } count={groups.satellite.length} bodies={groups.satellite} isExpanded={expandedGroup === 'satellite'} onToggle={() => toggleGroup('satellite')} selectedBody={selectedBody} onBodySelect={onBodySelect} /> )} {/* Probes Group */} {groups.probe.length > 0 && ( } count={groups.probe.length} bodies={groups.probe} isExpanded={expandedGroup === 'probe'} onToggle={() => toggleGroup('probe')} selectedBody={selectedBody} onBodySelect={onBodySelect} /> )} {/* Comets Group */} {groups.comet.length > 0 && ( } count={groups.comet.length} bodies={groups.comet} isExpanded={expandedGroup === 'comet'} onToggle={() => toggleGroup('comet')} selectedBody={selectedBody} onBodySelect={onBodySelect} /> )} {/* No results message */} {allBodies.length === 0 && (
未找到匹配的天体
)}
); } // Group component for collapsible body lists function BodyGroup({ title, icon, count, bodies, isExpanded, onToggle, selectedBody, onBodySelect }: { title: string; icon: React.ReactNode; count: number; bodies: Array<{ body: CelestialBody; distance: number }>; isExpanded: boolean; onToggle: () => void; selectedBody: CelestialBody | null; onBodySelect: (body: CelestialBody) => void; }) { return (
{/* Group Header */} {/* Group Content */} {isExpanded && (
{bodies.map(({ body, distance }) => ( onBodySelect(body)} /> ))}
)}
); } function BodyItem({ body, distance, isSelected, onClick }: { body: CelestialBody, distance: number, isSelected: boolean, onClick: () => void }) { const isInactive = body.is_active === false; return ( ); }