Fix the poster URL helper's wrong extension, and correct a stale header
Some checks are pending
build-gate / build (push) Waiting to run

posterUrl() said .png. There are 378 poster .webp files and no matching .png, so
the helper could only ever have produced a 404 — but it was never called, because
the export and print paths each built the same URL inline. A dead helper carrying
a wrong constant is worse than no helper: it is primed to break whoever tidies up
by routing a call through it. Point it at .webp and route both callers through
it, so the format lives in one place.

The file header still said posters "DO NOT EXIST YET. Nothing has been generated."
378 previews are generated, shipped and served live, and the wall paints from
them. A reader following that line would go build a generator that already ran.
Replace it with what actually ships: previews by default, full-resolution posters
excluded because bundling them pushed the tree past what the catalog would accept.
This commit is contained in:
doxa-maps 2026-09-22 07:47:29 +00:00
parent b57aef457c
commit 914b0f0ca5
10 changed files with 57 additions and 36 deletions

View file

@ -21,10 +21,20 @@
* It dispatches a window CustomEvent scoped by instanceId, so several embeds on one
* page never cross-talk. The shell listens and drives the map pane.
*
* POSTERS DO NOT EXIST YET. Nothing has been generated, so every card currently
* falls back to a labelled placeholder via @error. That is deliberate: the wall is
* testable NOW, and generation (client-side, via the library's useMapPoster) lands
* next without changing this file's markup.
* ASSETS — TWO SIZES, ONE OF WHICH SHIPS (corrected 2026-09-22; this header used to say
* "POSTERS DO NOT EXIST YET. Nothing has been generated", which is no longer true and would
* send a reader off to build a generator that already ran):
* previews/<id>.webp — ~65KB each, 378 generated, SHIPPED in the default tree and served
* live. These are what the wall paints, fetched lazily per card.
* posters/<id>.webp — full print resolution, 378 generated, NOT shipped by default
* (~42MB). See IDEA-POSTER-EXPORT-404-ON-DROPPED-FOLDER-TRADEOFF:
* bundling them pushed the tree to 80MB, git-packed to 57MiB, and the
* catalog REJECTED the push — so the all-in version shipped nothing.
* Export and print-preview therefore 404 on a default drop and degrade
* honestly; set bundlePosters:true or point assetsBase at a host that
* serves posters/ to restore them.
* The @error fallback to a labelled placeholder is still live and still the right behaviour —
* it now covers the missing-poster case rather than the nothing-generated-yet case.
*/
import { computed, inject, ref, watch, onBeforeUnmount } from 'vue'
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
@ -40,7 +50,18 @@ const isDark = computed(() => profileConfig.value?.isDark === true)
// Assets resolve RELATIVE to the host page so the tree stays drop-portable —
// file://, a CDN subpath, Railway and Capacitor all behave identically.
const assetsBase = computed(() => String(profileConfig.value?.assetsBase || './assets').replace(/\/+$/, ''))
const posterUrl = (id) => `${assetsBase.value}/posters/${id}.png`
// Full-size print poster. `.webp` is the ONLY format that exists: data/posters/ holds 378 .webp
// and ZERO matching .png. This helper previously said `.png` and was UNCALLED — printPoster() and
// exportPoster() each built the same URL inline — so the wrong extension was invisible, sitting
// ready to break whoever "tidied up" by routing a call through it. Now it is the single source of
// truth for both, and a format change has ONE place to happen.
//
// NOTE the full-size posters are NOT shipped in the default tree (42MB): see
// IDEA-POSTER-EXPORT-404-ON-DROPPED-FOLDER-TRADEOFF. This URL 404s unless the publisher sets
// bundlePosters:true or points assetsBase at a host that serves posters/. Both the export and the
// print-preview paths degrade honestly when it does (export reports an error; the preview window
// shows "Poster not available yet" via the img onerror).
const posterUrl = (id) => `${assetsBase.value}/posters/${id}.webp`
// ─── REGIONAL SECTIONS ───────────────────────────────────────────────────────
// clusters.json carries no region field, so the mapping lives here. It is keyed by
@ -244,7 +265,7 @@ async function exportPoster(list) {
exportState.value = { label: list.label, kind: 'Poster', phase: 'fetch',
message: 'fetching poster', pct: 20 }
try {
const url = `${assetsBase.value}/posters/${list.id}.webp`
const url = posterUrl(list.id)
const res = await fetch(url)
if (!res.ok) throw new Error(`poster not found (${res.status})`)
exportState.value = { ...exportState.value, phase: 'save', message: 'saving', pct: 80 }
@ -285,7 +306,7 @@ async function printPoster(list) {
exportState.value = { label: list.label, kind: 'Poster', phase: 'fetch',
message: 'preparing print preview', pct: 30 }
try {
const url = `${assetsBase.value}/posters/${list.id}.webp`
const url = posterUrl(list.id)
// Preview + print in a dedicated window: a single centered, page-fit image and an
// onload -> print() so the dialog opens on the poster the user is looking at. The
// poster is a 3ft square print (see the template) → @page portrait, image scaled to

View file

@ -1 +1 @@
pid=2071820 started=2026-09-22T07:24:51Z by=lk10x
pid=2170487 started=2026-09-22T07:42:05Z by=lk10x

File diff suppressed because one or more lines are too long

View file

@ -607,7 +607,7 @@
"bundle": "my-upg-100-list",
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"output": "doxa-maps/my-upg-100-list/my-upg-100-list.js",
"integrity": "sha384-kp9nHCASuuYGJTAlEJ4gHkCUr9YrbLOHweqkWiyngdBAaDmVsUtOjafvDSBmUSZI",
"integrity": "sha384-Juq7s0kvFMgANiysoEh2N3MFkIZU16TZCmRdTKJ6nI8MWOWn4BfpaT8Syy9NJlJk",
"elements": [
"my-upg-100-list-map"
],
@ -623,7 +623,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-kp9nHCASuuYGJTAlEJ4gHkCUr9YrbLOHweqkWiyngdBAaDmVsUtOjafvDSBmUSZI\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-Juq7s0kvFMgANiysoEh2N3MFkIZU16TZCmRdTKJ6nI8MWOWn4BfpaT8Syy9NJlJk\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -637,7 +637,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/upg-100-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-kp9nHCASuuYGJTAlEJ4gHkCUr9YrbLOHweqkWiyngdBAaDmVsUtOjafvDSBmUSZI\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-Juq7s0kvFMgANiysoEh2N3MFkIZU16TZCmRdTKJ6nI8MWOWn4BfpaT8Syy9NJlJk\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -651,7 +651,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/upg-100-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-kp9nHCASuuYGJTAlEJ4gHkCUr9YrbLOHweqkWiyngdBAaDmVsUtOjafvDSBmUSZI\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-Juq7s0kvFMgANiysoEh2N3MFkIZU16TZCmRdTKJ6nI8MWOWn4BfpaT8Syy9NJlJk\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
}
]

View file

@ -130,7 +130,7 @@ header.top .sub { margin-top: 3px; font: 12px/1.4 var(--sans); color: var(--mut)
<script>window.FORGE = {"mode":"built","scope":"bundle","manifestUrl":"../manifest.json","bundle":"my-upg-100-list","hrefBase":"../"};
/* file:// contract: manifest inlined at build — no fetch needed to render. */
window.FORGE.manifest = {"schema":"doxa-maps-manifest@1","generatedFrom":"plugin-designs/*/*.vue","embedBase":".","bundleCount":19,"profileCount":28,"bundles":[{"bundle":"my-upg-100-list","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","output":"doxa-maps/my-upg-100-list/my-upg-100-list.js","integrity":"sha384-kp9nHCASuuYGJTAlEJ4gHkCUr9YrbLOHweqkWiyngdBAaDmVsUtOjafvDSBmUSZI","elements":["my-upg-100-list-map"],"profiles":[{"profile":"poster-wall","file":"poster-wall.vue","description":"A wall of printable poster cards, one per 100-list entry, each with a \"Show on map\" action that","element":"my-upg-100-list-map","type":"single","isMap":true,"iframeUrl":"./my-upg-100-list/poster-wall/index.html","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","embed":{"iframe":"\u003ciframe src=\"./my-upg-100-list/poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-kp9nHCASuuYGJTAlEJ4gHkCUr9YrbLOHweqkWiyngdBAaDmVsUtOjafvDSBmUSZI\" crossorigin=\"anonymous\">\u003c/script>\n\u003cmy-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/my-upg-100-list-map>"}},{"profile":"upg-100-list","file":"upg-100-list.vue","description":"A personal unreached-people-groups list painted as true boundary polygons —","element":"my-upg-100-list-map","type":"single","isMap":true,"iframeUrl":"./my-upg-100-list/upg-100-list/index.html","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","embed":{"iframe":"\u003ciframe src=\"./my-upg-100-list/upg-100-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-kp9nHCASuuYGJTAlEJ4gHkCUr9YrbLOHweqkWiyngdBAaDmVsUtOjafvDSBmUSZI\" crossorigin=\"anonymous\">\u003c/script>\n\u003cmy-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/my-upg-100-list-map>"}},{"profile":"upg-100-mfe","file":"upg-100-mfe.vue","description":"The standalone, shareable and embeddable composite of the my-upg-100-list family — it nests the map","element":"my-upg-100-list-map","type":"nested-elements-mfe","isMap":true,"iframeUrl":"./my-upg-100-list/upg-100-mfe/index.html","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","embed":{"iframe":"\u003ciframe src=\"./my-upg-100-list/upg-100-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-kp9nHCASuuYGJTAlEJ4gHkCUr9YrbLOHweqkWiyngdBAaDmVsUtOjafvDSBmUSZI\" crossorigin=\"anonymous\">\u003c/script>\n\u003cmy-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/my-upg-100-list-map>"}}]}]};</script>
window.FORGE.manifest = {"schema":"doxa-maps-manifest@1","generatedFrom":"plugin-designs/*/*.vue","embedBase":".","bundleCount":19,"profileCount":28,"bundles":[{"bundle":"my-upg-100-list","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","output":"doxa-maps/my-upg-100-list/my-upg-100-list.js","integrity":"sha384-Juq7s0kvFMgANiysoEh2N3MFkIZU16TZCmRdTKJ6nI8MWOWn4BfpaT8Syy9NJlJk","elements":["my-upg-100-list-map"],"profiles":[{"profile":"poster-wall","file":"poster-wall.vue","description":"A wall of printable poster cards, one per 100-list entry, each with a \"Show on map\" action that","element":"my-upg-100-list-map","type":"single","isMap":true,"iframeUrl":"./my-upg-100-list/poster-wall/index.html","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","embed":{"iframe":"\u003ciframe src=\"./my-upg-100-list/poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-Juq7s0kvFMgANiysoEh2N3MFkIZU16TZCmRdTKJ6nI8MWOWn4BfpaT8Syy9NJlJk\" crossorigin=\"anonymous\">\u003c/script>\n\u003cmy-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/my-upg-100-list-map>"}},{"profile":"upg-100-list","file":"upg-100-list.vue","description":"A personal unreached-people-groups list painted as true boundary polygons —","element":"my-upg-100-list-map","type":"single","isMap":true,"iframeUrl":"./my-upg-100-list/upg-100-list/index.html","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","embed":{"iframe":"\u003ciframe src=\"./my-upg-100-list/upg-100-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-Juq7s0kvFMgANiysoEh2N3MFkIZU16TZCmRdTKJ6nI8MWOWn4BfpaT8Syy9NJlJk\" crossorigin=\"anonymous\">\u003c/script>\n\u003cmy-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/my-upg-100-list-map>"}},{"profile":"upg-100-mfe","file":"upg-100-mfe.vue","description":"The standalone, shareable and embeddable composite of the my-upg-100-list family — it nests the map","element":"my-upg-100-list-map","type":"nested-elements-mfe","isMap":true,"iframeUrl":"./my-upg-100-list/upg-100-mfe/index.html","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","embed":{"iframe":"\u003ciframe src=\"./my-upg-100-list/upg-100-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-Juq7s0kvFMgANiysoEh2N3MFkIZU16TZCmRdTKJ6nI8MWOWn4BfpaT8Syy9NJlJk\" crossorigin=\"anonymous\">\u003c/script>\n\u003cmy-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/my-upg-100-list-map>"}}]}]};</script>
<script>/**
* staging-forge.js — the ONE-PAGE semantic staging environment (root + bundle pages).
*

File diff suppressed because one or more lines are too long

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
<script src="../my-upg-100-list.js" integrity="sha384-kp9nHCASuuYGJTAlEJ4gHkCUr9YrbLOHweqkWiyngdBAaDmVsUtOjafvDSBmUSZI" crossorigin="anonymous"></script>
<script src="../my-upg-100-list.js" integrity="sha384-Juq7s0kvFMgANiysoEh2N3MFkIZU16TZCmRdTKJ6nI8MWOWn4BfpaT8Syy9NJlJk" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
<script src="../my-upg-100-list.js" integrity="sha384-kp9nHCASuuYGJTAlEJ4gHkCUr9YrbLOHweqkWiyngdBAaDmVsUtOjafvDSBmUSZI" crossorigin="anonymous"></script>
<script src="../my-upg-100-list.js" integrity="sha384-Juq7s0kvFMgANiysoEh2N3MFkIZU16TZCmRdTKJ6nI8MWOWn4BfpaT8Syy9NJlJk" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -40,7 +40,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
<script src="../my-upg-100-list.js" integrity="sha384-kp9nHCASuuYGJTAlEJ4gHkCUr9YrbLOHweqkWiyngdBAaDmVsUtOjafvDSBmUSZI" crossorigin="anonymous"></script>
<script src="../my-upg-100-list.js" integrity="sha384-Juq7s0kvFMgANiysoEh2N3MFkIZU16TZCmRdTKJ6nI8MWOWn4BfpaT8Syy9NJlJk" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long