The Driver asked for a top-right dropdown with Auto plus fixed overrides, remembered, and said plainly that the CSS already working must not break. So Auto writes NOTHING. The grid is repeat(auto-fill, minmax(240px, 1fr)), which already gives one column on a phone and three to five on a desktop by measuring its container; Auto leaves the stylesheet alone and only an explicit override sets grid-template-columns. An Auto that computed a number and wrote it back would look identical until the container resized, and then be silently wrong — the same picture, with the responsiveness removed. An override is honoured even when it is a poor idea: five columns on a 390px phone is a 62px card. That is deliberate. The reader asked for it, Auto is the default and one click away, and the control shows which is active. Clamping someone's explicit choice to what we think is sensible is how a control stops being trusted. It is remembered per PROFILE, not per bundle. Two grids on one page are two different lists, and useDashboardLayout already paid for that lesson when a shared key made one caller inherit another's saved layout. Blocked storage is caught and ignored: in private mode the default is the correct outcome, not an error to report. It sits in its own row rather than in #filters, which is gated on useSearch || useFilters — a host turning both off would otherwise lose a control that has nothing to do with either. It modifies the grid, so it lives on the grid. Both strings are authored in all eleven catalogues, in the snake_case this catalogue uses: a camelCase key here would have resolved to nothing and rendered its own name, which is the defect I shipped in a legend earlier today. |
||
|---|---|---|
| .. | ||
| 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.