From 168b1f1bd98d0de2eb3cfbfdacdd7a2529f491e3 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Tue, 29 Sep 2026 07:27:50 +0000 Subject: [PATCH] Country posters print their list, deck and packet, with the map drawn at the click The regions list showed a poster per country and could print the poster alone. Supplying a records provider is what makes the Prayer List, Card Deck and Prayer Packet buttons appear at all -- PosterWall hides them when a wall cannot supply rows, rather than failing at click time -- and this wall never supplied any. Records come from the shared provider, not a copy of anyone's fetch. It caches one request per language and every country in every region shares it, so opening five regions is still one request, and the same rows feed the sheet, so the printed map and the printed list cannot disagree about which groups are in a country. Page 1 is GENERATED, because there is nothing to load. No country sheet ships: data/posters holds 28 .html and all 28 are zones, and emit-countries.mjs writes only country-posters.json, whose `sheet` field is a paper size rather than a filename. So the packet's default lift asked for posters/country-.html and 404ed on all 175. country-sheet-print.js draws it instead, in the same shape as the zone sheet next door so the two surfaces cannot draw the same sheet two ways, and returns '' when there is no country or no rows so the caller falls through rather than printing an empty country. There is ONE loading path for the generator, not two: this calls generateCountrySheet, and posterSheets resolves the served, sha384-pinned poster-render.js itself. Nothing here fetches or imports the generator directly. MEASURED against the development baseline, both built here: 1044 -> 1061 KB, +17 KB. An earlier measurement of this same wiring on the pre-pinned base read +208 KB; almost all of that was the printing subsystem that is now served rather than bundled, so the cost fell by about 190 KB without this file changing. createPosterGenerator does not appear in the bundle. item-count-key replaces nothing: the noun pair still names the section, and the count now goes through the plural-aware key. --- .../regions-dashboard/regions-list.vue | 25 ++ .../src/country-sheet-print.js | 47 +++ public/dx-maps/doxa-maps-spa/manifest.json | 8 +- public/dx-maps/manifest.json | 8 +- .../region-dashboards/index.html | 2 +- .../regions-dashboard/regions-dashboard.js | 312 +++++++++--------- .../regions-dashboard/regions-list/index.html | 2 +- .../regions-dashboard/regions-mfe/index.html | 2 +- 8 files changed, 239 insertions(+), 167 deletions(-) create mode 100644 plugin-designs/regions-dashboard/src/country-sheet-print.js diff --git a/plugin-designs/regions-dashboard/regions-list.vue b/plugin-designs/regions-dashboard/regions-list.vue index 3803b1ccc..f3f06a8f0 100644 --- a/plugin-designs/regions-dashboard/regions-list.vue +++ b/plugin-designs/regions-dashboard/regions-list.vue @@ -67,6 +67,8 @@ import { DXLIFE_TOKENS } from './dxlife-tokens.js' import PosterWall from '@map/components/poster/PosterWall.vue' import RegionSectionCard from '@map/components/regions/RegionSectionCard.vue' import posterData from '@map/data/country-posters.json' +import { createPeopleGroupRecords } from '@map/lists/peopleGroupRecords.js' +import { makeCountrySheet } from './src/country-sheet-print.js' import { resolveAssetsBase } from '@map/utils/embedBase.js' import { onBeforeUnmount } from 'vue' import { cyrillicHeading } from '@map/styles/portedGlobals.js' @@ -277,6 +279,25 @@ const POSTER_EVENT = 'doxa-regions:show-country-on-map' // poster events. const instanceId = computed(() => cfg.value.instanceId || 'regions-list') const posterAssetsBase = computed(() => resolveAssetsBase(cfg.value)) + +// ★ THE PRINT ROWS, AND THE SHEET DRAWN FROM THEM. Supplying `records` is what makes the Prayer +// List, Card Deck and Prayer Packet buttons appear on each country (PosterWall hides them when a +// wall cannot supply rows, rather than failing at click time). One fetch per language, cached in +// the provider and shared by every country in every region, so opening five regions is still one +// request. The same provider feeds the sheet, so the printed map and the printed list can never +// disagree about which groups are in a country. +const countryRecords = createPeopleGroupRecords({ + apiBase: () => prayBaseUrl.value, + lang: () => languageCode.value, + profileConfig: injectedCfg, +}) +// Page 1 of a country packet, and the country poster, drawn at the click. Nothing is stored: no +// country sheet ships, and the packet's default lift would ask for posters/country-.html and +// 404 on all 175. +const countrySheet = makeCountrySheet({ + records: countryRecords, + assetsBase: () => posterAssetsBase.value, +}) const openPosters = ref(new Set()) function togglePosters(region) { @@ -527,6 +548,10 @@ useShadowStyles( unit="UPG" :item-noun="t('Country')" :item-noun-plural="t('Countries')" + item-count-key="regions.countryCount" + :records="countryRecords ? (item) => countryRecords({ type: 'country', values: [item.iso3] }) : null" + :sheet="countrySheet" + :card-stocks="true" :collapsible="false" :embedded="true" :section-heads="false" diff --git a/plugin-designs/regions-dashboard/src/country-sheet-print.js b/plugin-designs/regions-dashboard/src/country-sheet-print.js new file mode 100644 index 000000000..dfba0f571 --- /dev/null +++ b/plugin-designs/regions-dashboard/src/country-sheet-print.js @@ -0,0 +1,47 @@ +/** + * country-sheet-print.js — a country's map sheet, GENERATED in the browser at the click. + * + * The print standard is generate, store only previews: no country sheet is shipped, and none should + * be. MEASURED before this existed: data/posters holds 28 .html sheets and all 28 are ZONES, while + * emit-countries.mjs writes only country-posters.json, whose `sheet` field is a PAPER SIZE ('3x3') + * rather than a filename. So a packet's page-1 lift for a country asked for posters/country-.html + * and got a 404 for all 175 of them. This draws it instead. + * + * Same shape as my-upg-100-list's zone sheet (data/zone-sheet-print.js), deliberately, so the two + * surfaces cannot draw the "same" sheet two ways: + * + * const sheet = makeCountrySheet({ records, assetsBase: () => base }) + * usePosterPrints({ …, sheet }) // (item, format) -> html + * + * + * The country case is simpler than the zone case: generateCountrySheet resolves the zone and its + * geometry from the country entry itself, so there is no assignment step to keep in sync. + */ + +/** + * @param {object} o + * records (selector) => Promise the shared provider; this asks it for ONE country + * assetsBase () => string where boundaries/ is served from + * @returns {(item, format) => Promise} the sheet's HTML, or '' when it cannot be drawn + */ +export function makeCountrySheet({ records, assetsBase }) { + return async function countrySheet(item, format) { + const iso3 = item && item.iso3 + if (!iso3) return '' // a selection or a row without a country: no sheet + // Lazy, like the zone sheet: the generator and the boundary loader are only pulled when a + // reader actually prints, so they stay out of every wall's initial download. + const { generateCountrySheet } = await import('@map/packet/posterSheets.js') + const [{ ISO3_NAME }, rows] = await Promise.all([ + import('@map/data/iso3-name.js'), + records({ type: 'country', values: [iso3] }), + ]) + if (!rows || !rows.length) return '' // nothing to pin: fall through rather than draw an empty country + return generateCountrySheet({ + country: { id: item.id, iso3, label: item.label, count: item.count }, + records: rows, + assetsBase: assetsBase(), + ISO3_NAME, + format, + }) + } +} diff --git a/public/dx-maps/doxa-maps-spa/manifest.json b/public/dx-maps/doxa-maps-spa/manifest.json index bcaa2e361..58a102e1c 100644 --- a/public/dx-maps/doxa-maps-spa/manifest.json +++ b/public/dx-maps/doxa-maps-spa/manifest.json @@ -1110,7 +1110,7 @@ "bundle": "regions-dashboard", "scriptUrl": "./regions-dashboard/regions-dashboard.js", "output": "dx-maps/regions-dashboard/regions-dashboard.js", - "integrity": "sha384-RmFYhIWs0imk7jLNohHlJXnu0K8w7Q0Zt7N0nTIUAph0wmJzA8oaw/E0UsCnvggr", + "integrity": "sha384-s87DToh5nsLnHox93ut/oNUr7YlkI3T4XabQsEIq9W+WbNMoxurGMwKlOW6vS1V8", "elements": [ "regions-dashboard" ], @@ -1133,7 +1133,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n\n\n" + "script": "\n\n\n\n\n" } }, { @@ -1149,7 +1149,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n" + "script": "\n\n\n" } }, { @@ -1165,7 +1165,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n" + "script": "\n\n\n" } } ] diff --git a/public/dx-maps/manifest.json b/public/dx-maps/manifest.json index bcaa2e361..58a102e1c 100644 --- a/public/dx-maps/manifest.json +++ b/public/dx-maps/manifest.json @@ -1110,7 +1110,7 @@ "bundle": "regions-dashboard", "scriptUrl": "./regions-dashboard/regions-dashboard.js", "output": "dx-maps/regions-dashboard/regions-dashboard.js", - "integrity": "sha384-RmFYhIWs0imk7jLNohHlJXnu0K8w7Q0Zt7N0nTIUAph0wmJzA8oaw/E0UsCnvggr", + "integrity": "sha384-s87DToh5nsLnHox93ut/oNUr7YlkI3T4XabQsEIq9W+WbNMoxurGMwKlOW6vS1V8", "elements": [ "regions-dashboard" ], @@ -1133,7 +1133,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n\n\n" + "script": "\n\n\n\n\n" } }, { @@ -1149,7 +1149,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n" + "script": "\n\n\n" } }, { @@ -1165,7 +1165,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n" + "script": "\n\n\n" } } ] diff --git a/public/dx-maps/regions-dashboard/region-dashboards/index.html b/public/dx-maps/regions-dashboard/region-dashboards/index.html index 31bd516a4..73c90f4ed 100644 --- a/public/dx-maps/regions-dashboard/region-dashboards/index.html +++ b/public/dx-maps/regions-dashboard/region-dashboards/index.html @@ -65,7 +65,7 @@ - + - + - +