trails/apps/planner/app/components/NearbyPoiMarkers.tsx
Ullrich Schäfer c2abb64ee0
Add per-waypoint notes and nearby POI snap to Planner
- `note` field on Waypoint type, stored in Yjs Y.Map and exported as
  `<desc>` inside `<wpt>` in GPX
- Inline textarea note editing in WaypointSidebar with auto-resize,
  character counter (500 max), save-on-blur, Escape cancel
- Note indicator dot on map markers; note tooltip on hover
- `useNearbyPois` hook: fetches POIs within 500m of selected waypoint
  via Overpass proxy, 500ms debounce, AbortController, 60s rate-limit
  suppression
- NearbyPoiMarkers component: renders POI markers on map for selected
  waypoint with snap-to-POI on click
- Nearby section in WaypointSidebar: list with snap buttons, spinner,
  empty/rate-limited states, "Show more" toggle (5 → all)
- Unit tests for fetchNearbyPois bbox geometry and snap-to-POI Yjs
  transaction behaviour

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:58:21 +02:00

49 lines
1.4 KiB
TypeScript

import L from "leaflet";
import { Marker, Tooltip } from "react-leaflet";
import type { Poi } from "~/lib/overpass";
import type { PoiCategory } from "@trails-cool/map-core";
interface NearbyPoiMarkersProps {
pois: Poi[];
categories: PoiCategory[];
onSnap: (poi: Poi) => void;
}
function nearbyPoiIcon(color: string, icon: string): L.DivIcon {
return L.divIcon({
className: "",
html: `<div style="
width:18px;height:18px;border-radius:50%;
background:${color};color:white;
display:flex;align-items:center;justify-content:center;
font-size:10px;
border:1.5px solid white;box-shadow:0 1px 3px rgba(0,0,0,0.25);
transform:translate(-9px,-9px);
">${icon}</div>`,
iconSize: [0, 0],
});
}
export function NearbyPoiMarkers({ pois, categories, onSnap }: NearbyPoiMarkersProps) {
return (
<>
{pois.map((poi) => {
const cat = categories.find((c) => c.id === poi.category);
if (!cat) return null;
return (
<Marker
key={poi.id}
position={[poi.lat, poi.lon]}
icon={nearbyPoiIcon(cat.color, cat.icon)}
eventHandlers={{ click: () => onSnap(poi) }}
zIndexOffset={900}
>
<Tooltip direction="top" offset={[0, -10]} opacity={0.95}>
<span>{poi.name ?? cat.icon} {cat.icon !== poi.name ? cat.icon : ""}</span>
</Tooltip>
</Marker>
);
})}
</>
);
}