import { Subtle } from "@app/components/UI/Typography/Subtle.tsx"; import { NodeDetail } from "@app/components/PageComponents/Map/NodeDetail"; import { cn } from "@app/core/utils/cn.ts"; import { PageLayout } from "@components/PageLayout.tsx"; import { Sidebar } from "@components/Sidebar.tsx"; import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.tsx"; import { SidebarButton } from "@components/UI/Sidebar/sidebarButton.tsx"; import { useAppStore } from "@core/stores/appStore.ts"; import { useDevice } from "@core/stores/deviceStore.ts"; import { Hashicon } from "@emeraldpay/hashicon-react"; import { numberToHexUnpadded } from "@noble/curves/abstract/utils"; import { bbox, lineString } from "@turf/turf"; import { BoxSelectIcon, MapPinIcon, ZoomInIcon, ZoomOutIcon, } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { AttributionControl, Marker, Popup, useMap } from "react-map-gl"; import MapGl from "react-map-gl/maplibre"; import { Protobuf } from "@meshtastic/js"; export const MapPage = (): JSX.Element => { const { nodes, waypoints } = useDevice(); const { rasterSources, darkMode } = useAppStore(); const { default: map } = useMap(); const [zoom, setZoom] = useState(0); const [selectedNode, setSelectedNode] = useState(null); const allNodes = Array.from(nodes.values()); const getBBox = useCallback(() => { if (!map) { return; } const nodesWithPosition = allNodes.filter( (node) => node.position?.latitudeI, ); if (!nodesWithPosition.length) { return; } if (nodesWithPosition.length === 1) { map.easeTo({ zoom: 12, center: [ (nodesWithPosition[0].position?.longitudeI ?? 0) / 1e7, (nodesWithPosition[0].position?.latitudeI ?? 0) / 1e7, ], }); return; } const line = lineString( nodesWithPosition.map((n) => [ (n.position?.latitudeI ?? 0) / 1e7, (n.position?.longitudeI ?? 0) / 1e7, ]), ); const bounds = bbox(line); const center = map.cameraForBounds( [ [bounds[1], bounds[0]], [bounds[3], bounds[2]], ], { padding: { top: 10, bottom: 10, left: 10, right: 10 } }, ); if (center) { map.easeTo(center); } }, [allNodes, map]); useEffect(() => { map?.on("zoom", () => { setZoom(map?.getZoom() ?? 0); }); }, [map]); useEffect(() => { map?.on("load", () => { getBBox(); }); }, [map, getBBox]); return ( <> {rasterSources.map((source) => ( ))} { // const waypoint = new Protobuf.Waypoint({ // name: "test", // description: "test description", // latitudeI: Math.trunc(e.lngLat.lat * 1e7), // longitudeI: Math.trunc(e.lngLat.lng * 1e7) // }); // addWaypoint(waypoint); // connection?.sendWaypoint(waypoint, "broadcast"); // }} // @ts-ignore attributionControl={false} renderWorldCopies={false} maxPitch={0} style={{ filter: darkMode ? "brightness(0.6) invert(1) contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.7)" : "", }} dragRotate={false} touchZoomRotate={false} initialViewState={{ zoom: 1.6, latitude: 35, longitude: 0, }} > {waypoints.map((wp) => (
))} {/* {rasterSources.map((source, index) => ( ))} */} {allNodes.map((node) => { if (node.position?.latitudeI && node.num !== selectedNode?.num) { return ( { setSelectedNode(node); map?.easeTo({ zoom: 12, center: [ (node.position?.longitudeI ?? 0) / 1e7, (node.position?.latitudeI ?? 0) / 1e7, ], }); }} >
{node.user?.longName || `!${numberToHexUnpadded(node.num)}`}
); } })} {selectedNode?.position && ( setSelectedNode(null)} > )}
); };