From 87bd98d610cdd6ff9c1e04c6a783abc67939c63a Mon Sep 17 00:00:00 2001
From: doxa-maps-88655c70
<88627970+doxa-maps-88655c70@users.noreply.github.com>
Date: Thu, 24 Sep 2026 10:02:22 +0000
Subject: [PATCH] =?UTF-8?q?Restore=20the=20clickable=20poster=20preview=20?=
=?UTF-8?q?=E2=80=94=20the=20last=20capability=20the=20migration=20dropped?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Migrating my-upg-100-list onto the shared wall left one behind, and it was not
decoration: clicking the poster preview opened it for printing, a Driver-named
behaviour ("show the poster in the browser to help print it"). I removed it, so
this is a regression I introduced and am closing.
previewAction: 'none' | 'print'. Default 'none' keeps the image inert, which is
exactly what country-posters and key-cities render today.
★ IT IS A KEYBOARD CONTROL, NOT JUST A CLICK TARGET. The original carried
role="button", tabindex="0" and Enter/Space handlers alongside @click. Re-adding
the click alone would have been a half-restoration that LOOKS complete — an
with only @click is unreachable without a mouse, and the focus-visible outline is
how a keyboard user sees where they are on a control that is otherwise a picture.
The alt and title change with the mode too: "prayer poster" and "click to preview
and print" are different promises to a screen reader.
buttons.previewPrintPoster added to all eleven locales in the same change;
check:i18n-parity still reports 0 keys of debt.
VERIFIED AT THE RENDERED LAYER, and exercised BY KEYBOARD rather than by mouse:
100-list (preview-action="print") — 27 previews, is-clickable, role=button,
tabindex=0, cursor zoom-in, translated title, descriptive alt. Focused the image
and dispatched ENTER: 1 print frame opened, 0 downloads, 0 errors, with every
.webp ABORTED so it ran through the rasterise fallback.
country-posters (default) — 174 previews, is-clickable false, role null,
tabindex null, original alt. Inert exactly as before.
That completes the consolidation: my-upg-100-list 890 -> 179 lines, and all four
walls now render from one 633-line component with nothing left unported.
---
library/components/poster/PosterWall.vue | 34 ++++-
library/i18n/locales/ar/buttons.json | 1 +
library/i18n/locales/de/buttons.json | 1 +
library/i18n/locales/en/buttons.json | 3 +-
library/i18n/locales/es/buttons.json | 1 +
library/i18n/locales/fr/buttons.json | 1 +
library/i18n/locales/hi/buttons.json | 1 +
library/i18n/locales/it/buttons.json | 1 +
library/i18n/locales/pt/buttons.json | 1 +
library/i18n/locales/ro/buttons.json | 1 +
library/i18n/locales/ru/buttons.json | 1 +
library/i18n/locales/zh/buttons.json | 1 +
.../my-upg-100-list/poster-wall.vue | 1 +
public/__gallery/index.html | 2 +-
.../all-people-groups/all-people-groups.js | 40 +++---
.../all-people-groups/index.html | 2 +-
.../cities-internet/cities-internet.js | 38 ++---
.../connectivity-list/index.html | 2 +-
.../connectivity-map/index.html | 2 +-
.../cities-internet/data-tables/index.html | 2 +-
.../country-posters/countries-map/index.html | 2 +-
.../country-poster-wall/index.html | 2 +-
.../country-posters-mfe/index.html | 2 +-
.../country-posters/country-posters.js | 130 +++++++++---------
.../dashboard-plus-grid.js | 64 ++++-----
.../dashboard-plus-grid/default/index.html | 2 +-
.../dashboard-plus-grid/index.html | 2 +-
public/doxa-maps/demo-map/demo-map.js | 46 +++----
public/doxa-maps/demo-map/demo-map/index.html | 2 +-
.../demo-map/demo-map/maplibre/index.html | 2 +-
.../doxa-research-map/doxa-research-map.js | 2 +-
.../doxa-research-map/research-map/index.html | 2 +-
.../research-map/maplibre/index.html | 2 +-
.../doxa-simple-map/doxa-simple-map.js | 56 ++++----
.../doxa-simple-map/adoption/index.html | 2 +-
.../doxa-simple-map/engagement/index.html | 2 +-
.../doxa-simple-map/index.html | 2 +-
.../doxa-simple-map/prayer/index.html | 2 +-
.../gospel-resources/charts/index.html | 2 +-
.../gospel-resources/data-tables/index.html | 2 +-
.../gospel-resources/gospel-resources.js | 2 +-
.../resources-list/index.html | 2 +-
.../gospel-resources/resources-map/index.html | 2 +-
public/doxa-maps/index.html | 2 +-
public/doxa-maps/key-cities/key-cities.js | 104 +++++++-------
public/doxa-maps/manifest.json | 76 +++++-----
.../my-upg-100-list/my-upg-100-list.js | 126 ++++++++---------
.../my-upg-100-list/poster-wall/index.html | 2 +-
.../my-upg-100-list/upg-100-list/index.html | 2 +-
.../my-upg-100-list/upg-100-mfe/index.html | 2 +-
.../prayer-walk-planner.js | 20 +--
.../prayer-walk-planner/index.html | 2 +-
.../region-dashboards/index.html | 2 +-
.../regions-dashboard/regions-dashboard.js | 130 +++++++++---------
.../regions-dashboard/regions-list/index.html | 2 +-
.../regions-dashboard/regions-mfe/index.html | 2 +-
.../research-dashboard/research-dashboard.js | 48 +++----
.../research-dashboard/index.html | 2 +-
.../template-bundle/template-bundle.js | 26 ++--
.../template-bundle/template-map-a/index.html | 2 +-
.../template-bundle/template-map-b/index.html | 2 +-
61 files changed, 532 insertions(+), 490 deletions(-)
diff --git a/library/components/poster/PosterWall.vue b/library/components/poster/PosterWall.vue
index ad6000827..8f29713dc 100644
--- a/library/components/poster/PosterWall.vue
+++ b/library/components/poster/PosterWall.vue
@@ -116,6 +116,18 @@ const props = defineProps({
// reintroduced both rejected buttons — the capability gap was never the whole
// blocker; the shared component still encoded the pre-brief design.
posterAction: { type: String, default: 'download' }, // 'download' | 'print'
+ // ★ IS THE PREVIEW ITSELF A CONTROL? Default 'none' keeps the image inert, which is
+ // what country-posters and key-cities render today. 'print' makes clicking the
+ // poster preview open it for printing — a Driver-named behaviour ("show the poster
+ // in the browser to help print it"), and the LAST capability the my-upg-100-list
+ // migration had not carried across.
+ // ⚠ WHEN IT IS A CONTROL IT MUST BE A KEYBOARD CONTROL. The original carried
+ // role="button", tabindex="0" and Enter/Space handlers alongside the click; an
+ //
with only @click is unreachable without a mouse, and re-adding the click
+ // alone would be a half-restoration that LOOKS complete. The alt and title change
+ // with the mode too, because "prayer poster" and "click to preview and print" are
+ // different promises to a screen reader.
+ previewAction: { type: String, default: 'none' }, // 'none' | 'print'
// Hide the Prayer List button entirely, rather than showing it as a
// "coming soon" placeholder. The placeholder is honest where the feature is
// genuinely unbuilt, and it is the OTHER button the Driver objected to on a wall
@@ -311,6 +323,7 @@ const prints = usePosterPrints({
label: (item) => item?.label || item?.id || '',
})
const canPrintRows = computed(() => typeof props.records === 'function')
+const previewIsControl = computed(() => props.previewAction === 'print')
function downloadPacket(item) {
// Still the honest "not yet" when this wall has no records provider: NOT an
@@ -442,6 +455,12 @@ useShadowStyles(
'background:#fff;color:#5b6672;font:inherit;font-size:9.5px;font-weight:600;' +
'padding:2px 4px;cursor:pointer;line-height:1.25}' +
'.pstock:hover{border-color:#10b981;color:#10b981}' +
+ // previewAction='print' only. The zoom-in cursor says "this opens something", and
+ // the focus-visible outline is not optional: it is how a keyboard user sees where
+ // they are on a control that is otherwise just a picture.
+ '.img.is-clickable{cursor:zoom-in}' +
+ '.img.is-clickable:hover{outline:2px solid #38bdf8;outline-offset:-2px}' +
+ '.img.is-clickable:focus-visible{outline:2px solid #38bdf8;outline-offset:-2px}' +
'.is-dark .pstock{background:#12211a;border-color:#2c4a3b;color:#9fb3a8}' +
'.is-dark .pbtn{color:#9fb3a8}' +
// The section is the sticky header's CONTAINING BLOCK: a sticky element only
@@ -572,9 +591,20 @@ useShadowStyles(