fix(mobile): the map compass stands above the base-layer switcher

Beside it the two round controls read as one crowded row over the dock; on the switcher's own left edge, one gap above it, they form a column.
This commit is contained in:
Maurice
2026-10-01 10:38:29 +02:00
parent 94447fa011
commit 52934a8326
2 changed files with 17 additions and 20 deletions
+11 -11
View File
@@ -21,11 +21,13 @@ import type { ViewportPadding } from '../../../../utils/mapViewport'
const NO_POIS: Poi[] = []
/**
* The compass stands one gap to the right of the base-layer switcher both engines draw
* in the bottom left corner. Worked out from the switcher's own numbers rather than
* written down as 70, so moving or resizing the switcher carries the compass along.
* The compass stands one gap above the base-layer switcher both engines draw in the
* bottom left corner, on the same left edge, so the two round controls form a column
* instead of a row. Worked out from the switcher's own numbers, so moving or resizing
* the switcher carries the compass along.
*/
const COMPASS_LEFT = MAP_LAYER_SWITCHER_INSET + MAP_ROUND_CONTROL_SIZE + 8
const COMPASS_LEFT = MAP_LAYER_SWITCHER_INSET
const COMPASS_RAISE = MAP_ROUND_CONTROL_SIZE + 8
/** The safe-area insets at the top and the bottom of the screen, in pixels. */
interface SafeInsets {
@@ -436,14 +438,12 @@ export default function MMapArea({ planner, shell }: MMapAreaProps) {
)}
{/* Compass, GL maps only (Leaflet cannot rotate). Both engines draw the base-layer
switcher in the bottom left corner, so the compass sits beside it rather than in
the corner: at `left-3` it started 8px left of the switcher and ran on under it,
reading as a second button showing through the frosted shell. Same
--bottom-nav-h band as the locate button's `right: 12`, so the round controls
still share one line. The left offset is inline because it is computed from the
switcher's own numbers. */}
switcher in the bottom left corner, so the compass stands on top of it, on the
same left edge: beside it the two read as one crowded row next to the dock.
The offsets are inline because they are computed from the switcher's own
numbers. */}
{mapActive && glMap && (
<div className="pointer-events-none absolute z-[25]" style={{ left: COMPASS_LEFT, bottom: 'calc(var(--bottom-nav-h, 84px) + 12px)' }}>
<div className="pointer-events-none absolute z-[25]" style={{ left: COMPASS_LEFT, bottom: `calc(var(--bottom-nav-h, 84px) + ${12 + COMPASS_RAISE}px)` }}>
<MapCompassPill map={glMap} />
</div>
)}
@@ -194,15 +194,12 @@ describe('MMapArea', () => {
expect(segment.style.flexGrow).toBe('1')
})
it('FE-MOB-MAPAREA-002: the compass rides the same bottom offset as the locate button', () => {
it('FE-MOB-MAPAREA-002: the compass stands on top of the base-layer switcher', () => {
const { container } = renderArea()
// LocationButton hard-codes `right: 12` off the same variable, so matching
// the offset here is what keeps the two round controls on one line.
expect(compassBand(container)?.style.bottom).toBe('calc(var(--bottom-nav-h, 84px) + 12px)')
// Beside the base-layer switcher both engines draw in the corner: its inset, its
// size and one gap. In the corner itself it lay under the switcher's frosted shell.
expect(compassBand(container)?.style.left).toBe(`${MAP_LAYER_SWITCHER_INSET + MAP_ROUND_CONTROL_SIZE + 8}px`)
// The switcher's band, raised by its size and one gap, on the switcher's own left edge.
expect(compassBand(container)?.style.bottom).toBe(`calc(var(--bottom-nav-h, 84px) + ${12 + MAP_ROUND_CONTROL_SIZE + 8}px)`)
expect(compassBand(container)?.style.left).toBe(`${MAP_LAYER_SWITCHER_INSET}px`)
expect(compassBand(container)?.className).not.toContain('left-3')
})
@@ -347,8 +344,8 @@ describe('MMapArea', () => {
for (const shellOver of [{ trTab: 'plan' }, { trTab: 'roadtrip', mapFront: true }] as Partial<MTripShellApi>[]) {
const { container, unmount } = renderArea(shellOver)
expect(parseFloat(compassBand(container)?.style.left ?? '0'))
.toBeGreaterThanOrEqual(MAP_LAYER_SWITCHER_INSET + MAP_ROUND_CONTROL_SIZE)
// Above the switcher: raised past its full height, so the two never overlap.
expect(compassBand(container)?.style.bottom).toContain(`+ ${12 + MAP_ROUND_CONTROL_SIZE + 8}px`)
// With the renderer mocked, the compass is still the one element in this layer
// that sets --bottom-nav-h inline; its left offset joined the same style object.
expect(container.querySelectorAll('[style*="--bottom-nav-h"]')).toHaveLength(1)