"use client"; import React, { useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { X, ChevronDown, ChevronUp } from "lucide-react"; // ─── 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-400 border-cyan-500/30", items: [ { svg: airliner("cyan"), label: "Airliner (swept wings)" }, { svg: turboprop("cyan"), label: "Turboprop (straight wings)" }, { svg: heli("cyan"), label: "Helicopter (rotor disc)" }, { svg: airliner("#555"), label: "Grounded / Parked (grey)" }, ], }, { name: "PRIVATE AVIATION", color: "text-orange-400 border-orange-500/30", items: [ { svg: airliner("#FF8C00"), label: "Private Flight — Airliner" }, { svg: turboprop("#FF8C00"), label: "Private Flight — Turboprop" }, { svg: heli("#FF8C00"), label: "Private Flight — Helicopter" }, ], }, { name: "PRIVATE JETS", color: "text-purple-400 border-purple-500/30", items: [ { svg: bizjet("#9B59B6"), label: "Private Jet — Bizjet" }, { svg: airliner("#9B59B6"), label: "Private Jet — Airliner" }, { svg: turboprop("#9B59B6"), label: "Private Jet — Turboprop" }, ], }, { name: "MILITARY AVIATION", color: "text-yellow-400 border-yellow-500/30", items: [ { svg: airliner("yellow"), label: "Military — Standard" }, { svg: plane("yellow"), label: "Fighter / Interceptor" }, { svg: heli("yellow"), label: "Military — Helicopter" }, { 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("gray"), label: "Civilian / Unknown Vessel" }, { svg: ship("yellow"), label: "Tanker" }, { svg: ship("#ff2222"), label: "Military Vessel" }, { svg: ship("#3b82f6"), label: "Cargo Ship" }, { svg: ship("white"), label: "Cruise / Passenger" }, { svg: ``, label: "Aircraft Carrier" }, { 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: "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 [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 */} MAP LEGEND 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;