doxa-maps/library
doxa-maps-88655c70 90ceac36ba PinHint must not require vue-i18n either, and a gate so the next one is caught
The shepherd reported a P0 I caused: db36397b made library FilterDropdown call
useI18n() unconditionally, which throws "Need to install with `app.use`" on any
host that never installed vue-i18n. people-groups-grid deliberately has none, so
the grid rendered blank standalone, in the studio and in every composite nesting
it -- one of the seven production plugins going to DX. Studio fixed that
instance in 6603dc17.

That fix was NOT on my branch. 6603dc17 was not an ancestor of my HEAD and my
tree still carried the unguarded call, so my next push would have reverted it.
Merged before doing anything else.

PinHint carried the same unguarded call, added by me in 9ba6ad7a. Guarded the
same way: host translations when present, the English literal otherwise, with
te() answering false so callers fall through to their own defaults.

The gate the shepherd asked for is _chk-library-i18n-optional.mjs. It scans
library/components for useI18n() calls that are not behind a guard, and it
separates LIVE from LATENT, because a wall of identical failures gets ignored
while a list of one gets fixed: it computes which bundles install no i18n and
which of those actually import each offender.

Measured: 17 library components still call useI18n() unguarded, 7 bundles
install no i18n (big-picture, doxa-maps-spa, doxa-vision-card, golden-path-check,
people-groups-grid, plugin-studio, stack-demo), and LIVE is currently none --
no bare host renders an unguarded component today. The 17 are debt, not safety.
They are left for their owners rather than rewritten from here, since library/
reaches every bundle.

Two of my own errors on the way, both caught before they reached anyone. I first
reported 14 bare bundles, because I grepped for createI18n when the install is
usually createAppI18n from @map/i18n -- country-posters does install it. And the
gate first reported PeopleGroupDetail as LIVE in people-groups-grid on the
strength of a COMMENT mentioning it: a substring match cannot tell an import from
prose, which is precisely the defect I reported in check:shared-reached a day
earlier and then rebuilt myself. It now strips comments and requires a real
import statement or an element tag.
2026-09-25 03:43:56 +00:00
..
api Add the Gospel Access filter, the ladder the binary flag was flattening 2026-09-23 13:19:22 +00:00
colors Adopt the research map's region colours, and pin the one unit that wasn't px 2026-09-24 20:48:27 +00:00
components PinHint must not require vue-i18n either, and a gate so the next one is caught 2026-09-25 03:43:56 +00:00
composables Merge commit '840830ebc47250b642d6d58ba1e584a30e74d47d' into bundler-1/work 2026-09-24 22:45:25 +00:00
constants doxa-maps — portable bundler for embeddable JAMstack maps 2026-09-10 01:53:07 +00:00
data Regions: expand a region to its country posters, reusing the shared wall 2026-09-24 04:26:29 +00:00
i18n Country page: six more terms the clone had and live has moved past 2026-09-25 02:09:20 +00:00
layouts Plugin studio: an Explorer tree for the rail, imitating VS Code 2026-09-24 21:40:48 +00:00
maps Load the RTL text plugin from one place, and in the composite too 2026-09-22 19:55:58 +00:00
packet packet: a partial translation renders 12 prayer points, not 3 2026-09-24 12:20:38 +00:00
scripts packets: render the MIXED photo case, and assert the fallback says something 2026-09-25 02:42:04 +00:00
stores fix(spa): make embedded maps survive the sandboxed plugin iframe 2026-09-12 21:07:26 +00:00
styles Fiord: the MapLibre dark that actually looks like the map it replaces 2026-09-24 02:26:14 +00:00
utils embedBase: the asset pool is INSIDE the tree, not beside it 2026-09-25 01:30:56 +00:00
index.js Brand-neutral shared VerticalTabsLayout with lazy nested-element hosting; fix cap-5 prayer tab leaf path; neutralize library identifiers; add Forgejo CI build-gate workflow 2026-09-19 17:24:30 +00:00
ProfileLoader.vue One page, one map token — and the nested search bar comes back 2026-09-24 01:14:37 +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.