feat: map view stacks top/bottom + sorts photos by distance to center

Column layout: map on top, photos on bottom — applies on desktop and
mobile. Bounds-filtered photo list is now sorted by distance from the
current map center, so photos closest to where you're looking show up
first and the list re-sorts automatically as you pan or zoom.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-04-17 12:53:49 -04:00
parent e55703ea6e
commit 4cb479404a
1 changed files with 13 additions and 13 deletions

View File

@ -136,24 +136,17 @@
max-width: 1440px; width: 100%; margin: 0 auto;
}
#live-search-panel .ls-body.ls-split {
display: flex; flex-direction: row; gap: 12px;
display: flex; flex-direction: column; gap: 12px;
overflow: hidden;
}
#live-search-panel .ls-body.ls-split > .ls-map-wrap {
flex: 0 0 50%; height: 100%; min-height: 0;
flex: 1 1 50%; width: 100%; min-height: 0;
}
#live-search-panel .ls-body.ls-split > .ls-grid {
flex: 1 1 50%; overflow-y: auto; align-content: start;
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
}
@media (max-width: 768px) {
#live-search-panel .ls-body.ls-split {
flex-direction: column;
}
#live-search-panel .ls-body.ls-split > .ls-map-wrap,
#live-search-panel .ls-body.ls-split > .ls-grid {
flex: 1 1 50%;
}
#live-search-panel .ls-body.ls-split > .ls-grid {
grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
}
@ -572,21 +565,28 @@
// Fix map sizing (Leaflet needs this after dynamic show)
setTimeout(() => mapInstance.invalidateSize(), 100);
// Bounds-filtered grid on the other half of the split. Updates live
// as the user pans/zooms so "photos taken on that part of the map"
// stay in sync with the visible viewport.
// Bounds-filtered grid below the map. Updates live as the user
// pans/zooms so "photos taken on that part of the map" stay in sync
// with the visible viewport. Sorted by distance from map center so the
// closest-to-middle photos appear first.
const updateGridFromBounds = () => {
if (currentView !== 'map') return;
const b = mapInstance.getBounds();
const center = mapInstance.getCenter();
const visible = geoItems.filter(i =>
b.contains([i.exifInfo.latitude, i.exifInfo.longitude])
);
visible.sort((a, b1) => {
const da = center.distanceTo([a.exifInfo.latitude, a.exifInfo.longitude]);
const db = center.distanceTo([b1.exifInfo.latitude, b1.exifInfo.longitude]);
return da - db;
});
renderGridItems(visible);
const statusEl = panel.querySelector('.ls-status');
if (statusEl) {
const totalGeo = geoItems.length;
statusEl.textContent =
visible.length + ' of ' + totalGeo + ' shown in view';
visible.length + ' of ' + totalGeo + ' in view (closest to center first)';
}
};
mapInstance.on('moveend', updateGridFromBounds);