fix(map,lightbox): center map above day detail panel and fix lightbox close

- Map pans up when DayDetailPanel is open so route markers aren't hidden
- Files lightbox: clicking dark background closes lightbox again
- Memories lightbox: clicking dark background closes lightbox again
This commit is contained in:
mauriceboe
2026-04-04 20:26:24 +02:00
parent 11b6974387
commit e4065c276b
4 changed files with 20 additions and 10 deletions

View File

@@ -120,9 +120,10 @@ function ImageLightbox({ files, initialIndex, onClose }: ImageLightboxProps) {
</div> </div>
{/* Main image + nav */} {/* Main image + nav */}
<div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative', minHeight: 0 }} onClick={e => e.stopPropagation()}> <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative', minHeight: 0 }}
onClick={e => { if (e.target === e.currentTarget) onClose() }}>
{navBtn('left', goPrev, hasPrev)} {navBtn('left', goPrev, hasPrev)}
{imgSrc && <img src={imgSrc} alt={file.original_name} style={{ maxWidth: '85vw', maxHeight: '80vh', objectFit: 'contain', borderRadius: 8, display: 'block' }} />} {imgSrc && <img src={imgSrc} alt={file.original_name} style={{ maxWidth: '85vw', maxHeight: '80vh', objectFit: 'contain', borderRadius: 8, display: 'block' }} onClick={e => e.stopPropagation()} />}
{navBtn('right', goNext, hasNext)} {navBtn('right', goNext, hasNext)}
</div> </div>

View File

@@ -161,12 +161,13 @@ function MapController({ center, zoom }: MapControllerProps) {
// Fit bounds when places change (fitKey triggers re-fit) // Fit bounds when places change (fitKey triggers re-fit)
interface BoundsControllerProps { interface BoundsControllerProps {
hasDayDetail?: boolean
places: Place[] places: Place[]
fitKey: number fitKey: number
paddingOpts: Record<string, number> paddingOpts: Record<string, number>
} }
function BoundsController({ places, fitKey, paddingOpts }: BoundsControllerProps) { function BoundsController({ places, fitKey, paddingOpts, hasDayDetail }: BoundsControllerProps) {
const map = useMap() const map = useMap()
const prevFitKey = useRef(-1) const prevFitKey = useRef(-1)
@@ -176,9 +177,14 @@ function BoundsController({ places, fitKey, paddingOpts }: BoundsControllerProps
if (places.length === 0) return if (places.length === 0) return
try { try {
const bounds = L.latLngBounds(places.map(p => [p.lat, p.lng])) const bounds = L.latLngBounds(places.map(p => [p.lat, p.lng]))
if (bounds.isValid()) map.fitBounds(bounds, { ...paddingOpts, maxZoom: 16, animate: true }) if (bounds.isValid()) {
map.fitBounds(bounds, { ...paddingOpts, maxZoom: 16, animate: true })
if (hasDayDetail) {
setTimeout(() => map.panBy([0, 150], { animate: true }), 300)
}
}
} catch {} } catch {}
}, [fitKey, places, paddingOpts, map]) }, [fitKey, places, paddingOpts, map, hasDayDetail])
return null return null
} }
@@ -377,17 +383,18 @@ export const MapView = memo(function MapView({
leftWidth = 0, leftWidth = 0,
rightWidth = 0, rightWidth = 0,
hasInspector = false, hasInspector = false,
hasDayDetail = false,
}) { }) {
// Dynamic padding: account for sidebars + bottom inspector // Dynamic padding: account for sidebars + bottom inspector + day detail panel
const paddingOpts = useMemo(() => { const paddingOpts = useMemo(() => {
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768 const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
if (isMobile) return { padding: [40, 20] } if (isMobile) return { padding: [40, 20] }
const top = 60 const top = 60
const bottom = hasInspector ? 320 : 60 const bottom = hasInspector ? 320 : hasDayDetail ? 280 : 60
const left = leftWidth + 40 const left = leftWidth + 40
const right = rightWidth + 40 const right = rightWidth + 40
return { paddingTopLeft: [left, top], paddingBottomRight: [right, bottom] } return { paddingTopLeft: [left, top], paddingBottomRight: [right, bottom] }
}, [leftWidth, rightWidth, hasInspector]) }, [leftWidth, rightWidth, hasInspector, hasDayDetail])
// photoUrls: only base64 thumbs for smooth map zoom // photoUrls: only base64 thumbs for smooth map zoom
const [photoUrls, setPhotoUrls] = useState<Record<string, string>>(getAllThumbs) const [photoUrls, setPhotoUrls] = useState<Record<string, string>>(getAllThumbs)
@@ -509,7 +516,7 @@ export const MapView = memo(function MapView({
/> />
<MapController center={center} zoom={zoom} /> <MapController center={center} zoom={zoom} />
<BoundsController places={dayPlaces.length > 0 ? dayPlaces : places} fitKey={fitKey} paddingOpts={paddingOpts} /> <BoundsController places={dayPlaces.length > 0 ? dayPlaces : places} fitKey={fitKey} paddingOpts={paddingOpts} hasDayDetail={hasDayDetail} />
<SelectionController places={places} selectedPlaceId={selectedPlaceId} dayPlaces={dayPlaces} paddingOpts={paddingOpts} /> <SelectionController places={places} selectedPlaceId={selectedPlaceId} dayPlaces={dayPlaces} paddingOpts={paddingOpts} />
<MapClickHandler onClick={onMapClick} /> <MapClickHandler onClick={onMapClick} />
<MapContextMenuHandler onContextMenu={onMapContextMenu} /> <MapContextMenuHandler onContextMenu={onMapContextMenu} />

View File

@@ -902,10 +902,11 @@ export default function MemoriesPanel({ tripId, startDate, endDate }: MemoriesPa
</button> </button>
)} )}
<div onClick={e => e.stopPropagation()} style={{ display: 'flex', gap: 16, alignItems: 'flex-start', justifyContent: 'center', padding: 20, width: '100%', height: '100%' }}> <div onClick={e => { if (e.target === e.currentTarget) closeLightbox() }} style={{ display: 'flex', gap: 16, alignItems: 'flex-start', justifyContent: 'center', padding: 20, width: '100%', height: '100%' }}>
<img <img
src={lightboxOriginalSrc} src={lightboxOriginalSrc}
alt="" alt=""
onClick={e => e.stopPropagation()}
style={{ maxWidth: (!isMobile && lightboxInfo) ? 'calc(100% - 280px)' : '100%', maxHeight: '100%', objectFit: 'contain', borderRadius: 10, cursor: 'default' }} style={{ maxWidth: (!isMobile && lightboxInfo) ? 'calc(100% - 280px)' : '100%', maxHeight: '100%', objectFit: 'contain', borderRadius: 10, cursor: 'default' }}
/> />

View File

@@ -598,6 +598,7 @@ export default function TripPlannerPage(): React.ReactElement | null {
leftWidth={leftCollapsed ? 0 : leftWidth} leftWidth={leftCollapsed ? 0 : leftWidth}
rightWidth={rightCollapsed ? 0 : rightWidth} rightWidth={rightCollapsed ? 0 : rightWidth}
hasInspector={!!selectedPlace} hasInspector={!!selectedPlace}
hasDayDetail={!!showDayDetail && !selectedPlace}
/> />