fix(map): transit polish — earlier label collapse, route-toggle coupling, md note preview

Station badges on transit journeys collapse to icon dots much earlier when
zooming out (label threshold 900px instead of 400). The drawn transit paths
now ride the day-route toggle: turning the route off hides them too, since
they are part of the computed route. The journey card's note preview renders
its first line as inline markdown instead of raw asterisks.
This commit is contained in:
Maurice
2026-07-02 23:41:37 +02:00
committed by Maurice
parent fab288a889
commit 440bb8497f
6 changed files with 17 additions and 9 deletions
+5 -3
View File
@@ -428,6 +428,7 @@ export const MapView = memo(function MapView({
reservations = [] as Reservation[],
showReservationStats = false,
visibleConnectionIds = [] as number[],
showTransitRoutes = true,
onReservationClick,
pois = [] as Poi[],
onPoiClick,
@@ -446,9 +447,10 @@ export const MapView = memo(function MapView({
)), [pois, onPoiClick])
const visibleReservations = useMemo(() => {
const set = new Set(visibleConnectionIds || [])
// Transit journeys are part of the plan itself — always on the map (#1065).
return reservations.filter((r: Reservation) => r.type === 'transit' || set.has(r.id))
}, [reservations, visibleConnectionIds])
// Transit journeys ride the route toggle — they are part of the computed
// day route, so hiding the route hides them too (#1065).
return reservations.filter((r: Reservation) => (r.type === 'transit' && showTransitRoutes) || set.has(r.id))
}, [reservations, visibleConnectionIds, showTransitRoutes])
// Dynamic padding: account for sidebars + bottom inspector + day detail panel
const paddingOpts = useMemo((): L.FitBoundsOptions => {
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
+6 -3
View File
@@ -81,6 +81,7 @@ interface Props {
hasDayDetail?: boolean
reservations?: Reservation[]
visibleConnectionIds?: number[]
showTransitRoutes?: boolean
showReservationStats?: boolean
onReservationClick?: (reservationId: number) => void
pois?: Poi[]
@@ -199,6 +200,7 @@ export function MapViewGL({
hasDayDetail = false,
reservations = [],
visibleConnectionIds = [],
showTransitRoutes = true,
showReservationStats = false,
onReservationClick,
pois = [],
@@ -801,9 +803,10 @@ export function MapViewGL({
// booking's route, matching the Leaflet MapView's behaviour.
const visibleReservations = useMemo(() => {
const set = new Set(visibleConnectionIds || [])
// Transit journeys are part of the plan itself — always on the map (#1065).
return reservations.filter(r => r.type === 'transit' || set.has(r.id))
}, [reservations, visibleConnectionIds])
// Transit journeys ride the route toggle — they are part of the computed
// day route, so hiding the route hides them too (#1065).
return reservations.filter(r => (r.type === 'transit' && showTransitRoutes) || set.has(r.id))
}, [reservations, visibleConnectionIds, showTransitRoutes])
useEffect(() => {
const map = mapRef.current
@@ -414,7 +414,7 @@ export default function ReservationOverlay({ reservations, showConnections, show
for (const item of visibleItems) {
const fromPx = map.latLngToContainerPoint([item.from.lat, item.from.lng])
const toPx = map.latLngToContainerPoint([item.to.lat, item.to.lng])
const minPx = item.type === 'flight' ? 50 : item.type === 'cruise' ? 300 : item.type === 'car' ? 150 : 400
const minPx = item.type === 'flight' ? 50 : item.type === 'cruise' ? 300 : item.type === 'car' ? 150 : item.type === 'transit' ? 900 : 400
if (fromPx.distanceTo(toPx) >= minPx) set.add(item.res.id)
}
return set
@@ -331,7 +331,7 @@ export class ReservationMapboxOverlay {
const toPx = map.project([item.to.lng, item.to.lat])
const dx = fromPx.x - toPx.x, dy = fromPx.y - toPx.y
const dist = Math.sqrt(dx * dx + dy * dy)
const minPx = item.type === 'flight' ? 50 : item.type === 'cruise' ? 300 : item.type === 'car' ? 150 : 400
const minPx = item.type === 'flight' ? 50 : item.type === 'cruise' ? 300 : item.type === 'car' ? 150 : item.type === 'transit' ? 900 : 400
if (dist >= minPx) labelVisibleIds.add(item.res.id)
} catch { /* ignore */ }
}
@@ -561,7 +561,9 @@ function TransitJourneyCard({ r, days, onOpen, onDelete, canEdit }: {
{r.notes && (
<div className="text-content-faint" style={{ paddingLeft: 44, display: 'flex', alignItems: 'center', gap: 5, fontSize: 'calc(11px * var(--fs-scale-caption, 1))', minWidth: 0 }}>
<StickyNote size={11} style={{ flexShrink: 0 }} />
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r.notes.split('\n')[0]}</span>
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
<Markdown remarkPlugins={[remarkGfm]} allowedElements={['strong', 'em', 'del', 'code', 'a']} unwrapDisallowed>{r.notes.split('\n')[0]}</Markdown>
</span>
</div>
)}
{confirmOpen && ReactDOM.createPortal(
+1
View File
@@ -304,6 +304,7 @@ export default function TripPlannerPage(): React.ReactElement | null {
places={mapPlaces}
dayPlaces={dayPlaces}
route={route}
showTransitRoutes={routeShown}
routeSegments={routeSegments}
selectedPlaceId={selectedPlaceId}
onMarkerClick={handleMarkerClick}