'use client'; import React, { useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { X, ChevronDown, ChevronUp } from 'lucide-react'; import ExternalImage from '@/components/ExternalImage'; import { useTranslation } from '@/i18n'; // ─── Inline SVG legend icons (small, crisp, no external deps) ─── const plane = (fill: string, size = 16) => ``; const airliner = (fill: string, size = 16) => ``; const turboprop = (fill: string, size = 16) => ``; const bizjet = (fill: string, size = 16) => ``; const heli = (fill: string, size = 16) => ``; const ship = (fill: string, size = 16) => ``; const triangle = (fill: string, size = 16) => ``; const circle = (fill: string, size = 16) => ``; const dot = (fill: string, size = 16) => ``; function IconImg({ svg }: { svg: string }) { return ( ); } // ─── Legend data ─── interface LegendItem { svg: string; label: string; } interface LegendCategory { name: string; color: string; items: LegendItem[]; } const sat = (fill: string, size = 16) => ``; const square = (fill: string, size = 16) => ``; const clusterCircle = (fill: string, stroke: string, size = 16) => `5`; const LEGEND: LegendCategory[] = [ { name: 'COMMERCIAL AVIATION', color: 'text-cyan-600 border-cyan-700/30', items: [ { svg: airliner('#0891b2'), label: 'Airliner (dim cyan — baseline)' }, { svg: turboprop('#0891b2'), label: 'Turboprop (dim cyan)' }, { svg: heli('#0891b2'), label: 'Helicopter (dim cyan)' }, { svg: airliner('#555'), label: 'Grounded / Parked (grey)' }, ], }, { name: 'PRIVATE / UNKNOWN AVIATION', color: 'text-purple-400 border-purple-500/30', items: [ { svg: airliner('#9B59B6'), label: 'Private Flight — Airliner (purple)' }, { svg: turboprop('#9B59B6'), label: 'Private Flight — Turboprop' }, { svg: bizjet('#9B59B6'), label: 'Private Jet — Bizjet' }, { svg: heli('#9B59B6'), label: 'Private / Unknown — Helicopter' }, ], }, { name: 'MILITARY AVIATION', color: 'text-amber-400 border-amber-500/30', items: [ { svg: airliner('#f59e0b'), label: 'Military — Standard (amber)' }, { svg: plane('#f59e0b'), label: 'Fighter / Interceptor (amber)' }, { svg: heli('#f59e0b'), label: 'Military — Helicopter (amber)' }, { svg: ``, label: 'UAV / Drone (live ADS-B)', }, ], }, { name: 'TRACKED AIRCRAFT (ALERT)', color: 'text-pink-400 border-pink-500/30', items: [ { svg: airliner('#FF1493'), label: 'VIP / Celebrity / Bizjet (hot pink)' }, { svg: airliner('#FF2020'), label: 'Dictator / Oligarch (red)' }, { svg: airliner('#3b82f6'), label: 'Government / Police / Customs (blue)' }, { svg: heli('#32CD32'), label: 'Medical / Fire / Rescue (lime)' }, { svg: airliner('yellow'), label: 'Military / Intelligence (yellow)' }, { svg: airliner('#222'), label: 'PIA — Privacy / Stealth (black)' }, { svg: airliner('#FF8C00'), label: 'Private Flights / Joe Cool (orange)' }, { svg: airliner('white'), label: 'Climate Crisis (white)' }, { svg: airliner('#9B59B6'), label: 'Private Jets / Historic / Other (purple)' }, ], }, { name: 'POTUS FLEET', color: 'text-yellow-400 border-yellow-500/30', items: [ { svg: ``, label: 'Air Force One / Two (gold ring)', }, { svg: ``, label: 'Marine One (gold ring + heli)', }, ], }, { name: 'SATELLITES', color: 'text-sky-400 border-sky-500/30', items: [ { svg: sat('#ff3333'), label: 'Military Recon / SAR (red)' }, { svg: sat('#00e5ff'), label: 'Synthetic Aperture Radar (cyan)' }, { svg: sat('#ffffff'), label: 'Signals Intelligence / ELINT (white)' }, { svg: sat('#4488ff'), label: 'Navigation — GPS / GLONASS / BeiDou (blue)' }, { svg: sat('#ff00ff'), label: 'Early Warning — Missile Detection (magenta)' }, { svg: sat('#44ff44'), label: 'Commercial Imaging (green)' }, { svg: sat('#ffdd00'), label: 'Space Station — ISS / Tiangong (gold)' }, { svg: sat('#aaaaaa'), label: 'Unclassified / Other (grey)' }, ], }, { name: 'MARITIME', color: 'text-blue-400 border-blue-500/30', items: [ { svg: ship('#ff2222'), label: 'Cargo / Tanker (red)' }, { svg: ship('#f59e0b'), label: 'Military Vessel (amber)' }, { svg: ship('white'), label: 'Cruise / Passenger / Yacht (white)' }, { svg: ship('#FF69B4'), label: 'Tracked Yacht (pink)' }, { svg: ship('#3b82f6'), label: 'Civilian / Unknown (blue)' }, { svg: ``, label: 'Aircraft Carrier (orange)', }, { svg: clusterCircle('#3b82f6', '#1d4ed8'), label: 'Ship Cluster (count inside)' }, ], }, { name: 'GEOPHYSICAL', color: 'text-orange-400 border-orange-500/30', items: [{ svg: circle('#ffcc00'), label: 'Earthquake (yellow blob, size = magnitude)' }], }, { name: 'WILDFIRES', color: 'text-red-400 border-red-500/30', items: [ { svg: ``, label: 'Active wildfire / hotspot', }, { svg: clusterCircle('#cc0000', '#ff3300'), label: 'Fire cluster (grouped hotspots)' }, ], }, { name: 'INCIDENTS & INTELLIGENCE', color: 'text-red-400 border-red-500/30', items: [ { svg: triangle('#ffaa00'), label: 'GDELT / LiveUA event (yellow)' }, { svg: triangle('#ff0000'), label: 'Violent / Kinetic event (red)' }, { svg: ``, label: 'Threat Alert (news cluster)', }, ], }, { name: 'NEWS & OSINT', color: 'text-cyan-400 border-cyan-500/30', items: [ { svg: `!! ALERTNews Headline`, label: 'Geolocated news alert box', }, ], }, { name: 'GPS JAMMING / INTERFERENCE', color: 'text-red-400 border-red-500/30', items: [ { svg: square('#ff0040'), label: 'High severity (>75% aircraft degraded)' }, { svg: ``, label: 'Medium severity (50-75% degraded)', }, { svg: ``, label: 'Low severity (25-50% degraded)', }, ], }, { name: 'INFRASTRUCTURE', color: 'text-purple-400 border-purple-500/30', items: [ { svg: ``, label: 'Data Center', }, { svg: circle('#888'), label: 'Internet Outage Zone (grey)' }, ], }, { name: 'SURVEILLANCE / CCTV', color: 'text-green-400 border-green-500/30', items: [ { svg: dot('#22c55e'), label: 'Individual CCTV camera (green dot)' }, { svg: clusterCircle('#22c55e', '#16a34a'), label: 'Camera cluster (count inside)' }, { svg: ``, label: 'CCTV icon (detail view)', }, ], }, { name: 'SELECTION HUD', color: 'text-cyan-400 border-cyan-500/30', items: [ { svg: ``, label: 'Predictive vector (~5 min ahead)', }, { svg: ``, label: 'Proximity rings (10 / 50 / 100nm)', }, { svg: ``, label: 'Flight trail (position history)', }, { svg: ``, label: 'Active route (origin → dest)', }, ], }, { name: 'SIGINT GRID', color: 'text-emerald-400 border-emerald-500/30', items: [ { svg: dot('#22c55e'), label: 'APRS-IS station (green, isnād 0.7)' }, { svg: triangle('#22c55e'), label: 'Meshtastic node (green triangle, isnād 0.5)' }, { svg: dot('#f59e0b'), label: 'JS8Call station (amber, isnād 0.9)' }, ], }, { name: 'ORACLE SERVICE', color: 'text-cyan-400 border-cyan-500/30', items: [ { svg: `ORCL:7.2`, label: 'Oracle score badge (weighted risk)', }, { svg: `MKT:23%`, label: 'Prediction market consensus', }, { svg: `▲`, label: 'Sentiment: ▲ positive / ▼ negative / — neutral', }, ], }, { name: 'OVERLAYS', color: 'text-gray-400 border-gray-500/30', items: [ { svg: ``, label: 'Day / Night terminator', }, { svg: ``, label: 'Ukraine frontline', }, ], }, ]; const MapLegend = React.memo(function MapLegend({ isOpen, onClose, }: { isOpen: boolean; onClose: () => void; }) { const { t } = useTranslation(); const [collapsed, setCollapsed] = useState>(new Set()); const toggle = (name: string) => { setCollapsed((prev) => { const next = new Set(prev); if (next.has(name)) next.delete(name); else next.add(name); return next; }); }; return ( {isOpen && ( <> {/* Backdrop */} {/* Legend Panel */} {/* Header */} {t('legend.title').toUpperCase()} ICON REFERENCE KEY {/* Legend Content */} {LEGEND.map((cat) => { const isCollapsed = collapsed.has(cat.name); return ( {/* Category Header */} toggle(cat.name)} className="w-full flex items-center justify-between px-3 py-2 bg-[var(--bg-secondary)]/50 hover:bg-[var(--bg-secondary)]/80 transition-colors" > {cat.name} {isCollapsed ? ( ) : ( )} {/* Items */} {!isCollapsed && ( {cat.items.map((item, idx) => ( {item.label} ))} )} ); })} {/* Footer */} {LEGEND.reduce((sum, c) => sum + c.items.length, 0)} ICON DEFINITIONS ACROSS{' '} {LEGEND.length} CATEGORIES > )} ); }); export default MapLegend;