From 4b941be4bfa464cfec51df5b9459e8fea9507194 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Mon, 28 Sep 2026 06:47:13 +0000 Subject: [PATCH] Country posters: the packet prints the selected groups, not the first fifty loaded Choosing "Asia" in the legend printed the same first 50 groups as any other row, Sudan included. The packet now takes the pins the selection shows, through the shared library/maps/pin-selection.js (reading pins as drawn, not raw rows). Selected pins that match no rows fall back to the full list with a warning; an empty selection reaches the printer's own error; over 50, the cover says '50 of N'. --- .../country-posters/countries-map.vue | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/plugin-designs/country-posters/countries-map.vue b/plugin-designs/country-posters/countries-map.vue index fde9aa519..1da70ca9d 100644 --- a/plugin-designs/country-posters/countries-map.vue +++ b/plugin-designs/country-posters/countries-map.vue @@ -1262,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. @@ -1314,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({