Driver request: "a toggle or carrot added to the bottom of the region
section that says view country posters, which will let you view country
posters for each of the countries in the regions" — with View-on-map and
Print, "the same reusable code from upg 100 list". This is a third
sanctioned addition alongside the tab strip and the no-selection chooser.
Almost nothing was built. library/components/poster/PosterWall.vue was
already the shared, fully parameterised grid, and it already owned the
card layout, the "Show on map" header button, the PRINT OPTIONS footer
and the client-side raster. regions-list.vue supplies only data and a
toggle — the same division country-poster-wall.vue states in its own
header.
- A "View country posters" toggle at the bottom of every region section,
carrying aria-expanded and aria-controls, using the same caret SVG the
header and footer links already use, rotated when open.
- Opening a region renders that region's countries. Measured: 41 cards
for Africa and all 41 previews LOAD (naturalWidth>0 — a 404 still
yields an <img>, so the load is the real check). No assets were
copied: public/assets/previews already holds 174 country-*.webp and
generate-tree already stages them.
- "Show Chad on the map" reaches the Region Dashboards tab with title
"Chad" and hash "#chad", by mapping PosterWall's CustomEvent listId
back through the country-selected the tabs already exchange.
- India prints its own reason with the exact number from the data; China
renders a real poster. Only India is unsupported — 855 groups and no
sheet, against China's 154 on a 3x4.
Two defects the screenshot caught and no assertion did:
- PosterWall's root is position:absolute;inset:0, because in its own
bundles it IS a pane. Embedded in a region card it painted 1440x1100
over the region's country list. Fixed by parameterising the shared
component rather than overriding its CSS locally: new `embedded` and
`sectionHeads` props, both defaulting to today's behaviour, so
country-posters and key-cities are unchanged by construction. Both
re-checked. Re-measured: root static, 1200px wide, panel below the
grid, no overlap.
- With one unnamed group the wall printed a section head reading the
literal "Other" plus a count duplicating the region card's own
summary. Suppressed by sectionHeads=false.
The dataset moved to library/data/country-posters.json now that it has a
second consumer, one import line changed in country-posters, and
emit-countries.mjs was retargeted so the next generator run cannot
recreate the duplicate.
The three new strings do not exist on DX-life, so there was nothing to
copy and nothing was invented in another language: en only, with the
other seven locales falling back to the key.
Regression: 15 suites green, including region-vs-live 73/73,
country-vs-live 28/28, mobile 44/44 and 26/26, and a new
_probe-region-posters.mjs. check:library-index drifted for real this
time (3 new library files) and is regenerated here.
summarizeRegions() was duplicated in regions-list.vue and
region-dashboards.vue — two copies of the same rollup, so two chances
for the region page and the dashboard to disagree about one number.
Both now import a port of DX-life's config/countries-meta.ts, placed in
library/ because it has two named consumers.
Ported verbatim: slugify's replace chain, FULL_PRAYER_COVERAGE_COUNT,
addToStats's conditions, fitView's constants, lngExtent's largest-gap
walk, WORLD_VIEW, both sort orders. Changed only: TypeScript to JS
(interfaces to JSDoc), and their `import { COUNTRIES } from
'../app/utils/countries'` becomes library/data/countries.json — their
same 242-entry {value,label} array, in their order. toNumber and
emptyStats are exported beyond their surface, and only those two: their
pages need no cross-region total because DX-life has no "all regions"
view, and ours does for the no-selection chooser.
Two things the copies had wrong, both fixed by porting rather than
patching:
- They slugged a country from the API's LOCALIZED label. Theirs slugs
from the canonical English name, deliberately. The live site settled
it: /regions/the-united-states is 200 and /regions/united-states is
404; /regions/the-democratic-republic-of-the-congo is 200 and
/regions/dr-congo is 404. Since the dashboard writes the slug into
the URL hash, our deep links pointed at pages that do not exist
there.
- They dropped centre/zoom/bounds entirely, so our maps derived their
own frame. Theirs computes a fit view per country and per region,
including the antimeridian: Oceania's bounds come out east 187.9,
where a naive max() says 178 and spans the globe backwards.
Also fixed regions-list.vue's formatNumber, still hardcoded en-US after
the same fix landed in region-dashboards.vue, and its region sort, which
used (a.label || 'Other') where theirs compares a.label directly.
Proof: region-vs-live 73/73 and country-vs-live 28/28 UNCHANGED — the
rollup is equivalent. New _probe-countries-meta.mjs is 20/20 and
includes a negative test showing the antimeridian assertion really
discriminates. oceania-and-list, regions-swap, standalone-app,
dashboard, total and search all green. 159 lines of duplication gone.
Standalone repo that builds embeddable JAMstack map bundles (web components),
composes them into a lazy-loaded SPA via layouts/, and optionally wraps a
Capacitor Android/iOS app — one build, choose your output/CDN. Diátaxis docs.
History reset to a single clean commit; no PII, IPs, or internal terms.