doxa-maps/library
Doxa Maps f06751f3a8 formatList: a list of items in the reader's language, since join(', ') is wrong in every locale but English
join(', ') builds "A, B, C" for every reader. Arabic joins with و and no comma, Chinese with 、,
German and Russian with their own final conjunction, and no catalogue key can fix it, because the
separator and conjunction ARE the grammar. gospel measured it inside a fully keyed sentence
(pins.sharedPoint in Arabic still carried English commas) and counted 31 such joins across library
and plugins, with no Intl.ListFormat and no helper anywhere in the tree.

library/i18n now exports formatList(items, { type, style, locale }), backed by Intl.ListFormat.
It resolves the locale the way tStatic does (explicit argument, then the host's runtime locale,
then the page's), caches one formatter per locale and options, and falls back to ', ' only where
Intl.ListFormat does not exist. Proven from the shipped source, not a copy: en "A, B, and C",
ar "A وB وC", zh "A、B和C", de "A, B und C", disjunction "A or B", one item, none, and the runtime
locale when no argument is given. The call sites stay with their owners to migrate.
2026-09-29 13:29:18 +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 library/ keeps the reason and drops the speaker: no comment quotes or cites the Driver 2026-09-29 05:26:25 +00:00
components A table row's detail sheet names itself in the reader's language when its first column is empty 2026-09-29 12:44:25 +00:00
composables The regions idle paint expression moves to the library that already painted with it 2026-09-29 13:29:18 +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 Map sheets are generated in the browser at the click, by the same generator the Node script runs 2026-09-29 05:26:27 +00:00
elements library/ keeps the reason and drops the speaker: no comment quotes or cites the Driver 2026-09-29 05:26:25 +00:00
i18n formatList: a list of items in the reader's language, since join(', ') is wrong in every locale but English 2026-09-29 13:29:18 +00:00
layouts The last library reference drops the speaker, and the baseline shrinks to what is left 2026-09-29 05:26:26 +00:00
lists Speak the reader's language on the UPG-100 map, its wall and the print HUD 2026-09-29 08:33:43 +00:00
maps library/ keeps the reason and drops the speaker: no comment quotes or cites the Driver 2026-09-29 05:26:25 +00:00
packet Serve the packet text at print time instead of bundling all 11 languages 2026-09-29 08:33:44 +00:00
packets library/ keeps the reason and drops the speaker: no comment quotes or cites the Driver 2026-09-29 05:26:25 +00:00
print 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
scripts The browser/Node sheet equivalence check can measure on a fresh checkout 2026-09-29 12:44:25 +00:00
stores A collapsed legend reopens itself after you close a people-group detail 2026-09-29 11:56:47 +00:00
styles library/ keeps the reason and drops the speaker: no comment quotes or cites the Driver 2026-09-29 05:26:25 +00:00
utils Move four identical bodies into the library 2026-09-29 09:19:04 +00:00
vendor/cldr library/ keeps the reason and drops the speaker: no comment quotes or cites the Driver 2026-09-29 05:26:25 +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 A desktop-only composite blocks on a phone too: the phone rule is a composable its root can call 2026-09-29 09:18:55 +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.