doxa-maps/library/components
Doxa Maps 5b35257f7b Fit to the pins when a narrow screen cuts them out of the frame
A country page frames by a fixed center and zoom, and a fixed zoom shows less on
a narrow screen. Measured on the drop-in: /regions/niger at 390 wide put the
camera over southern Niger and northern Nigeria with the Agadez outline cut off
at the top and 0 of the page's 2 pins in view, while the same page at 1440
showed both.

Inherited rather than introduced: their CountryDetail passes only center and
zoom to CountryMap and never a box, so the live site frames the same way.
chooserZoom cannot save it either -- its first line returns props.zoom unchanged
unless colorMode is 'region', and a country page is 'prayer', so the
width-and-height-aware solver below it never runs.

The fit is CONDITIONAL, which is the part that keeps this a clone. fitTheirWay
ends in easeTo({center, zoom}), so it moves the centre as well as the zoom;
fitting unconditionally would re-frame every page that is already correct. So
the configured camera is applied and kept, and the pins' box is fitted only when
a pin actually falls outside it. Asked on moveend, because getBounds reads the
current camera and flyTo is animated, so asking sooner would test the camera
being left behind.

The cap is a ceiling: maxZoom = props.zoom lets the fit zoom OUT, which is what
the narrow case needs, while forbidding it from zooming in past the camera the
page asked for. Capping it the other way would have made this a no-op on the one
case it exists for.

The pins' box is the honest input available here. The country outline comes from
the countries tile source, so its extent is only as good as the tiles that
happen to be loaded; reading a box off it would measure the viewport, not the
country. A box supplied by the page would be better still, since pins can
cluster in one corner.

Probe in _qa-cycle lifts pinsBox and fitIfPinsAreOutOfView out of this file by
source and tests both sides: a well-framed page takes zero fits, and the narrow
case fits the pins' box capped at props.zoom. Mutation-tested both ways --
removing the already-framed early return, and capping with minZoom instead of
maxZoom, each make it fail.
2026-09-29 07:07:48 +00:00
..
charts library/ keeps the reason and drops the speaker: no comment quotes or cites the Driver 2026-09-29 05:26:25 +00:00
dashboards library/ keeps the reason and drops the speaker: no comment quotes or cites the Driver 2026-09-29 05:26:25 +00:00
hints library/ keeps the reason and drops the speaker: no comment quotes or cites the Driver 2026-09-29 05:26:25 +00:00
legends The Country Posters map's legend Packet export works, and the card deck rolls out behind one switch 2026-09-29 05:26:27 +00:00
map-controls library/ keeps the reason and drops the speaker: no comment quotes or cites the Driver 2026-09-29 05:26:25 +00:00
maps Fit to the pins when a narrow screen cuts them out of the frame 2026-09-29 07:07:48 +00:00
poster Fix what an adversarial review of the print standard confirmed: 21 defects, each re-checked against the code 2026-09-29 06:23:19 +00:00
qa Comments state their findings instead of citing files outside the repo 2026-09-29 03:46:37 +00:00
regions library/ keeps the reason and drops the speaker: no comment quotes or cites the Driver 2026-09-29 05:26:25 +00:00
search The browser-side generator keeps the reason and drops the speaker 2026-09-29 05:26:27 +00:00
tables DataTable + StackLayout: physical left/right -> logical, where the rule mirrors 2026-09-28 09:48:45 +00:00
BackToTopButton.vue Shipped comments describe the behaviour instead of quoting a person 2026-09-28 17:40:35 +00:00
PeopleGroupDetail.vue Every animating library component now honours prefers-reduced-motion itself 2026-09-29 01:38:07 +00:00
README.md consolidate docs into documentation/ and deployment shells into deployment/ 2026-09-21 23:23:23 +00:00
ResearchMapFilterPanel.vue Four shared controls get a 24x24 target at every pointer, not only on touch (WCAG 2.5.8) 2026-09-26 13:35:57 +00:00
ResearchMapSideMenu.vue Every animating library component now honours prefers-reduced-motion itself 2026-09-29 01:38:07 +00:00
SideMenuDrawer.vue Every animating library component now honours prefers-reduced-motion itself 2026-09-29 01:38:07 +00:00
ViewSelect.vue Every animating library component now honours prefers-reduced-motion itself 2026-09-29 01:38:07 +00:00
WARNING.md Complete app-profiles->plugin-designs sweep across comments/docs; build green; layouts kept at root (load-bearing) 2026-09-17 18:18:19 +00:00

library/components/ — shared Vue components

The map UI, built from parameterized pieces every app-profile reuses. Fix one here and every map benefits — never edit a shared component to customize one map.

  library/components/
  ┌───────────────────────────────────────────┐
  │ legends/        map-controls/   poster/      │
  │ charts/         tables/                       │
  │ PeopleGroupDetail.vue   SideMenuDrawer.vue    │
  │ ResearchMapFilterPanel.vue  …SideMenu.vue     │
  └───────────────────────────────────────────┘
     reused by every app-profile via @map/components/…
  • legends/, map-controls/, poster/ each have their own README.
  • Every component uses <script setup>, calls useShadowStyles(), and reaches stores via inject('mapStore' | 'uiStore' | 'dataStore') — never a direct store import.

Full catalog + conventions: ../../documentation/architecture/components.md · per-file roles: ../../documentation/reference.md.