The Driver asked for the arrow on the people-group grid and on the regions list. Those needed different wiring, and the reason is worth recording because it is not a preference. The regions dashboard owns its scroller: .rd-scroll has overflow-y:auto, so the plugin mounts the button itself and drives its own element. It deliberately does not touch the page's scroll — this renders inside a shadow root in someone else's page, and their scroll is not ours to move. The people-group grid owns no scroller at all. .pgg-root sets no overflow and .pgg-body has no rule; the grid simply grows and something outside it scrolls. In this shell that something is .vtl-host, which lives in the layout, outside every plugin's shadow root, so the grid could not reach it even if it should. So the arrow for that surface belongs in the layout, beside the circle the layout already owns, driving the pane it already owns. The grid is untouched. .vtl-host is per tab, so the arrow follows `active` rather than binding one ref, or it would scroll whichever pane rendered last. One component, two consumers, and each drives a scroller it actually owns. Checked that this adds nothing to the hardcoded-English census: 256 before, 256 after — the three regions entries there are PosterWall prop literals and predate this. |
||
|---|---|---|
| .. | ||
| api | ||
| charts | ||
| colors | ||
| components | ||
| composables | ||
| constants | ||
| data | ||
| elements | ||
| i18n | ||
| layouts | ||
| lists | ||
| maps | ||
| packet | ||
| packets | ||
| scripts | ||
| stores | ||
| styles | ||
| utils | ||
| vendor/cldr | ||
| 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.