feat: Consolidated UX improvements for map selection

- Snap selection to feature geometry when clicking labeled places
- Add wikidata enrichment for basemap labels (population, description)
- Differentiate visual feedback: reticle marker vs pulsing highlight
- Clear previous feature highlight when selection changes
- Store selection mode (reticle/feature) and feature info in state

Frontend: MapView click handler, PlaceDetail wikidata fetch, CSS
Backend: /api/place/wikidata/<id> route for Wikidata API lookups

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Matt 2026-04-26 08:15:09 +00:00
commit b354fd0aa0
5 changed files with 123 additions and 20 deletions

View file

@ -6,7 +6,7 @@ import {
import OpeningHours from 'opening_hours'
import toast from 'react-hot-toast'
import { useStore } from '../store'
import { fetchElevation, fetchPlaceDetails, fetchDriveTime, fetchNearbyContacts, fetchLandclass } from '../api'
import { fetchElevation, fetchPlaceDetails, fetchPlaceByWikidata, fetchDriveTime, fetchNearbyContacts, fetchLandclass } from '../api'
import { hasFeature } from '../config'
import { buildAddress } from '../utils/place'
@ -480,6 +480,35 @@ export default function PlaceDetail() {
return () => controller.abort()
}, [osmType, osmId])
// Fetch wikidata enrichment when place has wikidata but no OSM details
const wikidataId = selectedPlace?.wikidata || selectedPlace?.raw?.wikidata
useEffect(() => {
// Skip if OSM details are available (they provide richer data)
if (osmType && osmId) return
// Skip if no wikidata ID
if (!wikidataId) return
const controller = new AbortController()
fetchPlaceByWikidata(wikidataId, controller.signal).then((data) => {
if (!controller.signal.aborted && data) {
// Merge wikidata info into placeDetails (description, population, etc.)
setPlaceDetails((prev) => ({
...(prev === 'loading' ? {} : prev || {}),
description: data.description,
population: data.population,
osm_relation_id: data.osm_relation_id,
extratags: {
...(prev && prev !== 'loading' ? prev.extratags : {}),
...data.extratags,
},
}))
}
})
return () => controller.abort()
}, [wikidataId, osmType, osmId])
// Fetch drive time when place or user location changes
useEffect(() => {
if (!userLocation || placeLat == null || placeLon == null) {