Poster Sections: generate the presets from each poster type's own regions

gen:poster-sections-presets writes poster-sections.instances.json from each
type's scopes() (all regions, then one preset per region titled by the type's
own section title in the site's English, then configure), the same list
check:poster-sections holds the file to. Today it reproduces the 20 presets
exactly, in the data's region order; when the data's regions change, running
it is the whole fix.
This commit is contained in:
Doxa Maps 2026-10-02 09:50:33 +00:00
parent 859cad37af
commit 446ed37d1c
5 changed files with 146 additions and 102 deletions

View file

@ -425,6 +425,7 @@
"check:poster-section:self-test": "node plugin-designs/country-posters/scripts/check-poster-section.mjs --self-test",
"check:poster-sections": "node plugin-designs/poster-sections/scripts/check-poster-sections.mjs",
"check:poster-sections:self-test": "node plugin-designs/poster-sections/scripts/check-poster-sections.mjs --self-test",
"gen:poster-sections-presets": "node plugin-designs/poster-sections/scripts/gen-presets.mjs",
"check:side-lane-photo-pixels": "node plugin-designs/country-posters/scripts/check-side-lane-photo-pixels.mjs",
"check:side-lane-photo-pixels:self-test": "node plugin-designs/country-posters/scripts/check-side-lane-photo-pixels.mjs --self-test",
"check:poster-type-registry": "node internal/check-poster-type-registry.mjs",
@ -702,6 +703,7 @@
"check:poster-section:self-test": "a registry without 'country', a region key without \"&\" → \"and\", and a section that uses a name it does not inject must each make check:poster-section fail.",
"check:poster-sections": "the Poster Sections page (plugin-designs/poster-sections): every panel choice (each region or All regions, each language, open or collapsed, 1-5 per row) builds <dxm-poster-section> tags that the element's own attribute reader turns back into exactly those choices; All regions is one section per region; Copy embed is the bundle script plus those same tags. The presets file holds, per poster type, exactly an all-regions preset plus one per region its adapter's scopes() returns, so a region the data drops (or gains) cannot drift from the presets.",
"check:poster-sections:self-test": "a tag builder that drops columns, one that drops collapsed, one that repeats a region under All regions, and a preset for a region the type does not have must each make check:poster-sections fail.",
"gen:poster-sections-presets": "writes plugin-designs/poster-sections/poster-sections.instances.json from each poster type's own scopes() (all regions + one preset per region, titled by the type's own section title, then configure); the list check:poster-sections holds the file to.",
"check:side-lane-photo-pixels": "BROWSER gate (browser seat; elsewhere 75 NOT MEASURED): the 60x96 side-lane sheet rasterised by poster-raster.js, measured in pixels at every photo slot. A data: photo draws; every photo on its own host stays flat, never the broken-image glyph an external <image> rasterises as.",
"check:side-lane-photo-pixels:self-test": "the same raster WITHOUT stripExternalImages must leave the external photo slots NOT flat (the glyph), else the gate proves nothing.",
"check:poster-type-registry": "the poster type registry is ONE per page: every bundle inlines its own copy of posterTypes.js and <dxm-poster-section> is defined by whichever bundle loads first, so with two independent copies loaded side by side a type registered through one is found through the other; the built-in country is listed once; a name registered twice keeps the first; every registration is announced on window (dxm-poster-type-registered) and PosterSectionView re-resolves on it. Run the `check:poster-type-registry:self-test` script for the NEGATIVE test (a per-bundle registry fails)."

View file

