The poster wall was generalised into library/components/poster/PosterWall.vue and two bundles migrated onto it — but the ORIGINAL, my-upg-100-list's 903-line wall, was left on its own copy. So the one wall carrying the real print actions is the one wall nothing else benefits from, and the shared component's packet path was still a "coming soon" stub. Every print fix made in the 100-list this flight (the card deck, the stock picker, the image_url fetch) was invisible to the three bundles on the shared component, and vice versa. ★ THE SEAM IS WHAT MADE THIS SHAREABLE AT ALL. The PRINT ACTIONS are common; the RECORD FETCHING is not. fetchListRecords in the 100-list knows the people-groups API, the selector evaluator and the pg_slugs special case; Key Cities and Country Posters have entirely different data shapes. usePosterPrints.js therefore takes a `records(item)` PROVIDER and owns everything after it — the HUD state machine, the in-place print frame, and the documents. That also keeps the bundles honest. A wall that CAN supply rows passes the prop and gets the list + card-deck prints; one that cannot omits it, the Card Deck button is not rendered, and Prayer List keeps its truthful "coming soon" instead of a button that fails at click time. Country Posters shows exactly that today: 175 cards, Prayer List and Poster Map, no Card Deck — because it has no provider yet, not because something broke. ⚠ ONE exportState, not two. The composable owns a ref by default, and a wall rendering its OWN state while these actions wrote to a private one would show no progress and swallow every error — the mechanism working and the feedback not, which is the failure mode this flight keeps finding. PosterWall hands the composable its own ref so both write to the surface the reader is looking at. Prints IN PLACE via the shared openPrintFrame, never window.open() — the mechanism the Driver asked for by name: "not supposed to open up a new browser, but should open up the print dialog directly in the browser". NOT DONE, and deliberately: the 100-list wall is NOT yet migrated onto the shared component. Its template is 107 lines against the shared 72 with a different structure, and it is a Driver-reviewed surface — that is a rewrite whose risk does not fit in one tick alongside this. The shared half lands first and is verified; the migration stays open on the card with this composable now waiting for it. Verified: all three bundles on the shared wall build; country-poster-wall renders 175 cards with zero page errors; check:poster-prints drives the composable in a browser and asserts BOTH directions. |
||
|---|---|---|
| .. | ||
| api | ||
| colors | ||
| components | ||
| composables | ||
| constants | ||
| data | ||
| i18n | ||
| layouts | ||
| maps | ||
| packet | ||
| scripts | ||
| stores | ||
| styles | ||
| utils | ||
| index.js | ||
| ProfileLoader.vue | ||
| README.md | ||
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.