From a45f1914a6a93d0adbedbc269a26ad536e7cf5e0 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Mon, 28 Sep 2026 17:47:40 +0000 Subject: [PATCH] Let the legend collapse on desktop, the way it already does on mobile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mobile has had a fold control since the narrow layout existed; desktop had none, so a reader who wanted to see the map underneath had no way to move the legend off it. The state was already there — every section read "not narrow OR open", so on desktop the OR was always satisfied and the flag governed nothing. Now the flag alone decides at both widths. The control is deliberately not a new one. Same 22x20 caret, same rotation, same aria contract as the shared SemanticTreeLegend's collapse button, which the mobile legend also copies. Matching it costs nothing and means a reader who has met one of these legends has met this one. Collapsed, the panel shrinks to the caret. Hiding the contents alone would have left a 380px box of empty background over the map: the reader presses collapse and gets a blank panel instead of their map, which is worse than having no control at all. The choice is remembered for the session, so it survives working with the map but not a fresh visit, and a remembered choice beats the width default — otherwise dragging a window across the breakpoint would silently reopen a legend that had been deliberately closed, undoing a decision rather than responding to one. Storage access is wrapped: a sandboxed embed throws on it, and a legend that cannot remember is much better than a map that will not load. --- .../gospel-resources/resources-map.vue | 71 ++++++++++++++++--- public/dx-maps/doxa-maps-spa/manifest.json | 12 ++-- .../gospel-resources/charts/index.html | 2 +- .../gospel-resources/data-tables/index.html | 2 +- .../gospel-dashboard/index.html | 2 +- .../gospel-resources/gospel-resources.js | 44 ++++++------ .../resources-list/index.html | 2 +- .../gospel-resources/resources-map/index.html | 2 +- public/dx-maps/manifest.json | 12 ++-- 9 files changed, 100 insertions(+), 49 deletions(-) diff --git a/plugin-designs/gospel-resources/resources-map.vue b/plugin-designs/gospel-resources/resources-map.vue index 0650c28a4..dae1fb796 100644 --- a/plugin-designs/gospel-resources/resources-map.vue +++ b/plugin-designs/gospel-resources/resources-map.vue @@ -542,12 +542,34 @@ function openFromUrl() { // "a red dot can sit on a green country" is the thing that stops a correct map reading as // a bug, so it stays one tap away rather than being dropped on small screens. const narrow = ref(false) +// ONE state for both widths. It used to govern the mobile sheet only — every section read +// `!narrow || legendOpen`, so on desktop the legend was always open and there was no way to +// shut it. Now `legendOpen` alone decides, and desktop gets the same collapse control mobile +// has always had. const legendOpen = ref(true) +// Remembered for the SESSION, not forever: a reader who collapses the legend to see the map +// wants it to stay collapsed while they work, and wants a fresh visit to start from the +// designed state rather than from a decision they made once and forgot. sessionStorage is +// exactly that lifetime. Wrapped because a sandboxed or storage-blocked embed throws on +// access, and a legend that cannot remember is far better than a map that will not load. +const LEGEND_KEY = 'gm.legendOpen' +function rememberLegend(v) { + try { window.sessionStorage?.setItem(LEGEND_KEY, v ? '1' : '0') } catch (_) {} +} +function recallLegend() { + try { const v = window.sessionStorage?.getItem(LEGEND_KEY); return v == null ? null : v === '1' } + catch (_) { return null } +} +function toggleLegend() { legendOpen.value = !legendOpen.value; rememberLegend(legendOpen.value) } function syncNarrow() { const n = typeof window !== 'undefined' && window.innerWidth < 700 if (n === narrow.value) return narrow.value = n - legendOpen.value = !n + // A remembered choice wins over the width default. Without this, dragging a window across + // the breakpoint would silently reopen a legend the reader had deliberately closed — the + // resize would be undoing their decision rather than responding to it. + const remembered = recallLegend() + legendOpen.value = remembered == null ? !n : remembered } if (typeof window !== 'undefined') { syncNarrow() @@ -1950,6 +1972,21 @@ useShadowStyles( // Narrow screens: the rail is still on the right, so the legend must stop short // of it rather than run under it. 46px = 32px button + 3px inset + clearance. '@media(max-width:480px){.gm-legend{width:auto;inset-inline-end:46px}}' + + // The caret's box matches .stl-collapse-btn exactly (22x20, 5px radius, 1px border) so the + // two legends read as the same control. The colours are this map's, because the palette is + // the map's and the geometry is the fleet's. + // Collapsed, the panel must SHRINK TO THE CARET. Hiding the contents alone would leave a + // 380px box of empty background sitting over the map — the reader would have pressed + // collapse and got a blank panel instead of their map back, which is worse than no control. + '.gm-legend.closed{width:auto;padding:4px;background:rgba(243,243,241,.92)}' + + '.gm-legend.closed .gm-collapse{position:static;inset:auto}' + + '.gm-collapse{position:absolute;inset-block-start:8px;inset-inline-end:8px;width:22px;height:20px;' + + 'display:flex;align-items:center;justify-content:center;background:rgba(209,212,205,.4);' + + 'border:1px solid #d1d4cd;border-radius:5px;cursor:pointer;color:#6d766e;padding:0;' + + 'transition:transform .3s ease-out,color .1s,background .1s;transform-origin:center}' + + '.gm-collapse:hover{color:#3b463d;background:rgba(146,177,149,.25);border-color:#92b195}' + + '.gm-collapse svg{transition:transform .18s;transform:rotate(180deg)}' + + '.gm-collapse.closed svg{transform:rotate(0deg)}' + '.is-dark .gm-legend{background:rgba(19,32,25,.95);color:#e5e7eb}' + '.gm-title{font-weight:700;font-size:15.5px;margin-bottom:5px}' + '.gm-keys{display:flex;flex-wrap:wrap;gap:5px 12px}' + @@ -2172,7 +2209,7 @@ useShadowStyles( -
+
+ + -
+
{{ mode === 'gap' ? t('gospel.legend.title') : t('gospel.legend.titleCoverage') }}
-
+
{{ t(b.labelKey) }}
-
+
-
+
-
+
Showing only {{ pinFilter === 'none' ? 'groups with nothing found' : pinFilter === 'some' ? 'groups with some resource' : pinFilter === 'hnr' ? 'groups that can hear the gospel but have no text Scripture in the pools checked' @@ -2313,7 +2364,7 @@ useShadowStyles( -
+
{{ t('gospel.prose.english') }}
-
+
{{ t('gospel.guide.dotVsCountry') }}
{{ t('gospel.guide.noneFoundShort') }}
{{ t('gospel.guide.tapCountry') }} diff --git a/public/dx-maps/doxa-maps-spa/manifest.json b/public/dx-maps/doxa-maps-spa/manifest.json index 883ea870f..37d735d9a 100644 --- a/public/dx-maps/doxa-maps-spa/manifest.json +++ b/public/dx-maps/doxa-maps-spa/manifest.json @@ -742,7 +742,7 @@ "bundle": "gospel-resources", "scriptUrl": "./gospel-resources/gospel-resources.js", "output": "dx-maps/gospel-resources/gospel-resources.js", - "integrity": "sha384-dr1KyHZ1s+ot5QjWWZrVN972zBZw9Ad8IrcvLvTjme50GkZU/kUJqIeVaEQ7AhzK", + "integrity": "sha384-Q+U6QnOArHlw2zKO9+1ORyLH1vKjFWjiACEehXFS+7lO8yaTujslwq0WzFejtujP", "elements": [ "gospel-resources-map" ], @@ -765,7 +765,7 @@ "scriptUrl": "./gospel-resources/gospel-resources.js", "embed": { "iframe": "", - "script": "\n\n\n" + "script": "\n\n\n" } }, { @@ -781,7 +781,7 @@ "scriptUrl": "./gospel-resources/gospel-resources.js", "embed": { "iframe": "", - "script": "\n\n\n" + "script": "\n\n\n" } }, { @@ -797,7 +797,7 @@ "scriptUrl": "./gospel-resources/gospel-resources.js", "embed": { "iframe": "", - "script": "\n\n\n\n\n" + "script": "\n\n\n\n\n" } }, { @@ -813,7 +813,7 @@ "scriptUrl": "./gospel-resources/gospel-resources.js", "embed": { "iframe": "", - "script": "\n\n\n" + "script": "\n\n\n" } }, { @@ -829,7 +829,7 @@ "scriptUrl": "./gospel-resources/gospel-resources.js", "embed": { "iframe": "", - "script": "\n\n\n\n\n" + "script": "\n\n\n\n\n" } } ] diff --git a/public/dx-maps/gospel-resources/charts/index.html b/public/dx-maps/gospel-resources/charts/index.html index 60e1af8fc..28a650d59 100644 --- a/public/dx-maps/gospel-resources/charts/index.html +++ b/public/dx-maps/gospel-resources/charts/index.html @@ -32,7 +32,7 @@ - + - + - + - + - + \n\n\n" + "script": "\n\n\n" } }, { @@ -781,7 +781,7 @@ "scriptUrl": "./gospel-resources/gospel-resources.js", "embed": { "iframe": "", - "script": "\n\n\n" + "script": "\n\n\n" } }, { @@ -797,7 +797,7 @@ "scriptUrl": "./gospel-resources/gospel-resources.js", "embed": { "iframe": "", - "script": "\n\n\n\n\n" + "script": "\n\n\n\n\n" } }, { @@ -813,7 +813,7 @@ "scriptUrl": "./gospel-resources/gospel-resources.js", "embed": { "iframe": "", - "script": "\n\n\n" + "script": "\n\n\n" } }, { @@ -829,7 +829,7 @@ "scriptUrl": "./gospel-resources/gospel-resources.js", "embed": { "iframe": "", - "script": "\n\n\n\n\n" + "script": "\n\n\n\n\n" } } ]