From 13efc1a5d1ddc00cff7b747c5010fb58898ac030 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Mon, 28 Sep 2026 08:01:07 +0000 Subject: [PATCH] Update from source d8baaefd2 --- .../country-posters/countries-map.meta.json | 5 + .../country-posters/countries-map.vue | 52 ++++- .../country-poster-wall.meta.json | 5 + .../doxa-simple-map/doxa-simple-map.meta.json | 1 + .../country-posters/countries-map/index.html | 2 +- .../country-poster-wall/index.html | 2 +- .../country-posters-mfe/index.html | 2 +- .../country-posters/country-posters.js | 208 +++++++++--------- public/dx-maps/doxa-maps-spa/manifest.json | 11 +- public/dx-maps/manifest.json | 11 +- 10 files changed, 176 insertions(+), 123 deletions(-) create mode 100644 plugin-designs/country-posters/countries-map.meta.json create mode 100644 plugin-designs/country-posters/country-poster-wall.meta.json diff --git a/plugin-designs/country-posters/countries-map.meta.json b/plugin-designs/country-posters/countries-map.meta.json new file mode 100644 index 00000000..70ec7e8a --- /dev/null +++ b/plugin-designs/country-posters/countries-map.meta.json @@ -0,0 +1,5 @@ +{ + "type": "single", + "label": "Country Posters — countries map", + "note": "The map pane of the Country Posters element (country-posters-mfe composes it); also embeddable alone." +} diff --git a/plugin-designs/country-posters/countries-map.vue b/plugin-designs/country-posters/countries-map.vue index 3c08da7f..96108c68 100644 --- a/plugin-designs/country-posters/countries-map.vue +++ b/plugin-designs/country-posters/countries-map.vue @@ -1252,7 +1252,8 @@ async function openPacket() { // // library/composables/usePosterPrints.js ALREADY has printPacket: the same pages, authored as HTML // with @page rules, printed in place. This map was running a private second implementation of a - // shared product feature. Routing to it deletes the duplicate, drops jspdf from this bundle, and + // shared product feature. Routing to it deletes the duplicate (jspdf itself stays: useMapPoster.toPdf + // still brings it in for the poster, and the bundle grew with the HTML renderer), and // the packet gains the pages the shared renderer has that the local one never did (the life // calendar, the funnel, the prayer wheel — see packet-render.buildPacket's page order). const [{ usePosterPrints }, { defaultPosterSpec }, { useMapPoster }] = await Promise.all([ @@ -1261,12 +1262,30 @@ async function openPacket() { import('@map/composables/poster/useMapPoster.js'), ]) - // Same 50-group cap as before: an overnight safety limit, not a design choice. - let groups = mapData.normalizedPeopleGroups.value || [] - if (groups.length > 50) { - console.warn(`[country-posters] packet export truncated ${groups.length} → 50 people groups`) - groups = groups.slice(0, 50) - } + // ★ THE PACKET IS THE SELECTION, not the first 50 loaded groups (rega: "Asia" printed Sudan). + // library/maps/pin-selection.js reads the pins as DRAWN (their properties are derived: filled-in + // language family, canonical region keys), so a row filter would pick a plausible WRONG subset. + // This map has no dim expression, so the pins layer's own filter is the whole selection. + const all = mapData.normalizedPeopleGroups.value || [] + let groups = all + try { + const { selectedPinIds } = await import('@map/maps/pin-selection.js') + const m = map.value + const filt = m && m.getLayer('language-family-pins') ? m.getFilter('language-family-pins') : null + const ids = m ? selectedPinIds(m, { expressions: [filt].filter(Boolean) }) : null + if (ids && ids.size) { + const picked = all.filter((g) => ids.has(String(g.uniqueId ?? g.id ?? ''))) + // ids but no rows is an ID MISMATCH, not an empty selection: print everything and say so, + // rather than a packet about nothing. + if (picked.length) groups = picked + else console.warn('[country-posters] packet: the selected pins matched no rows (id mismatch); printing the full list') + } else if (ids) { + groups = [] // a genuinely empty selection: the printer's own "no records" error says so + } + } catch (e) { console.warn('[country-posters] packet selection unavailable; printing the full list:', e?.message || e) } + // Same 50-group cap as before: an overnight safety limit, not a design choice. The cover says so. + const selectedTotal = groups.length + if (groups.length > 50) groups = groups.slice(0, 50) // ★ AN EXPLICIT ADAPTER, because the two halves name the same fields differently and a mismatch // here is SILENT — the packet would print with blank names and empty photos rather than failing. @@ -1313,7 +1332,7 @@ async function openPacket() { const zone = { id: String(activeTab.value?.id || 'research-map'), - label: legendTitle.value || tabLabel(activeTab.value) || 'Doxa Map', + label: (legendTitle.value || tabLabel(activeTab.value) || 'Doxa Map') + (selectedTotal > 50 ? ` — 50 of ${selectedTotal}` : ''), zoneKey: String(activeTab.value?.id || 'research-map'), } const prints = usePosterPrints({ @@ -1407,6 +1426,23 @@ async function ensureRegionsLoaded() { const regionsData = await mapData.loadRegionsData?.() if (regionsData && map.value) { mapLayers.addRegionsLayer?.(regionsData, 'doxa-regions') + // PRE-WARM the shader variant here, while a large GeoJSON is loading anyway. highlightCountryByIso + // turns these three paints DATA-DRIVEN on a click; the first time that costs a one-off shader + // compile (rega on research-map: 5.5 s MapLibre / 11.1 s Mapbox under SwiftShader). Painting each + // current value through a case with two identical branches keeps the look and moves the compile + // off the gesture. All three, or the other two still compile on the click (simpleresearch). + // "Already data-driven" means the value READS THE FEATURE somewhere, not merely that it is an + // array: a zoom-only interpolate is an array and still compiles a variant on the first gesture + // (simpleresearch). Anything keyed on a feature is left exactly as the layer wrote it. + const readsFeature = (e) => Array.isArray(e) && (e[0] === 'get' || e[0] === 'has' || e[0] === 'feature-state' || e.some(readsFeature)) + for (const [layer, prop] of [['regions-fill', 'fill-opacity'], ['regions-border', 'line-color'], ['regions-border', 'line-width']]) { + try { + const v = map.value.getLayer(layer) && map.value.getPaintProperty(layer, prop) + if (v != null && !readsFeature(v)) { + map.value.setPaintProperty(layer, prop, ['case', ['in', ['get', 'iso_3166_1_alpha_3'], ['literal', []]], v, v]) + } + } catch (_) { /* a style without the layer: nothing to warm */ } + } // Hide regions on non-Doxa-Regions tabs so they don't show through. if (map.value.getLayer('regions-fill') && activeTab.value?.id !== 'doxa-regions') { map.value.setLayoutProperty('regions-fill', 'visibility', 'none') diff --git a/plugin-designs/country-posters/country-poster-wall.meta.json b/plugin-designs/country-posters/country-poster-wall.meta.json new file mode 100644 index 00000000..ae9b999f --- /dev/null +++ b/plugin-designs/country-posters/country-poster-wall.meta.json @@ -0,0 +1,5 @@ +{ + "type": "single", + "label": "Country Posters — poster wall", + "note": "The printable poster wall pane of the Country Posters element (country-posters-mfe composes it); also embeddable alone." +} diff --git a/plugin-designs/doxa-simple-map/doxa-simple-map.meta.json b/plugin-designs/doxa-simple-map/doxa-simple-map.meta.json index 6d3ae69b..0da75c4a 100644 --- a/plugin-designs/doxa-simple-map/doxa-simple-map.meta.json +++ b/plugin-designs/doxa-simple-map/doxa-simple-map.meta.json @@ -1,4 +1,5 @@ { + "label": "Prayer Progress — prayer map", "stage": "production", "_comment": "Prayer Progress is a production map: the Plugin Studio and the gallery list it outside Experimental (stage is read into manifest.json by generate-tree)." } diff --git a/public/dx-maps/country-posters/countries-map/index.html b/public/dx-maps/country-posters/countries-map/index.html index 455416dd..64fbfd7e 100644 --- a/public/dx-maps/country-posters/countries-map/index.html +++ b/public/dx-maps/country-posters/countries-map/index.html @@ -36,7 +36,7 @@ - + - + - + \n\n" + "script": "\n\n\n\n" } }, { "profile": "country-poster-wall", "stage": "experimental", + "label": "Country Posters — poster wall", "file": "country-poster-wall.vue", "description": "One printable card per country, grouped into COLLAPSIBLE regional sections so the", "element": "country-posters-map", @@ -204,7 +206,7 @@ "scriptUrl": "./country-posters/country-posters.js", "embed": { "iframe": "", - "script": "\n\n" + "script": "\n\n" } }, { @@ -220,7 +222,7 @@ "scriptUrl": "./country-posters/country-posters.js", "embed": { "iframe": "", - "script": "\n\n\n\n" + "script": "\n\n\n\n" } } ] @@ -431,6 +433,7 @@ { "profile": "doxa-simple-map", "stage": "production", + "label": "Prayer Progress — prayer map", "file": "doxa-simple-map.vue", "description": "The simple world map, shipped as three presets off ONE prop table —", "element": "doxa-map", diff --git a/public/dx-maps/manifest.json b/public/dx-maps/manifest.json index 588f643b..8ae2c29a 100644 --- a/public/dx-maps/manifest.json +++ b/public/dx-maps/manifest.json @@ -167,7 +167,7 @@ "bundle": "country-posters", "scriptUrl": "./country-posters/country-posters.js", "output": "dx-maps/country-posters/country-posters.js", - "integrity": "sha384-toNru0aS5EWD+nQu5sHLNTA4yymbYAGM0bok5vTAqb1wDamtqeFg+qTS0C0ExrTY", + "integrity": "sha384-CvAn6ZBYlPM0nIXmcfYBAR2ziHHVumz+Im40Oe69o1ta0irtH7sxhnEc2J2oxnWJ", "elements": [ "country-posters-map" ], @@ -180,6 +180,7 @@ { "profile": "countries-map", "stage": "experimental", + "label": "Country Posters — countries map", "file": "countries-map.vue", "description": "The researcher's workbench retargeted from people groups to COUNTRIES — region", "element": "country-posters-map", @@ -189,12 +190,13 @@ "scriptUrl": "./country-posters/country-posters.js", "embed": { "iframe": "", - "script": "\n\n\n\n" + "script": "\n\n\n\n" } }, { "profile": "country-poster-wall", "stage": "experimental", + "label": "Country Posters — poster wall", "file": "country-poster-wall.vue", "description": "One printable card per country, grouped into COLLAPSIBLE regional sections so the", "element": "country-posters-map", @@ -204,7 +206,7 @@ "scriptUrl": "./country-posters/country-posters.js", "embed": { "iframe": "", - "script": "\n\n" + "script": "\n\n" } }, { @@ -220,7 +222,7 @@ "scriptUrl": "./country-posters/country-posters.js", "embed": { "iframe": "", - "script": "\n\n\n\n" + "script": "\n\n\n\n" } } ] @@ -431,6 +433,7 @@ { "profile": "doxa-simple-map", "stage": "production", + "label": "Prayer Progress — prayer map", "file": "doxa-simple-map.vue", "description": "The simple world map, shipped as three presets off ONE prop table —", "element": "doxa-map",