@ -10,14 +10,6 @@
"scope": "all"
}
},
{
"id": "countries-africa",
"title": "Country posters — Africa",
"props": {
"type": "country",
"scope": "africa"
}
},
{
"id": "countries-asia",
"title": "Country posters — Asia",
@ -27,11 +19,11 @@
}
},
{
"id": "countries-europe",
"title": "Country posters — Europe",
"id": "countries-middle-east",
"title": "Country posters — Middle East",
"props": {
"type": "country",
"scope": "europe"
"scope": "middle-east"
}
},
{
@ -43,11 +35,27 @@
}
},
{
"id": "countries-middle-east",
"title": "Country posters — Middle East",
"id": "countries-africa",
"title": "Country posters — Africa",
"props": {
"type": "country",
"scope": "middle-east"
"scope": "africa"
}
},
{
"id": "countries-europe",
"title": "Country posters — Europe",
"props": {
"type": "country",
"scope": "europe"
}
},
{
"id": "countries-other",
"title": "Country posters — Other",
"props": {
"type": "country",
"scope": "other"
}
},
{
@ -66,14 +74,6 @@
"scope": "oceania"
}
},
{
"id": "countries-other",
"title": "Country posters — Other",
"props": {
"type": "country",
"scope": "other"
}
},
{
"id": "upg100-all",
"title": "UPG 100 posters — all regions",

View file

@ -0,0 +1,42 @@
#!/usr/bin/env node
// gen-presets.mjs (bun run gen:poster-sections-presets) — writes poster-sections.instances.json from each poster type's
// OWN regions: "<prefix>-all" plus one preset per scope its adapter's scopes() returns, titled by the type's own
// (English) section title, then "configure". The same source check:poster-sections holds the file to, so when the
// data's regions change, running this is the whole fix. A type whose file is not on the tree yet keeps the presets it
// already has.
import { readFileSync, writeFileSync, existsSync } from 'node:fs'
import { join, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '../../..')
const FILE = join(ROOT, 'plugin-designs/poster-sections/poster-sections.instances.json')
const TYPES = [
{ type: 'country', prefix: 'countries', noun: 'Country posters', file: 'library/components/poster/types/countryPosterType.js' },
{ type: 'upg100-list', prefix: 'upg100', noun: 'UPG 100 posters', file: 'plugin-designs/my-upg-100-list/data/upg100-poster-type.js' },
]
const old = JSON.parse(readFileSync(FILE, 'utf8'))
const { createServer } = await import('vite')
const server = await createServer({ root: ROOT, configFile: false, logLevel: 'error', appType: 'custom', server: { middlewareMode: true, hmr: false, ws: false }, resolve: { alias: { '@map': join(ROOT, 'library') } } })
// English from the real catalogue (library/i18n/locales/en/<area>.json), so a title the type translates reads as the
// site's English; a key the catalogue lacks comes back as itself, which every adapter treats as "use the region name".
const english = (key) => {
const [area, ...parts] = String(key).split('.')
const f = join(ROOT, `library/i18n/locales/en/${area}.json`)
if (!parts.length || !existsSync(f)) return key
let o = JSON.parse(readFileSync(f, 'utf8'))
for (const p of parts) { if (!o || typeof o !== 'object' || !(p in o)) return key; o = o[p] }
return typeof o === 'string' ? o : key
}
const instances = []
try {
for (const { type, prefix, noun, file } of TYPES) {
if (!existsSync(join(ROOT, file))) { instances.push(...old.instances.filter((i) => i.props && i.props.type === type)); continue }
const a = (await server.ssrLoadModule(join(ROOT, file))).default
instances.push({ id: `${prefix}-all`, title: `${noun} — all regions`, props: { type, scope: 'all' } })
for (const scope of a.scopes()) instances.push({ id: `${prefix}-${scope}`, title: `${noun} — ${a.title(scope, english)}`, props: { type, scope } })
}
} finally { await server.close() }
instances.push({ id: 'configure', title: 'Configure — make a new preset', props: { configure: true } })
writeFileSync(FILE, JSON.stringify({ ...old, instances }, null, 2) + '\n')
const before = new Set(old.instances.map((i) => i.id)), after = new Set(instances.map((i) => i.id))
console.log(`poster-sections presets: ${instances.length} (removed: ${[...before].filter((x) => !after.has(x)).join(', ') || 'none'}; added: ${[...after].filter((x) => !before.has(x)).join(', ') || 'none'})`)

View file

@ -1218,21 +1218,6 @@
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-all/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "countries-africa",
"title": "Country posters — Africa",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "africa"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-africa/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-africa/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "countries-asia",
"title": "Country posters — Asia",
@ -1249,18 +1234,18 @@
}
},
{
"id": "countries-europe",
"title": "Country posters — Europe",
"id": "countries-middle-east",
"title": "Country posters — Middle East",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "europe"
"scope": "middle-east"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-europe/index.html",
"iframeUrl": "./poster-sections/poster-sections/countries-middle-east/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-europe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-middle-east/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
@ -1279,18 +1264,48 @@
}
},
{
"id": "countries-middle-east",
"title": "Country posters — Middle East",
"id": "countries-africa",
"title": "Country posters — Africa",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "middle-east"
"scope": "africa"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-middle-east/index.html",
"iframeUrl": "./poster-sections/poster-sections/countries-africa/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-middle-east/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-africa/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "countries-europe",
"title": "Country posters — Europe",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "europe"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-europe/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-europe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "countries-other",
"title": "Country posters — Other",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "other"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-other/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-other/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
@ -1323,21 +1338,6 @@
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-oceania/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "countries-other",
"title": "Country posters — Other",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "other"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-other/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-other/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "upg100-all",
"title": "UPG 100 posters — all regions",

View file

@ -1218,21 +1218,6 @@
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-all/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "countries-africa",
"title": "Country posters — Africa",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "africa"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-africa/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-africa/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "countries-asia",
"title": "Country posters — Asia",
@ -1249,18 +1234,18 @@
}
},
{
"id": "countries-europe",
"title": "Country posters — Europe",
"id": "countries-middle-east",
"title": "Country posters — Middle East",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "europe"
"scope": "middle-east"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-europe/index.html",
"iframeUrl": "./poster-sections/poster-sections/countries-middle-east/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-europe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-middle-east/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
@ -1279,18 +1264,48 @@
}
},
{
"id": "countries-middle-east",
"title": "Country posters — Middle East",
"id": "countries-africa",
"title": "Country posters — Africa",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "middle-east"
"scope": "africa"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-middle-east/index.html",
"iframeUrl": "./poster-sections/poster-sections/countries-africa/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-middle-east/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-africa/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "countries-europe",
"title": "Country posters — Europe",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "europe"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-europe/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-europe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "countries-other",
"title": "Country posters — Other",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "other"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-other/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-other/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
@ -1323,21 +1338,6 @@
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-oceania/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "countries-other",
"title": "Country posters — Other",
"apiBaseUrl": "",
"props": {
"profile": "poster-sections",
"type": "country",
"scope": "other"
},
"element": "poster-sections",
"iframeUrl": "./poster-sections/poster-sections/countries-other/index.html",
"embed": {
"iframe": "<iframe src=\"./poster-sections/poster-sections/countries-other/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>"
}
},
{
"id": "upg100-all",
"title": "UPG 100 posters — all regions",