Commit graph

5 commits

Author SHA1 Message Date
Doxa Maps
5520587417 A collapsed legend reopens itself after you close a people-group detail
Collapse the legend, tap a pin, then close the detail: the legend comes back
open, though nothing asked it to. Reported against the leaf research map;
reproduced at 1440 in en, collapsed-first.

selectPeopleGroup saved the pre-detail legend state on every call that carried
a group, not only on the call that entered detail. The second call therefore
saved the 'open' the first call had just forced, on top of the 'collapsed' it
correctly saved on entry, and closing the detail restored that 'open'.

The measured part is why a second call happens at all. The pin click handler is
registered per map layer, and every visible pin has an invisible hitbox twin at
the same point -- same source, larger radius, added alongside it so taps are
easier to land. A layer-scoped click fires once per layer with a feature under
the point, so a single pin click calls selectPeopleGroup exactly twice, 3ms
apart. Measured on two different pins, both reporting both layers at the click
point; never more than twice. So ONE pick was already enough to lose the
collapsed state -- it never needed two, which is why this reproduced every time
rather than intermittently.

The fix is to make the method idempotent: save only when entering detail (no
group was selected before), restore only what was actually saved, then clear it
so a later detail cannot inherit a stale value. The duplicate binding is a real
defect in its own right and is tracked separately; this method should not have
depended on being called exactly once.

Verified two-sided against the shipped source, driving the real method body
rather than a copy: seven scenarios pass on the fix and four fail with the
previous body restored, while the scenarios that must be insensitive stay green
both ways. The poisoned run reproduces the browser measurement value for value
-- saved collapsed, overwritten to open by the second call, restored open.
Trace in _qa-cycle so the next reader can re-run it.
2026-09-29 11:56:47 +00:00
doxa-maps-88655c70
849cd61022 Make the map's clustering picker real: four options, four different maps
Choosing "Native" in the research map's side menu drew nothing. So did MST, and
so did Network. A control that does nothing is worse than one that is absent:
it tells the reader the map cannot do what it can.

TWO CAUSES, AND FIXING EITHER ALONE WOULD HAVE LOOKED LIKE A FIX.

  1. mapStore never declared `clusteringMode`. The picker wrote to a property no
     reactive system was watching, so useMapClustering's `mode` kept its own
     internal default and the click changed nothing.
  2. The legend's Clusters checkbox force-set 'mst' "regardless of what's in the
     store", with the mode watcher "kept as a no-op for forwards compat" — its
     own words. Even with (1) fixed, one tick of that checkbox would have snapped
     Native back to MST: a control that works until you touch the other one.

So the two controls are now two views of one state. clusteringMode IS the state
('off' means disabled); the picker sets it; the checkbox maps onto it, promoting
only 'off' to 'mst' so the checkbox alone behaves exactly as it always has. They
can no longer show different things. The dim-slider's clusterPinOpacity got a
real home in the same pass, for the same reason it was missing.

★ THE GATE ASSERTS ON WHAT IS DRAWN, NOT ON WHAT IS SET. `clusteringMode ===
'mapbox'` would have passed the moment (1) was fixed, while the map still drew
MST lines — state was exactly the evidence that let an inert control ship. The
map now reports, per clustering layer, whether it exists, whether it is visible
and how many features are rendered; the gate clicks the real buttons and reads
that. MEASURED, before and after, on the same tree:

    before   off 0/0/0   native 0/0/0     mst 0/0/0       network 0/0/0
    after    off 0/0/0   native 37/37/0   mst 0/0/1700    network 0/0/23896
                        (circles/counts/lines)

It also asserts no orphan layers between modes, and that MST and Network differ
— two labels for one behaviour is the same defect as a dead option.

One measurement bug caught on the way, worth recording: a fixed 6-second pause
reported MST as drawing nothing while Network drew thousands of lines. MST over
~2,100 pins is quadratic and had simply not finished. The gate now waits for the
drawing to settle rather than guessing a duration — a gate that calls a slow
feature broken is worse than no gate.
2026-09-25 16:16:46 +00:00
doxa-maps
1cd2b46cd5 fix(spa): make embedded maps survive the sandboxed plugin iframe
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Three fixes for the power-app SPA running as a go-base plugin (sandboxed
iframe, origin 'null' — where localStorage throws and root-absolute asset
paths misresolve under the /plugin-assets/<name>/ subpath):

- localStorage: wrap every theme/preference read+write in try/catch across
  the library (ProfileLoader, useMapTheme, uiStore). `typeof localStorage`
  is not enough — in a sandbox the object exists but ACCESS throws
  SecurityError. Sandboxed maps now boot themeless instead of crashing.
- assets: the SPA shell now injects an absolute assetsBase (derived from its
  own document.baseURI) into every mounted element's profile-config, so
  bundles fetch tables/vendor (Tabulator) from the correct subpath instead
  of a root-absolute /assets that 404s under /plugin-assets/doxa-maps-spa/.
- nav: revert the Prayer Mobilization section icon to 'heart' (the prayer
  glyph read as a header it is not).

Rebuilds every bundle (library-wide localStorage change).
2026-09-12 21:07:26 +00:00
doxa-maps
35ac1c5607 docs: simplify all folder READMEs (what's here + graphic + link); migrate complex reference to docs/architecture/{data-sources,i18n,components,app-wrappers,poster-generation}.md 2026-09-11 18:50:31 +00:00
doxa-maps
d5ba21fa76 doxa-maps — portable bundler for embeddable JAMstack maps
Standalone repo that builds embeddable JAMstack map bundles (web components),
composes them into a lazy-loaded SPA via layouts/, and optionally wraps a
Capacitor Android/iOS app — one build, choose your output/CDN. Diátaxis docs.

History reset to a single clean commit; no PII, IPs, or internal terms.
2026-09-10 01:53:07 +00:00