diff --git a/client/src/index.css b/client/src/index.css index 278666809..7bea87652 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -1290,7 +1290,6 @@ img[alt="TREK"] { /* ── Dark-Mode: Tailwind-Klassen ─────────────── */ .dark .bg-slate-50 { background-color: #131316 !important; } -.dark .bg-slate-100 { background-color: #1c1c21 !important; } .dark .bg-white { background-color: #09090b !important; } .dark .bg-gray-50 { background-color: #131316 !important; } .dark .bg-gray-100 { background-color: #1c1c21 !important; } @@ -1307,10 +1306,7 @@ img[alt="TREK"] { .dark .bg-slate-100 { background-color: #27272a !important; } .dark .bg-slate-900 { background-color: #e4e4e7 !important; color: #09090b !important; } .dark .hover\:bg-slate-700:hover { background-color: #d4d4d8 !important; color: #09090b !important; } -/* Not inside the touch shell (.m-root): its fields state their own fill, a - transparent input inside a rounded wrapper above all, and this rule outweighs - every utility class, so it painted a dark box inside each of them. The - :where() keeps the desktop's weight exactly as it was. */ +/* Not in the touch shell (.m-root), whose fields set their own fill; :where() keeps the desktop's weight. */ .dark input:not(:where(.m-root *)), .dark textarea:not(:where(.m-root *)), .dark select:not(:where(.m-root *)) { background-color: #1c1c21; color: #f4f4f5; diff --git a/client/src/pages/atlas/atlasChrome.test.ts b/client/src/pages/atlas/atlasChrome.test.ts index a817c371b..802aa0434 100644 --- a/client/src/pages/atlas/atlasChrome.test.ts +++ b/client/src/pages/atlas/atlasChrome.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { chromeFitPadding, chromePan } from './atlasChrome'; // FE-ATLAS-CHROME-001 onwards: the atlas camera beside the touch shell's rail and header. @@ -11,6 +11,14 @@ describe('atlas chrome insets', () => { expect(chromePan({ top: 62, start: 0 }, 83, false)).toBeNull(); }); + it('FE-ATLAS-CHROME-005: the north edge is measured only where there is chrome to clear', () => { + const measure = vi.fn(() => -77); + expect(chromePan(undefined, measure, false)).toBeNull(); + expect(measure).not.toHaveBeenCalled(); + expect(chromePan({ top: 62, start: 0 }, measure, false)).toEqual([0, -139]); + expect(measure).toHaveBeenCalledTimes(1); + }); + it('FE-ATLAS-CHROME-002: the world moves away from the rail, in either reading direction', () => { expect(chromePan({ top: 62, start: 100 }, 83, false)).toEqual([-50, 0]); expect(chromePan({ top: 62, start: 100 }, 83, true)).toEqual([50, 0]); diff --git a/client/src/pages/atlas/atlasChrome.ts b/client/src/pages/atlas/atlasChrome.ts index 6679741d2..bd84bffa6 100644 --- a/client/src/pages/atlas/atlasChrome.ts +++ b/client/src/pages/atlas/atlasChrome.ts @@ -23,16 +23,17 @@ export const NORTH_EDGE_LAT = 75; * inhabited top (NORTH_EDGE_LAT, at `northEdgeY` in the map's own pixels) needs * to clear the header: a tall window shows it below the header anyway, a phone * had the stars of the far north under it. Leaflet pans the camera, so the - * numbers point the other way from the world's move. + * numbers point the other way from the world's move. `northEdgeY` may be a + * measurement, taken only where there is chrome: the desktop atlas has none. */ export function chromePan( insets: AtlasChromeInsets | undefined, - northEdgeY: number, + northEdgeY: number | (() => number), rtl = documentRtl() ): [number, number] | null { if (!insets) return null; const x = insets.start ? (rtl ? 1 : -1) * (insets.start / 2) : 0; - const y = Math.min(0, northEdgeY - insets.top); + const y = Math.min(0, (typeof northEdgeY === 'function' ? northEdgeY() : northEdgeY) - insets.top); return x || y ? [x, y] : null; } diff --git a/client/src/pages/atlas/useAtlas.ts b/client/src/pages/atlas/useAtlas.ts index 2d56c0457..c4760c3e3 100644 --- a/client/src/pages/atlas/useAtlas.ts +++ b/client/src/pages/atlas/useAtlas.ts @@ -373,10 +373,8 @@ export function useAtlas(options: { chromeInsets?: () => AtlasChromeInsets } = { map.getPane('regionPane')!.style.zIndex = '401' mapInstance.current = map - // The opening view centres the world beside the screen's chrome, not behind the rail and under the header. - // Measured only where there is chrome to clear: the desktop atlas opens exactly as before. - const insets = chromeInsetsRef.current?.() - const pan = insets ? chromePan(insets, map.latLngToContainerPoint([NORTH_EDGE_LAT, 0]).y) : null + // The opening view clears the touch shell's rail and header; the desktop atlas has none and opens as before. + const pan = chromePan(chromeInsetsRef.current?.(), () => map.latLngToContainerPoint([NORTH_EDGE_LAT, 0]).y) if (pan) map.panBy(pan, { animate: false }) // Both renderers live as long as the map does (see the note on the refs); map.remove() // disposes them along with every other layer it holds.