feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
import { useEffect, useRef, useCallback } from 'react'
|
|
|
|
|
import { useStore } from './store'
|
2026-04-20 20:59:18 +00:00
|
|
|
import { useTheme } from './hooks/useTheme'
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
import { requestRoute } from './api'
|
|
|
|
|
import { decodePolyline } from './utils/decode'
|
|
|
|
|
import MapView from './components/MapView'
|
|
|
|
|
import Panel from './components/Panel'
|
2026-04-20 20:59:18 +00:00
|
|
|
import PlaceDetail from './components/PlaceDetail'
|
2026-04-21 00:52:20 +00:00
|
|
|
import LayerControl from './components/LayerControl'
|
2026-04-20 04:47:44 +00:00
|
|
|
|
|
|
|
|
export default function App() {
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
const mapViewRef = useRef(null)
|
|
|
|
|
const routeDebounceRef = useRef(null)
|
2026-04-20 04:47:44 +00:00
|
|
|
|
2026-04-20 20:59:18 +00:00
|
|
|
// Initialize theme system
|
|
|
|
|
useTheme()
|
|
|
|
|
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
const stops = useStore((s) => s.stops)
|
|
|
|
|
const mode = useStore((s) => s.mode)
|
|
|
|
|
const route = useStore((s) => s.route)
|
2026-04-20 20:59:18 +00:00
|
|
|
const gpsOrigin = useStore((s) => s.gpsOrigin)
|
|
|
|
|
const geoPermission = useStore((s) => s.geoPermission)
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
const setRoute = useStore((s) => s.setRoute)
|
|
|
|
|
const setRouteLoading = useStore((s) => s.setRouteLoading)
|
|
|
|
|
const setRouteError = useStore((s) => s.setRouteError)
|
|
|
|
|
const clearRoute = useStore((s) => s.clearRoute)
|
|
|
|
|
const setUserLocation = useStore((s) => s.setUserLocation)
|
|
|
|
|
const setGeoPermission = useStore((s) => s.setGeoPermission)
|
|
|
|
|
|
2026-04-20 20:59:18 +00:00
|
|
|
// Proactive geolocation request on mount
|
|
|
|
|
useEffect(() => {
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
if (!navigator.geolocation) {
|
|
|
|
|
setGeoPermission('denied')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
navigator.geolocation.getCurrentPosition(
|
|
|
|
|
(pos) => {
|
|
|
|
|
setUserLocation({ lat: pos.coords.latitude, lon: pos.coords.longitude })
|
|
|
|
|
setGeoPermission('granted')
|
2026-04-20 04:47:44 +00:00
|
|
|
},
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
() => setGeoPermission('denied'),
|
2026-04-20 20:59:18 +00:00
|
|
|
{ enableHighAccuracy: false, timeout: 8000, maximumAge: 300000 }
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
)
|
|
|
|
|
}, [setUserLocation, setGeoPermission])
|
|
|
|
|
|
2026-04-20 20:59:18 +00:00
|
|
|
// Fetch route when stops, mode, gpsOrigin, or geoPermission change (debounced 500ms)
|
|
|
|
|
// NOTE: userLocation is NOT a dep — read from store inside the callback to avoid re-routing on every GPS update
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (routeDebounceRef.current) clearTimeout(routeDebounceRef.current)
|
|
|
|
|
|
|
|
|
|
routeDebounceRef.current = setTimeout(async () => {
|
2026-04-20 20:59:18 +00:00
|
|
|
const { userLocation } = useStore.getState()
|
|
|
|
|
|
|
|
|
|
// Build effective stop list
|
|
|
|
|
let effective = stops.map((s) => ({ lat: s.lat, lon: s.lon }))
|
|
|
|
|
if (gpsOrigin && geoPermission === 'granted' && userLocation) {
|
|
|
|
|
effective = [{ lat: userLocation.lat, lon: userLocation.lon }, ...effective]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (effective.length < 2) {
|
|
|
|
|
clearRoute()
|
|
|
|
|
return
|
|
|
|
|
}
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
|
|
|
|
|
setRouteLoading(true)
|
2026-04-20 04:47:44 +00:00
|
|
|
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
try {
|
2026-04-20 20:59:18 +00:00
|
|
|
const data = await requestRoute(effective, mode)
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
if (data.trip) {
|
|
|
|
|
setRoute(data.trip)
|
|
|
|
|
} else {
|
|
|
|
|
setRouteError('No route returned')
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
setRouteError(e.message || 'Route request failed')
|
|
|
|
|
} finally {
|
|
|
|
|
setRouteLoading(false)
|
|
|
|
|
}
|
|
|
|
|
}, 500)
|
2026-04-20 04:47:44 +00:00
|
|
|
|
|
|
|
|
return () => {
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
if (routeDebounceRef.current) clearTimeout(routeDebounceRef.current)
|
2026-04-20 04:47:44 +00:00
|
|
|
}
|
2026-04-20 20:59:18 +00:00
|
|
|
}, [stops, mode, gpsOrigin, geoPermission, clearRoute, setRoute, setRouteLoading, setRouteError])
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
|
|
|
|
|
// Handle maneuver click — fly to that point on the map
|
|
|
|
|
const handleManeuverClick = useCallback(
|
|
|
|
|
(maneuver) => {
|
|
|
|
|
if (!route || !route.legs) return
|
|
|
|
|
|
|
|
|
|
const legIdx = maneuver._legIndex || 0
|
|
|
|
|
const leg = route.legs[legIdx]
|
|
|
|
|
if (!leg || !leg.shape) return
|
|
|
|
|
|
|
|
|
|
const coords = decodePolyline(leg.shape, 6)
|
|
|
|
|
const idx = maneuver.begin_shape_index
|
|
|
|
|
if (idx >= 0 && idx < coords.length) {
|
|
|
|
|
const [lng, lat] = coords[idx]
|
|
|
|
|
mapViewRef.current?.flyTo(lat, lng, 15)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
[route]
|
|
|
|
|
)
|
2026-04-20 04:47:44 +00:00
|
|
|
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
return (
|
2026-04-20 20:59:18 +00:00
|
|
|
<div className="relative w-screen h-screen overflow-hidden" style={{ background: 'var(--bg-base)' }}>
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
<MapView ref={mapViewRef} />
|
|
|
|
|
<Panel onManeuverClick={handleManeuverClick} />
|
2026-04-20 20:59:18 +00:00
|
|
|
<PlaceDetail />
|
2026-04-21 00:52:20 +00:00
|
|
|
<LayerControl mapRef={mapViewRef} />
|
feat: search, multi-stop routing, and route display
Full navigation UI with:
- Search bar with 150ms debounced autocomplete from /api/geocode
- Keyboard navigation (arrow keys, Enter, Escape)
- Exact match badge for verified address results
- Multi-stop list with drag-to-reorder (dnd-kit)
- 10-stop cap with disabled state
- Mode selector (drive/walk/bike)
- Valhalla route display with per-leg color polyline
- Maneuver list with instructions, distance, time remaining
- Click maneuver to fly map to that point
- Optimize stops button (3+ stops, uses /optimized_route)
- Responsive: side panel (desktop ≥768px), bottom sheet (mobile)
- Stop pins: green origin, red destination, blue intermediate
- Pin popup with remove button
- Geolocation permission requested on first route, not on load
- Error handling for unroutable pairs
- nginx proxy for /api/ and /valhalla/ endpoints
Dependencies added: zustand, @dnd-kit/core, @dnd-kit/sortable,
@dnd-kit/utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 16:50:53 +00:00
|
|
|
</div>
|
|
|
|
|
)
|
2026-04-20 04:47:44 +00:00
|
|
|
}
|