mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-30 18:46:00 +00:00
fix(map): keep the mobile GPS button above the day-detail panel (#1348)
On mobile the location (GPS) FAB sat at bottom: calc(var(--bottom-nav-h) + 12px),
which only clears the bottom nav. When a day is selected, DayDetailPanel slides
up over the map from bottom: navh+20 and spans nearly full width at z-index
10000, covering the button's band — so the button was hidden behind it.
DayDetailPanel now publishes its live measured height to a root CSS var
--day-panel-h (ResizeObserver, reset to 0 on unmount), and both map renderers
lift the button above the panel when it's open, reusing the hasDayDetail prop
they already receive:
hasDayDetail
? calc(var(--bottom-nav-h) + 20px + var(--day-panel-h) + 12px)
: calc(var(--bottom-nav-h) + 12px)
Applied to both the Leaflet (MapView) and GL (MapViewGL) renderers. When the
panel closes, hasDayDetail is false and the offset falls back to the bottom-nav
value. Desktop is unaffected — the button is mobile-only.
Tests: new DayDetailPanel case asserting --day-panel-h is published and reset on
unmount; client tsc clean, full client suite green (2851).
This commit is contained in:
@@ -569,7 +569,12 @@ export const MapView = memo(function MapView({
|
||||
// Desktop browsers only get IP-based geolocation (city-level accuracy),
|
||||
// so the button would be misleading. Mobile, where real GPS lives, keeps it.
|
||||
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
|
||||
const locationButtonBottom = 'calc(var(--bottom-nav-h, 84px) + 12px)'
|
||||
// When the day-detail panel is open it slides up over the map (bottom: navh+20,
|
||||
// height var(--day-panel-h)) and covers the button's band, so lift the button
|
||||
// above it; otherwise keep the plain bottom-nav offset. #1348
|
||||
const locationButtonBottom = hasDayDetail
|
||||
? 'calc(var(--bottom-nav-h, 84px) + 20px + var(--day-panel-h, 0px) + 12px)'
|
||||
: 'calc(var(--bottom-nav-h, 84px) + 12px)'
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -727,7 +727,12 @@ export function MapViewGL({
|
||||
// Desktop browsers only get IP-based geolocation (city-level accuracy),
|
||||
// so the button would be misleading. Mobile, where real GPS lives, keeps it.
|
||||
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
|
||||
const buttonBottom = 'calc(var(--bottom-nav-h, 84px) + 12px)'
|
||||
// When the day-detail panel is open it slides up over the map (bottom: navh+20,
|
||||
// height var(--day-panel-h)) and covers the button's band, so lift the button
|
||||
// above it; otherwise keep the plain bottom-nav offset. #1348
|
||||
const buttonBottom = hasDayDetail
|
||||
? 'calc(var(--bottom-nav-h, 84px) + 20px + var(--day-panel-h, 0px) + 12px)'
|
||||
: 'calc(var(--bottom-nav-h, 84px) + 12px)'
|
||||
|
||||
return (
|
||||
<div className="w-full h-full relative">
|
||||
|
||||
@@ -51,6 +51,16 @@ describe('DayDetailPanel', () => {
|
||||
expect(document.body).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('FE-PLANNER-DAYDETAIL-063: publishes its height to --day-panel-h and resets it on unmount (#1348)', () => {
|
||||
document.documentElement.style.removeProperty('--day-panel-h');
|
||||
const { unmount } = render(<DayDetailPanel {...defaultProps} />);
|
||||
// The panel publishes its measured height so the map's mobile GPS button can
|
||||
// sit above it instead of being hidden behind it.
|
||||
expect(document.documentElement.style.getPropertyValue('--day-panel-h')).not.toBe('');
|
||||
unmount();
|
||||
expect(document.documentElement.style.getPropertyValue('--day-panel-h')).toBe('0px');
|
||||
});
|
||||
|
||||
it('FE-PLANNER-DAYDETAIL-002: returns null when day prop is null', () => {
|
||||
render(<DayDetailPanel {...defaultProps} day={null as any} />);
|
||||
expect(document.querySelector('[style*="position: fixed"]')).toBeNull();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import React, { useState, useEffect, useRef } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { X, Sun, Cloud, CloudRain, CloudSnow, CloudDrizzle, CloudLightning, Wind, Droplets, Sunrise, Sunset, Hotel, Calendar, MapPin, LogIn, LogOut, Hash, Pencil, Plane, Utensils, Train, Car, Ship, Ticket, FileText, Users, ChevronsDown, ChevronsUp } from 'lucide-react'
|
||||
|
||||
@@ -86,6 +86,27 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri
|
||||
updateAccommodationField, handleRemoveAccommodation,
|
||||
} = useDayDetail(day, days, tripId, lat, lng, language, onAccommodationChange)
|
||||
|
||||
// Publish the panel's live height as a root CSS var so the map's mobile GPS
|
||||
// button can sit just above the panel instead of being hidden behind it (#1348).
|
||||
// The card grows/shrinks (collapse, content, ≤60vh), so track it live.
|
||||
const cardRef = useRef<HTMLDivElement | null>(null)
|
||||
useEffect(() => {
|
||||
const el = cardRef.current
|
||||
if (!el) return
|
||||
const root = document.documentElement
|
||||
const publish = () => root.style.setProperty('--day-panel-h', `${el.offsetHeight}px`)
|
||||
publish()
|
||||
let ro: ResizeObserver | undefined
|
||||
if (typeof ResizeObserver !== 'undefined') {
|
||||
ro = new ResizeObserver(publish)
|
||||
ro.observe(el)
|
||||
}
|
||||
return () => {
|
||||
ro?.disconnect()
|
||||
root.style.setProperty('--day-panel-h', '0px')
|
||||
}
|
||||
}, [])
|
||||
|
||||
if (!day) return null
|
||||
|
||||
const formattedDate = day.date ? new Date(day.date + 'T00:00:00Z').toLocaleDateString(
|
||||
@@ -98,7 +119,7 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri
|
||||
|
||||
return (
|
||||
<div className="fixed z-50" style={{ bottom: 'calc(var(--bottom-nav-h) + 20px)', left: `calc(${leftWidth}px + (100vw - ${leftWidth}px - ${rightWidth}px) / 2)`, transform: 'translateX(-50%)', width: `min(800px, calc(100vw - ${leftWidth}px - ${rightWidth}px - 32px))`, ...(mobile ? { zIndex: 10000 } : null), ...font }}>
|
||||
<div className="bg-surface-elevated" style={{
|
||||
<div ref={cardRef} className="bg-surface-elevated" style={{
|
||||
backdropFilter: 'blur(40px) saturate(180%)',
|
||||
WebkitBackdropFilter: 'blur(40px) saturate(180%)',
|
||||
borderRadius: 20,
|
||||
|
||||
Reference in New Issue
Block a user