doxa-maps/library
Doxa Maps 667c6331c8 Square map controls, as an option beside the round ones
The Driver asked for square controls by name. The fact that shaped this:
the square look is not a DX-life design at all. Their CountryMap.vue adds
NavigationControl + FullscreenControl and overrides nothing, so what he
admired is the ENGINE'S default grouped card -- which makes the target
published and exact instead of a matter of taste. Every value here is read
from node_modules/maplibre-gl/dist/maplibre-gl.css, and the check compares
ours against that file rather than against my memory of it.

SQUARE IS NOT A RADIUS SWAP, which is why it lives on the TOOLBAR. Round
controls are separate floating circles with a gap and a shadow each; the
engine's square form is ONE panel that owns the background, the 4px corners
and the 2px ring while its buttons own nothing and are divided by 1px lines.
Setting border-radius:0 on the buttons alone gives squares floating 8px
apart -- neither shape. So MapToolbar takes controls="round"|"square", and
MapControlButton keeps a shape prop only for a button used outside a
toolbar, where a lone control gets the engine's 4px.

THE 29px IS DELIBERATELY NOT PORTED. Ours stay --map-btn-size, capped to
32px in this toolbar. 29px would cut the touch target below what this
project has already ruled on twice, so the variant takes the shape and
leaves the size. It is therefore not pixel-identical to the engine, and
that is a choice, stated.

No overflow:hidden. Clipping was the quick way to round the panel, but it
also clips a focus ring on any inner button, and the engine does not do it
-- it rounds the first and last buttons instead. Ported as their mechanism.
MapControlMenu teleports out of the toolbar, so clipping would not have
hidden a menu; the focus ring was the real cost, and the invisible kind.

Forced colours ship with it, which the round buttons never had: an rgba()
ring and a #ddd divider both vanish under a replaced palette, leaving one
undifferentiated block where the controls were.

BLAST RADIUS: round is the default and none of the nine MapToolbar
consumers passes controls=, so every map renders exactly as before.
Asserted, not claimed -- opting one consumer in turns the check red.

The regions dashboard is NOT switched. Its map already uses the engine's
native controls, ported from DX-life, so it already looks like this;
replacing them with ours would risk clone parity to arrive at the same
picture.

One near-miss, recorded because of how it hid: the first cut added a second
:class to a <button> that already had one, and Vue rejects a duplicate
attribute, so the SFC did not parse. check:sfc-parse said so IMMEDIATELY --
and I had piped it through `head -2`, which printed its counting line and
cut off the FAIL beneath. The block count fell 133 -> 132 in that same
output, I noticed, and then checked script TAGS rather than parseability and
talked myself out of it. Two separate signals, both read past. The two
bindings are merged into one; the count is 133 again.
2026-09-27 06:04:07 +00:00
..
api The people-group list is a universal prop: the same maps can show any project's list 2026-09-26 05:16:02 +00:00
colors The legends mirror now, and their labels never became their values 2026-09-26 22:06:58 +00:00
components Square map controls, as an option beside the round ones 2026-09-27 06:04:07 +00:00
composables Every shadow root honours prefers-reduced-motion 2026-09-27 05:05:04 +00:00
constants Every runtime CDN script and stylesheet is an exact version with an integrity hash 2026-09-26 05:50:24 +00:00
data Country names in the reader's language, for all 242 2026-09-27 04:14:31 +00:00
i18n gospel: the tables page's 14 titles and 112 column headers, in 11 locales 2026-09-27 04:14:31 +00:00
layouts Decouple the library's prose: no host-platform names in the QA widget, StackLayout or script notes 2026-09-26 17:28:45 +00:00
lists List names speak the reader's language: listLabel and listDefinition 2026-09-26 08:39:52 +00:00
maps Map labels ask for a font the engine's glyph server has: one shared helper 2026-09-25 13:48:10 +00:00
packet A packet says which list it holds, in the reader's language 2026-09-26 08:39:54 +00:00
scripts Svalbard carries its own data, not Norway's 2026-09-27 05:05:04 +00:00
stores Make the map's clustering picker real: four options, four different maps 2026-09-25 16:16:46 +00:00
styles Fiord: the MapLibre dark that actually looks like the map it replaces 2026-09-24 02:26:14 +00:00
utils Say where the country-name helper must not be used 2026-09-27 04:14:31 +00:00
vendor/cldr Country names in the reader's language, for all 242 2026-09-27 04:14:31 +00:00
index.js Move internal files out of the repo; fix five dead links; a fuller delegation diagram 2026-09-25 05:14:10 +00:00
ProfileLoader.vue Decouple the library's prose: no host-platform names in the QA widget, StackLayout or script notes 2026-09-26 17:28:45 +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.