"use client"; import { useState, useCallback, useRef, useEffect } from "react"; import { motion, AnimatePresence } from "motion/react"; import { Info } from "lucide-react"; import { getAttributions, type AttributionEntry } from "@/lib/map-styles"; type MapAttributionProps = { styleId: string; }; const SM_BREAKPOINT = 640; export function MapAttribution({ styleId }: MapAttributionProps) { const [expanded, setExpanded] = useState(false); const attributions = getAttributions(styleId); const containerRef = useRef(null); const toggle = useCallback(() => setExpanded((prev) => !prev), []); // Expand by default on larger screens (after mount to avoid hydration mismatch) useEffect(() => { const mq = window.matchMedia(`(min-width: ${SM_BREAKPOINT}px)`); const sync = () => setExpanded(mq.matches); const raf = window.requestAnimationFrame(sync); mq.addEventListener("change", sync); return () => { window.cancelAnimationFrame(raf); mq.removeEventListener("change", sync); }; }, []); // Close on outside click for small screens useEffect(() => { if (!expanded) return; function handlePointerDown(e: PointerEvent) { if ( window.innerWidth >= SM_BREAKPOINT || !containerRef.current || containerRef.current.contains(e.target as Node) ) return; setExpanded(false); } document.addEventListener("pointerdown", handlePointerDown); return () => document.removeEventListener("pointerdown", handlePointerDown); }, [expanded]); return (
{expanded ? ( ) : ( )}
); } function CollapsedAttribution({ onExpand }: { onExpand: () => void }) { return ( ); } function ExpandedAttribution({ attributions, onCollapse, }: { attributions: AttributionEntry[]; onCollapse: () => void; }) { return ( © {attributions.map((attr, i) => ( {attr.label} {i < attributions.length - 1 && ( · )} ))} · OpenSky Network ); }