doxa-maps/library
Doxa Maps 502d7107e3 Every zone a reader can pick resolves to its groups, Deaf included
The legend offers 28 zones; every place that turned a picked id back
into a zone spread clusters.json's three geographic buckets, which is
27. The missing one is Deaf, whose two deaf lists the legend collapses
into a single affinity-bloc row. So in the browser, silently:

  - the Prayer packet for Deaf returned on "if (!zone) return";
  - the Deaf poster titled itself by its slug;
  - a selection containing Deaf dropped it in .filter(Boolean);
  - the packet count read 27 while 28 packets exist, and that count
    prints on page 1 and at the tip of page 2's triangle.

The packet fetch also lacked rop1, the field the Deaf selector reads,
so even a found Deaf zone would have resolved to nobody.

The fix is one enumeration. legend-tree.js now exports DEAF_SELECTOR
(the unified row's selector, which exists nowhere in clusters.json) and
zonesWithSelectors(clusters): the legend's leaves with their selectors
attached. The plugin's printableZones() keeps the 27 catalogue objects
exactly as they were and adds only what the catalogue lacks, so the
packet, poster, selection and count all see the same 28. rop1 joins
both packet fetches.

The three hand-typed copies of the Deaf literal (the map, the poster
generator, the offline packet generator) now import the one
definition; the offline generator's own id-to-selector table is
replaced by zonesWithSelectors. The copies left are frozen snapshots and
proof scripts, which keep independent literals on purpose.

The offline sweep gate's coverage had the same 27: it never required a
Deaf packet. It now counts through the legend.

Verified: the live API carries exactly 123 A017 rows, matching the
legend's Deaf count; the default 3x4 posters for sudan, kerala, deaf
and west-africa are byte-identical before and after.
2026-09-29 02:16:27 +00:00
..
api The people-group list is a universal prop: the same maps can show any project's list 2026-09-26 05:16:02 +00:00
charts/whiteboard Delete 7 unreachable library components, and gate the thing a census cannot see 2026-09-29 01:38:07 +00:00
colors The legends mirror now, and their labels never became their values 2026-09-26 22:06:58 +00:00
components bandFill mode: 'fill-all' draws every group and lets the zoom separate them 2026-09-29 01:38:08 +00:00
composables Delete 7 unreachable library components, and gate the thing a census cannot see 2026-09-29 01:38:07 +00:00
constants The poster credited Mapbox for tiles OpenFreeMap had served 2026-09-29 00:06:52 +00:00
dashboards Write down the contract the four dashboard panels already share 2026-09-29 01:38:08 +00:00
data Country names in the reader's language, for all 242 2026-09-27 04:14:31 +00:00
elements Twenty-four warnings about an overwrite that was the whole point 2026-09-28 17:53:38 +00:00
i18n A country map you can drop on one page, without the dashboard around it 2026-09-29 01:38:07 +00:00
layouts Every animating library component now honours prefers-reduced-motion itself 2026-09-29 01:38:07 +00:00
lists List names speak the reader's language: listLabel and listDefinition 2026-09-26 08:39:52 +00:00
maps The poster credited Mapbox for tiles OpenFreeMap had served 2026-09-29 00:06:52 +00:00
packet Put the missing-map sentence in every packet language 2026-09-29 00:59:14 +00:00
packets Number({value:"1"}) is NaN, so the whole reachedness sentence vanished 2026-09-28 15:52:47 +00:00
scripts Every zone a reader can pick resolves to its groups, Deaf included 2026-09-29 02:16:27 +00:00
stores Make the map's clustering picker real: four options, four different maps 2026-09-25 16:16:46 +00:00
styles Share the ported _globals.scss rules through one module 2026-09-29 01:38:08 +00:00
utils A country map you can drop on one page, without the dashboard around it 2026-09-29 01:38:07 +00:00
vendor/cldr Country names in the reader's language, for all 242 2026-09-27 04:14:31 +00:00
index.js Move internal files out of the repo; fix five dead links; a fuller delegation diagram 2026-09-25 05:14:10 +00:00
ProfileLoader.vue ?lang= on the page turns every embedded map's direction and data language, not only its text 2026-09-27 06:42:54 +00:00
README.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/ (@map) — the shared map template

The other half of the architecture (see ../plugin-designs/README.md): every map in plugin-designs/<your-map>/ composes the reusable, parameterized pieces that live here. Fix something here and every map benefits on the next build; break something here and every map breaks — read components/WARNING.md before touching shared pieces.

Folder What lives there
ProfileLoader.vue The root of every bundle: parses profile-config, loads the profile, provides the stores + config
components/ Shared UI — map, legends, controls, popup (PeopleGroupDetail), tables, charts, hints (README)
composables/ Shared logic — map engine (useMapInstance), provider switch, shadow-DOM styles, theming
stores/ Per-instance Pinia stores (ui / map / data) — provided by ProfileLoader, injected by children
api/ Data-source registry (sources.json) + fetch layer — the JAMstack runtime wiring
colors/ Color sets maps opt into via profile-config.colorSet
i18n/ The shared string catalogs (all maps speak the same languages)
data/ Small shared datasets baked at build time (big served data lives in ../data/)
constants/ Shared constants
scripts/ Maintainer pipelines (posters, research) — not part of any bundle

The rule of thumb (same as WARNING.md): custom code in your app-profile, reusable code here — and things only move from the first to the second once they've earned it.