feat(renderer): interactive map with Leaflet + OpenStreetMap (M10.3)

- MapRenderer.vue: lazy-loads Leaflet, renders OSM tiles
- Orange marker pins for all places with coordinates
- Place list sidebar on desktop, popup on click
- "View on map" button in chat messages with places
- Integrated into content panel via openMapView()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-03 23:52:16 +00:00
co-authored by Claude Opus 4.6
parent 7a3d874f5e
commit aec87a347c
6 changed files with 189 additions and 2 deletions
@@ -99,6 +99,11 @@
:title="pdfUrl.title"
@back="closePdfViewer"
/>
<MapRenderer
v-else-if="mapPlaces.length > 0"
:places="mapPlaces"
@back="closeMapView"
/>
<!-- Grid views by active tab -->
<component
@@ -184,6 +189,7 @@ import NewsGrid from './NewsGrid.vue'
import ArticleDetail from './ArticleDetail.vue'
import ArticleReader from '@/components/renderers/ArticleReader.vue'
import PdfViewer from '@/components/renderers/PdfViewer.vue'
import MapRenderer from '@/components/renderers/MapRenderer.vue'
import MagazineGrid from './MagazineGrid.vue'
import ProjectGrid from './ProjectGrid.vue'
import NostrGrid from './NostrGrid.vue'
@@ -236,11 +242,13 @@ const {
closeLongFormArticle,
pdfUrl,
closePdfViewer,
mapPlaces,
closeMapView,
closePanel,
} = useContentPanel()
const hasDetailOpen = computed(() =>
!!(selectedFilm.value || selectedBook.value || selectedTVSeries.value || selectedSong.value || selectedPodcast.value || selectedArticle.value || selectedDesignSystemItem.value || longFormArticle.value || pdfUrl.value)
!!(selectedFilm.value || selectedBook.value || selectedTVSeries.value || selectedSong.value || selectedPodcast.value || selectedArticle.value || selectedDesignSystemItem.value || longFormArticle.value || pdfUrl.value || mapPlaces.value.length > 0)
)
const windowWidth = ref(window.innerWidth)