/** * VesselList — sidebar of currently-known vessels. * * Click a vessel to track it (the camera follows + the orbit is * highlighted). Click again to untrack. */ import type { Vessel } from '@kerbal-rt/shared-types'; import { vesselColor } from '../scene/color.js'; export interface VesselListProps { vessels: Vessel[]; selectedId: string | null; onSelect: (id: string | null) => void; } const PANEL_STYLE: React.CSSProperties = { position: 'absolute', top: 110, left: 12, width: 280, maxHeight: 'calc(100vh - 200px)', overflow: 'auto', padding: '0.5rem', background: 'rgba(0,0,0,0.7)', color: 'white', borderRadius: 6, fontSize: 12, fontFamily: 'monospace', backdropFilter: 'blur(4px)', border: '1px solid rgba(255,255,255,0.1)', }; const ROW_STYLE: React.CSSProperties = { padding: '0.4rem 0.5rem', marginBottom: 2, borderRadius: 3, cursor: 'pointer', background: 'rgba(255,255,255,0.04)', border: '1px solid transparent', display: 'flex', alignItems: 'center', gap: 6, }; const ROW_ACTIVE: React.CSSProperties = { ...ROW_STYLE, background: 'rgba(255,255,255,0.12)', border: '1px solid rgba(255,255,255,0.3)', }; const DOT_STYLE: (color: number) => React.CSSProperties = (color) => ({ width: 8, height: 8, borderRadius: '50%', background: `#${color.toString(16).padStart(6, '0')}`, flexShrink: 0, }); export function VesselList({ vessels, selectedId, onSelect }: VesselListProps) { const sorted = [...vessels].sort((a, b) => a.name.localeCompare(b.name)); return (
Vessels ({vessels.length})
{sorted.length === 0 ? (
No vessels yet.
) : ( sorted.map((v) => { const color = vesselColor(v.owner); const isActive = selectedId === v.id; return (
onSelect(isActive ? null : v.id)} title={v.id} >
{v.name}
{v.owner ?? '—'} · {v.situation.toLowerCase()} · {v.referenceBodyId}
); }) )}
); }