FILTER DROPDOWNS WERE INVISIBLE. Opening a filter rendered its options underneath the surrounding content, making the dashboard's primary control unusable. The cause was CLIPPING, not stacking order, and that distinction is why an earlier attempt failed. The filter band is a one-row horizontal scroller authored as overflow-x:auto with overflow-y:visible — but CSS Overflow 3 coerces a visible axis to auto when the other axis is not visible, so it computes to auto/auto and clips vertically. Clipping happens during painting, before stacking order is consulted, so raising the band to z-index 55 changed nothing: it won a stacking fight that was never the problem. You cannot re-order pixels that were never generated. The menu is now position:fixed, anchored to the trigger's viewport rect, which takes it out of the clip chain entirely. Fixed coordinates go stale whenever anything scrolls or resizes, so they are recomputed on open and while open, listening in the capture phase so the dashboard's inner scroll regions are seen too. PEOPLE-GROUP IMAGES WERE LETTERBOXED. A fixed 130px height against a 220px column cropped each person to a band. The image is now a square via aspect-ratio, and the column floor rises to 240px, roughly doubling the visible area. object-fit:cover is kept deliberately — stretching to a square would distort faces, which is worse than the letterbox it replaces. |
||
|---|---|---|
| .. | ||
| api | ||
| colors | ||
| components | ||
| composables | ||
| constants | ||
| data | ||
| i18n | ||
| layouts | ||
| 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.