Skip to content

Map Sizing Across Sidebar Changes — Implementation Plan

Decisions

Decision Choice Why
Transition scope Cover every transition that changes the map layout: Edit, View, and Settings The reported Edit-to-View failure shares the same layout boundary as the other mode changes.
Camera behavior Preserve the current center and zoom Resizing the Leaflet viewport must not undo the user's current map position.
Responsive scope Desktop and mobile The available map dimensions and sidebar presentation differ across responsive layouts.
Selection behavior Preserve existing selection and detail-panel semantics This task fixes geometry and rendering, not which object remains selected after a mode change.
Resize ownership Keep the map mounted where possible and make the Leaflet boundary react to its actual container size The route already avoids remounting for View/Edit, while a size observer handles conditional panels and CSS transitions without coupling Leaflet to sidebar internals.
Persistence/schema No server, Directus, or schema change Map sizing is client-side layout behavior; no directus/schema/*.json files exist and no persisted field is being read or written.

Prerequisites

  • Keep the route declaration in app/routes.ts unchanged: project/:projectId/map/:mapId continues to render app/routes/project-map.tsx.
  • Preserve the existing MapViewState flow and useMapViewState; resize handling must not write a new center or zoom merely because the container changed size.
  • Keep Leaflet client-only and continue using the existing lazy map boundary. Do not import Leaflet into the server-rendered route path beyond the current client-only component.
  • Treat app/features/map-editor/edit-sidebar.tsx and the right-side panels in app/routes/project-map.tsx as the actual mode-dependent layout owners. The generic shadcn sidebar component is not the controlling layout for this route.
  • No directus/schema/*.json snapshot exists in this workspace. No schema verification or persistence migration is required for this task.
  • There is no test suite. Verification must use pnpm verify typecheck, pnpm verify format, pnpm build, and focused browser/manual checks.

Step 1 — Add a Leaflet container-resize boundary

Goal: Recalculate Leaflet's viewport whenever the map host's rendered dimensions change, without changing the current camera.

Scope

  • In: app/components/map.tsx, add a client-only map child or equivalent internal boundary that observes the rendered map container and invokes Leaflet's size invalidation after its dimensions settle.
  • In: use the map instance's existing center and zoom while invalidating size; do not call fitBounds, setView, or any persistence callback as part of this response.
  • In: handle size changes caused by sidebar insertion/removal, flex reflow, viewport changes, and responsive transitions. Coalesce resize notifications when CSS transitions emit multiple intermediate sizes.
  • In: clean up the observer and any scheduled callback when the map unmounts or the observed element changes.
  • Out: Tile bounds, layer data, map object selection, camera persistence, and server actions.

Acceptance criteria

  • A change to the map host's width or height causes Leaflet to recalculate its visible pixel bounds.
  • The map center and zoom are unchanged by a size recalculation.
  • Resize callbacks do not run after the map has unmounted.
  • Existing upload and tile-set map variants use the same resize behavior.
  • The map remains client-only and does not introduce server-rendering errors.
  • pnpm verify typecheck passes.

Step 2 — Make the route's map host shrinkable and transition-safe

Goal: Ensure the flex layout gives the map a truthful, stable rectangle beside the edit and detail panels.

Scope

  • In: app/routes/project-map.tsx, review the flex containers around the map, edit sidebar, bottom edit sections, and right-side detail panels; add the smallest required min-width/min-height and overflow constraints so the central map column can shrink and expand instead of retaining an overflow-sized width.
  • In: keep the map at the same React tree position for View/Edit transitions, as the current route comment intends. Do not move map children into separate mode branches that would remount Leaflet.
  • In: ensure the central map host has an explicit full-size relationship to its parent and that map controls remain positioned inside that host after the available width changes.
  • In: account for the Settings branch, where the map is intentionally unmounted; preserve mapView state so returning from Settings restores the existing camera rather than fitting or resetting it.
  • Out: Redesigning sidebar contents, changing panel widths as a product decision, changing the topbar, or changing map layer rendering logic.

Acceptance criteria

  • View/Edit transitions do not leave the map column wider than the space between visible panels.
  • The map host can shrink on narrow desktop and mobile viewports without forcing horizontal overflow or cutting off its right/left edge.
  • The map remains mounted across View/Edit transitions.
  • Entering and leaving Settings preserves the existing map view state when the map remounts.
  • Map controls remain fully inside the visible map region after layout changes.
  • pnpm verify typecheck passes.

Step 3 — Coordinate responsive sidebar changes with map resizing

Goal: Verify that the resize boundary responds to both desktop panel changes and mobile sidebar/viewport changes without changing selection behavior.

Scope

  • In: app/routes/project-map.tsx and, only if required by the actual rendered structure, app/features/map-editor/edit-sidebar.tsx, ensure sidebar visibility or size changes are reflected in the map host's observed geometry.
  • In: preserve the existing selected POI, line, area, dataset feature, and edit-detail panel behavior when switching modes; do not close or reassign selections as a sizing side effect.
  • In: support viewport rotation/resizing and the mobile presentation currently provided by the route/components. If a mobile sidebar overlays rather than resizes the map, still invalidate the map when its open/closed state changes if the map host geometry or visible interaction area changes.
  • Out: Introducing a new sidebar system, changing mobile navigation semantics, or adding new selection state.

Acceptance criteria

  • On desktop, entering and leaving Edit updates the map's usable viewport for both left and right panel changes.
  • On mobile, changing the viewport size or sidebar open/closed state does not leave stale clipped map content.
  • Switching modes preserves current selections and existing detail-panel behavior.
  • No panel or map control overlaps another incoherently at representative narrow and wide sizes.
  • pnpm verify typecheck passes.

Step 4 — Verify map layers and camera preservation

Goal: Confirm the geometry fix resolves the observed blank or clipped left/right rendering for every supported map composition.

Acceptance criteria

  • pnpm verify typecheck passes.
  • pnpm verify format completes successfully.
  • pnpm build passes.
  • Manual check: load an uploaded-image map, pan/zoom to a non-default position, switch Edit to View, and confirm the center/zoom remain stable while the image fills the newly available viewport.
  • Manual check: repeat with a tile-set map and confirm tile coverage reaches both former sidebar edges after switching modes.
  • Manual check: with enabled image overlays, Avesmaps routes/features, POIs, lines, areas, and labels, switch View/Edit and confirm each layer renders across the complete map region without left/right clipping.
  • Manual check: enter and leave Settings and confirm the map remounts with the saved in-browser view rather than an unintended refit.
  • Manual check: test representative desktop and mobile viewport sizes, including resizing or rotating the viewport while the map is visible.
  • Manual check: verify selected object and detail-panel behavior remains unchanged while switching modes.
  • Confirm no server module, route loader/action, Directus field, or persisted map value was changed for the sizing fix.

Risks / open questions

  • The route's Edit sidebar and detail panels are ordinary flex children, while the generic app/components/ui/sidebar.tsx is not their owner. Implementation should avoid changing the unused abstraction unless a nearby call site proves otherwise.
  • Leaflet's size invalidation must occur after the flex layout has settled; an observer plus a scheduled callback should be preferred over a mode effect that guesses timing.
  • Settings intentionally unmounts the map. Its remount path must continue to use useMapViewState and must not treat the remount as a request to fit bounds.
  • No directus/schema/*.json snapshot exists, and no Directus field is involved.