Compare commits

...

4 commits

Author SHA1 Message Date
Doxa Maps
48d623330e Rename the UPG-100 tab: "UPG-100 List Posters" in all 11 locales (values only)
The house style is "UPG-100". Each existing translation changes "UPG 100" to
"UPG-100" and keeps its own wording; German becomes the compound "Poster der
UPG-100-Liste". Values only: no key is renamed.
- upgMap.displayName + upgMap.wallHeading ×11 (the in-app name and the wall
  heading).
- The three meta labels ("UPG-100 List Posters", "— Zoned Map", "— Poster Wall").
- 'tab.upg-100' ×11 in doxa-maps-spa/src/strings.js and in
  posterverse/src/strings.js, with the same words in both, so both shells name
  the plugin identically. Both owners confirmed they had no pending edit.
The unused legend.title.upg100List and messages.upg100WallHeading are left for
their own cleanup.
2026-10-02 08:42:13 +00:00
Doxa Maps
32d669deea check:label-key-coverage follows the region table to data/upg100-regions.js, and reads the labels regionOf returns as literals (a removed 'China + Mongolia' key FAILS it) 2026-10-02 08:05:44 +00:00
Doxa Maps
1faf1c9d49 Rebuild my-upg-100-list for the collapsible region sections and the upg100-list poster type, and regenerate the tree and SRI 2026-10-02 08:03:29 +00:00
Doxa Maps
07b28e405e UPG-100: region sections are the shared poster section, collapsible, and an 'upg100-list' poster type
UPG-100's poster wall groups its zones into regions (India, China + Mongolia,
Africa, Middle East, Central Asia, Southeast Asia + Oceania, Americas, Europe).
Those sections are now collapsible like Country Posters' and start open. They
are also available on their own as <dxm-poster-section type="upg100-list"
scope="africa">.

- data/upg100-regions.js (pure): the region table (REGION_OF, moved verbatim
  from poster-wall.vue), regionOf(id) and each region's scope slug.
- data/upg100-poster-type.js: the poster-type adapter (scopes, items, title,
  actions), built on the wall's own zones (upg100Zones), headings (regionTitle)
  and print path (the records provider with this plugin's evaluator, and
  zone-sheet-print.js).
- index.js registers the type ('upg100-list') and the element. The element
  registration is a no-op if another bundle on the page registered it first.
- poster-wall.vue groups through the same regionOf, draws the same zones, and
  passes collapsible + collapsedBy (all open). Its other props are unchanged.

check:upg100-poster-type (gates:pre) checks:
- every zone sits in a named region, with a negative control;
- the 8 sections exist, and the scopes are unique and round-trip;
- the headings exist ×11;
- the wiring holds.
Three mutants each fail it.
No library code changed.
2026-10-02 07:58:49 +00:00
29 changed files with 474 additions and 293 deletions

View file

@ -50,11 +50,14 @@ const ok = (cond, msg) => { if (!cond) fails.push(msg) }
// directly (legend-tree's regionFor returns 'India' / 'China + Mongolia' / 'Other' without a helper call).
const TABLES = [
{
file: 'plugin-designs/my-upg-100-list/poster-wall.vue',
// the poster wall's region sections (and <dxm-poster-section type="upg100-list">): the table moved out of
// poster-wall.vue into data/upg100-regions.js; regionOf RETURNS 'India' / 'China + Mongolia' / 'Other' directly
file: 'plugin-designs/my-upg-100-list/data/upg100-regions.js',
produces: 'REGION_OF',
mapsFile: 'plugin-designs/my-upg-100-list/data/legend-tree.js',
maps: 'REGION_KEY',
via: 'regionLabel',
via: 'regionTitle',
producerReturns: 'regionOf',
area: 'poster',
},
{
@ -87,6 +90,13 @@ function producerLabels(src, fn) {
const m = new RegExp(`const ${fn}\\s*=\\s*\\([^)]*\\)\\s*=>([\\s\\S]*?);\\n`).exec(src)
return m ? [...m[1].matchAll(/[?:]\s*'([^']+)'/g)].map((x) => x[1]) : null
}
/** The labels a function declaration RETURNS as literals: `return 'India'`. */
function returnedLabels(src, fn) {
const at = src.search(new RegExp(`function ${fn}\\s*\\(`))
if (at < 0) return null
const body = src.slice(at, src.indexOf('\n}\n', at))
return [...body.matchAll(/return\s+'([^']+)'/g)].map((x) => x[1])
}
/** Quoted values on the right of a colon — the English labels a table produces. */
const valuesOf = (body) => new Set([...body.matchAll(/:\s*'([^']+)'/g)].map((m) => m[1]))
/** Quoted keys on the left of a colon — the English labels a table covers. */
@ -119,6 +129,11 @@ for (const t of TABLES) {
if (!got || !got.length) { ok(false, `${t.file}: no \`const ${t.producerFn} = (…) =>\` returning labels — this gate has gone blind`); continue }
fromFn = got
}
if (t.producerReturns) {
const got = returnedLabels(src, t.producerReturns)
if (!got || !got.length) { ok(false, `${t.file}: no \`function ${t.producerReturns}(…)\` returning labels — this gate has gone blind`); continue }
fromFn = [...fromFn, ...got]
}
const produced = new Set([...fromTable, ...fromCalls, ...fromFn])
const covered = keysOf(maps)

View file

@ -0,0 +1,84 @@
#!/usr/bin/env node
// check-upg100-poster-type — UPG-100's region sections are ONE section, whether the poster wall draws them or
// <dxm-poster-section type="upg100-list" scope="…"> does. Headless. Asserts:
// A. every zone the wall shows (clusters.json: lists + asia_lists + uncovered_lists) belongs to a NAMED region,
// never 'Other', and the sections the wall promises exist (India, China + Mongolia, Africa, Middle East,
// Central Asia, Southeast Asia + Oceania, Americas, Europe). NEGATIVE CONTROL: a planted unknown zone falls to
// 'Other', so this check can fail;
// B. each region's scope (its slug) is unique and round-trips from the English name, so a scope can't name two
// sections;
// C. each region's heading has its poster.region_* key in all 11 locales;
// D. the wiring: the bundle registers the 'upg100-list' type and the element; the type's adapter has the four
// parts a section reads; the wall groups through the SAME regionOf and draws the SAME zones (upg100Zones), and
// its sections are collapsible.
import { readFileSync } from 'node:fs'
import { resolve, dirname, join } from 'node:path'
import { fileURLToPath, pathToFileURL } from 'node:url'
const REPO = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const P = (...a) => join(REPO, ...a)
const PLUGIN = 'plugin-designs/my-upg-100-list'
const fails = [], notes = []
const ok = (cond, msg, note) => { if (!cond) fails.push(msg); else if (note) notes.push(` ok ${note}`) }
const LANGS = ['en', 'es', 'fr', 'pt', 'de', 'it', 'ro', 'ru', 'ar', 'hi', 'zh']
let R, clusters, REGION_KEY
try {
R = await import(pathToFileURL(P(PLUGIN, 'data/upg100-regions.js')).href)
clusters = JSON.parse(readFileSync(P(PLUGIN, 'data/clusters.json'), 'utf8'))
// REGION_KEY is a plain table in legend-tree.js; read it from the source rather than importing the module (it
// pulls JSON the node loader cannot take without import attributes).
const src = readFileSync(P(PLUGIN, 'data/legend-tree.js'), 'utf8')
REGION_KEY = Object.fromEntries([...src.slice(src.indexOf('export const REGION_KEY'), src.indexOf('};', src.indexOf('export const REGION_KEY'))).matchAll(/'([^']+)': '([^']+)'/g)].map((m) => [m[1], m[2]]))
} catch (e) {
console.error(`UPG100-POSTER-TYPE: NOT MEASURED (exit 75) — an input did not load: ${e.message}`)
process.exit(75)
}
// ── A ──
const ids = [...(clusters.lists || []), ...(clusters.asia_lists || []), ...(clusters.uncovered_lists || [])].map((l) => l.id).filter(Boolean)
const others = ids.filter((id) => R.regionOf(id) === 'Other')
const used = new Set(ids.map((id) => R.regionOf(id)))
const PROMISED = ['India', 'China + Mongolia', 'Africa', 'Middle East', 'Central Asia', 'Southeast Asia + Oceania', 'Americas', 'Europe']
ok(R.regionOf('a-zone-nobody-placed') === 'Other', 'NEGATIVE CONTROL: an unknown zone did not fall to Other, so this check cannot see a missing region',
'negative control: an unplaced zone falls to Other')
ok(ids.length > 20 && !others.length && PROMISED.every((r) => used.has(r)),
`zones without a region: ${others.join(', ') || '(none)'}; sections missing: ${PROMISED.filter((r) => !used.has(r)).join(', ') || '(none)'}`,
`${ids.length} zones, every one in a named region; all ${PROMISED.length} sections present`)
// ── B ──
const scopes = R.REGIONS.map(R.regionScope)
ok(new Set(scopes).size === scopes.length && R.REGIONS.every((r) => R.regionScope(R.regionScope(r)) === R.regionScope(r)) && R.regionScope('Southeast Asia + Oceania') === 'southeast-asia-oceania',
`scopes are not unique or do not round-trip: ${scopes.join(', ')}`, `scopes unique and stable: ${scopes.join(', ')}`)
// ── C ──
const missingKeys = []
for (const r of R.REGIONS) {
const key = REGION_KEY[r]
if (!key) { missingKeys.push(`${r}: no REGION_KEY`); continue }
for (const l of LANGS) { const cat = JSON.parse(readFileSync(P('library/i18n/locales', l, 'poster.json'), 'utf8')); if (typeof cat[key] !== 'string' || !cat[key].trim()) missingKeys.push(`${l} poster.${key}`) }
}
ok(!missingKeys.length, `region headings missing: ${missingKeys.slice(0, 6).join(', ')}`, `every region heading exists in all ${LANGS.length} locales`)
// ── D ──
const index = readFileSync(P(PLUGIN, 'index.js'), 'utf8')
const type = readFileSync(P(PLUGIN, 'data/upg100-poster-type.js'), 'utf8')
const wall = readFileSync(P(PLUGIN, 'poster-wall.vue'), 'utf8')
const wired = {
'the bundle registers the upg100-list type': /registerPosterType\('upg100-list', \(\) => import\('\.\/data\/upg100-poster-type\.js'\)\)/.test(index),
'the bundle registers the element': /\nregisterPosterSectionElement\(\)/.test(index),
'the adapter has scopes, items, title and actions': ['scopes:', 'items(scope, locale)', 'title(scope, t)', 'actions({'].every((s) => type.includes(s)),
'the wall groups through the same regionOf': /const regionFor = \(id\) => regionTitle\(regionOf\(id\), t\)/.test(wall) && !/const REGION_OF = /.test(wall),
'the wall draws the same zones': /return upg100Zones\(profileConfig, locale\)/.test(wall),
'the wall sections are collapsible': /:collapsible="true"/.test(wall) && /:collapsed-by="allOpen"/.test(wall),
}
const missingWires = Object.entries(wired).filter(([, v]) => !v).map(([k]) => k)
ok(!missingWires.length, `missing: ${missingWires.join('; ')}`, 'the wall and <dxm-poster-section type="upg100-list"> share one region table, one zone list and the collapsible section')
for (const n of notes) console.log(n)
if (fails.length) {
console.error('UPG100-POSTER-TYPE: FAIL')
for (const f of fails) console.error(` ✗ ${f}`)
process.exit(1)
}
console.log('UPG100-POSTER-TYPE: PASS — UPG-100\'s region sections are one section, on the wall and as <dxm-poster-section type="upg100-list">.')

View file

@ -16,8 +16,8 @@
"copySelection": "نسخ",
"exportCsv": "تصدير CSV",
"copyNotRegroupable": "لا يمكن إعادة تجميعها معًا: انسخ ولايات أو مقاطعات بلد واحد، أو البلدان، كلًّا على حدة",
"displayName": "ملصقات قائمة UPG 100",
"wallHeading": "ملصقات قائمة UPG 100",
"displayName": "ملصقات قائمة UPG-100",
"wallHeading": "ملصقات قائمة UPG-100",
"wallIntroA": "كيف تُطعم جمعًا من خمسة آلاف؟ أجلسهم يسوع جماعاتٍ من خمسين ومن مئة، فصار المستحيل قابلًا للمشاركة (لوقا ٩:١٤). فعلنا المثل مع {n} شعوب غير مبلَّغة: ٢٧ قائمة من نحو خمسين إلى مئة. تُطبع كل قائمة حزمةَ صلاة وملصقًا، ليحمل ٢٧ تلميذًا أو كنيسة أو قائدًا محليًا كلٌّ واحدة — مصلّين لأجلهم ",
"peopleStillLoading": "لا تزال الشعوب قيد التحميل، حاول مرة أخرى بعد لحظة"
}

View file

@ -16,8 +16,8 @@
"copySelection": "Kopieren",
"exportCsv": "CSV exportieren",
"copyNotRegroupable": "Nicht gemeinsam umgruppierbar: Bundesstaaten oder Provinzen eines Landes oder die Länder getrennt kopieren",
"displayName": "Poster der UPG 100 Liste",
"wallHeading": "Poster der UPG 100 Liste",
"displayName": "Poster der UPG-100-Liste",
"wallHeading": "Poster der UPG-100-Liste",
"wallIntroA": "Wie würden Sie eine Menge von fünftausend speisen? Jesus ließ sie in Gruppen zu fünfzig und hundert lagern, und das Unmögliche wurde teilbar (Lukas 9,14). Dasselbe haben wir mit den {n} unerreichten Volksgruppen getan: 27 Listen von etwa fünfzig bis hundert. Jede Liste druckt als Gebetspaket und als Poster, damit 27 Jünger, Gemeinden oder einheimische Leiter je eine tragen können — und für sie beten ",
"peopleStillLoading": "die Volksgruppen werden noch geladen; versuchen Sie es gleich noch einmal"
}

View file

@ -16,8 +16,8 @@
"copySelection": "Copy",
"exportCsv": "Export CSV",
"copyNotRegroupable": "Can't be regrouped together: copy one country's states or provinces, or the countries, separately",
"displayName": "UPG 100 List Posters",
"wallHeading": "UPG 100 List Posters",
"displayName": "UPG-100 List Posters",
"wallHeading": "UPG-100 List Posters",
"wallIntroA": "How would you feed a crowd of five thousand? Jesus sat them down in groups of fifty and a hundred, and the impossible became shareable (Luke 9:14). We did the same with the {n} unreached people groups: 27 lists of about fifty to a hundred. Each list prints as a prayer packet and a poster, so 27 disciples, churches or local leaders can each carry one — praying for them ",
"peopleStillLoading": "the people groups are still loading, try again in a moment"
}

View file

@ -16,8 +16,8 @@
"copySelection": "Copiar",
"exportCsv": "Exportar CSV",
"copyNotRegroupable": "No se pueden reagrupar juntos: copia por separado los estados o provincias de un solo país, o los países",
"displayName": "Carteles de la lista UPG 100",
"wallHeading": "Carteles de la lista UPG 100",
"displayName": "Carteles de la lista UPG-100",
"wallHeading": "Carteles de la lista UPG-100",
"wallIntroA": "¿Cómo alimentarías a una multitud de cinco mil? Jesús los sentó en grupos de cincuenta y de cien, y lo imposible se volvió compartible (Lucas 9:14). Hicimos lo mismo con los {n} pueblos no alcanzados: 27 listas de unos cincuenta a cien. Cada lista se imprime como paquete de oración y cartel, para que 27 discípulos, iglesias o líderes locales lleven una cada uno — orando por ellos ",
"peopleStillLoading": "los pueblos aún se están cargando; inténtalo de nuevo en un momento"
}

View file

@ -16,8 +16,8 @@
"copySelection": "Copier",
"exportCsv": "Exporter en CSV",
"copyNotRegroupable": "Impossible de les regrouper ensemble : copiez séparément les États ou provinces d’un seul pays, ou les pays",
"displayName": "Affiches de la liste UPG 100",
"wallHeading": "Affiches de la liste UPG 100",
"displayName": "Affiches de la liste UPG-100",
"wallHeading": "Affiches de la liste UPG-100",
"wallIntroA": "Comment nourririez-vous une foule de cinq mille personnes ? Jésus les a fait asseoir par groupes de cinquante et de cent, et l’impossible est devenu partageable (Luc 9.14). Nous avons fait de même avec les {n} peuples non atteints : 27 listes d’environ cinquante à cent. Chaque liste s’imprime en dossier de prière et en affiche, pour que 27 disciples, Églises ou responsables locaux en portent chacun une — en priant pour eux ",
"peopleStillLoading": "les peuples sont encore en cours de chargement ; réessayez dans un instant"
}

View file

@ -16,8 +16,8 @@
"copySelection": "कॉपी करें",
"exportCsv": "CSV निर्यात करें",
"copyNotRegroupable": "इन्हें एक साथ पुनर्समूहित नहीं किया जा सकता: एक देश के राज्य या प्रांत, या देश, अलग-अलग कॉपी करें",
"displayName": "UPG 100 सूची पोस्टर",
"wallHeading": "UPG 100 सूची पोस्टर",
"displayName": "UPG-100 सूची पोस्टर",
"wallHeading": "UPG-100 सूची पोस्टर",
"wallIntroA": "पाँच हज़ार की भीड़ को आप कैसे खिलाते? यीशु ने उन्हें पचास-पचास और सौ-सौ के समूहों में बिठाया, और असंभव बाँटने योग्य हो गया (लूका 9:14). हमने {n} अनपहुँचे जनसमूहों के साथ वही किया: लगभग पचास से सौ तक की 27 सूचियाँ. हर सूची प्रार्थना पैकेट और पोस्टर के रूप में छपती है, ताकि 27 शिष्य, कलीसियाएँ या स्थानीय अगुवे एक-एक ले सकें — उनके लिए प्रार्थना करते हुए ",
"peopleStillLoading": "जनसमूह अभी लोड हो रहे हैं, थोड़ी देर में फिर कोशिश करें"
}

View file

@ -16,8 +16,8 @@
"copySelection": "Copia",
"exportCsv": "Esporta CSV",
"copyNotRegroupable": "Non si possono raggruppare insieme: copia separatamente gli stati o le province di un solo paese, o i paesi",
"displayName": "Poster della lista UPG 100",
"wallHeading": "Poster della lista UPG 100",
"displayName": "Poster della lista UPG-100",
"wallHeading": "Poster della lista UPG-100",
"wallIntroA": "Come sfameresti una folla di cinquemila? Gesù li fece sedere a gruppi di cinquanta e di cento, e l’impossibile divenne condivisibile (Luca 9:14). Abbiamo fatto lo stesso con i {n} popoli non raggiunti: 27 liste di circa cinquanta-cento. Ogni lista si stampa come pacchetto di preghiera e manifesto, così 27 discepoli, chiese o responsabili locali ne portano una ciascuno — pregando per loro ",
"peopleStillLoading": "i popoli si stanno ancora caricando; riprova tra un momento"
}

View file

@ -16,8 +16,8 @@
"copySelection": "Copiar",
"exportCsv": "Exportar CSV",
"copyNotRegroupable": "Não podem ser reagrupados juntos: copie separadamente os estados ou províncias de um só país, ou os países",
"displayName": "Cartazes da lista UPG 100",
"wallHeading": "Cartazes da lista UPG 100",
"displayName": "Cartazes da lista UPG-100",
"wallHeading": "Cartazes da lista UPG-100",
"wallIntroA": "Como você alimentaria uma multidão de cinco mil? Jesus os sentou em grupos de cinquenta e de cem, e o impossível tornou-se compartilhável (Lucas 9.14). Fizemos o mesmo com os {n} povos não alcançados: 27 listas de cerca de cinquenta a cem. Cada lista imprime como pacote de oração e cartaz, para que 27 discípulos, igrejas ou líderes locais levem uma cada um — orando por eles ",
"peopleStillLoading": "os povos ainda estão carregando; tente de novo em um instante"
}

View file

@ -16,8 +16,8 @@
"copySelection": "Copiază",
"exportCsv": "Exportă CSV",
"copyNotRegroupable": "Nu pot fi regrupate împreună: copiază separat statele sau provinciile unei singure țări, sau țările",
"displayName": "Afișe din lista UPG 100",
"wallHeading": "Afișe din lista UPG 100",
"displayName": "Afișe din lista UPG-100",
"wallHeading": "Afișe din lista UPG-100",
"wallIntroA": "Cum ai hrăni o mulțime de cinci mii? Isus i-a așezat în grupuri de cincizeci și de o sută, iar imposibilul a devenit împărțibil (Luca 9:14). Am făcut la fel cu cele {n} popoare neatinse: 27 de liste de aproximativ cincizeci până la o sută. Fiecare listă se tipărește ca pachet de rugăciune și afiș, ca 27 de ucenici, biserici sau lideri locali să poarte fiecare câte una — rugându-se pentru ei ",
"peopleStillLoading": "popoarele încă se încarcă; încearcă din nou peste o clipă"
}

View file

@ -16,8 +16,8 @@
"copySelection": "Копировать",
"exportCsv": "Экспорт в CSV",
"copyNotRegroupable": "Нельзя перегруппировать вместе: копируйте отдельно штаты или провинции одной страны либо страны",
"displayName": "Плакаты списка UPG 100",
"wallHeading": "Плакаты списка UPG 100",
"displayName": "Плакаты списка UPG-100",
"wallHeading": "Плакаты списка UPG-100",
"wallIntroA": "Как накормить толпу в пять тысяч человек? Иисус рассадил их группами по пятьдесят и по сто, и невозможное стало посильным (Лк. 9:14). Мы поступили так же с {n} неохваченными народами: 27 списков примерно по пятьдесят-сто. Каждый список печатается как молитвенный пакет и плакат, чтобы 27 учеников, церквей или местных служителей взяли по одному — молясь о них ",
"peopleStillLoading": "народы ещё загружаются; попробуйте ещё раз через мгновение"
}

View file

@ -16,8 +16,8 @@
"copySelection": "复制",
"exportCsv": "导出 CSV",
"copyNotRegroupable": "无法一起重新分组:请分别复制同一国家的邦或省,或各个国家",
"displayName": "UPG 100 名单海报",
"wallHeading": "UPG 100 名单海报",
"displayName": "UPG-100 名单海报",
"wallHeading": "UPG-100 名单海报",
"wallIntroA": "你会怎样喂饱五千人的群众?耶稣让他们一排五十、一排一百地坐下,不可能的事就变得可以分担了(路加福音 9:14)。我们对 {n} 个未得之民做了同样的事:27 份名单,每份约五十到一百。每份名单都能印成祷告手册和海报,让 27 位门徒、教会或当地领袖各领一份 — 为他们祷告 ",
"peopleStillLoading": "族群仍在加载中,请稍后再试"
}

View file

@ -242,6 +242,7 @@
"check:list-pattern-doc": "node internal/check-list-pattern-doc.mjs",
"check:pg-name-gate": "node internal/check-pg-name-gate.mjs",
"check:pin-selection": "node internal/check-pin-selection.mjs",
"check:upg100-poster-type": "node internal/check-upg100-poster-type.mjs",
"check:poster-action-print": "node internal/check-poster-action-print.mjs",
"check:popup-href-escaped": "node internal/check-popup-href-escaped.mjs",
"check:popup-pan-controls": "node internal/check-popup-pan-clears-controls.mjs",
@ -351,7 +352,7 @@
"fix:sri": "node internal/fix-sri.mjs",
"gallery": "node internal/generate-gallery.mjs",
"gates:post": "node internal/run-parallel.mjs --label=post -- check:capability-derived check:drop check:parse verify check:sri check:public-hygiene check:label-joins check:facet-cascade check:facet-one-field check:heartbeat check:kpi-unit check:composite-reg check:descriptions check:no-abs-paths check:no-codename check:dep-names check:composite-srcs check:embed-targets check:nested-token check:i18n-parity check:tabs-localized check:packets-all check:packet-strings-parity check:zone-census check:zoning-declared check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:script-flags check:capability-exemplars check:packet-fixture check:packet-browser check:provider-switch check:locale-reachable check:url-resolver check:manifest-covers check:one-palette check:pin-dim-slider check:legend-source check:clustering-modes check:composite-embed-knobs check:composite-locale-leaks check:linked-vocabulary check:wp-embed check:dashboard-geocoder-provider check:leaf-engine-per-provider check:auto-engine check:engine-contract check:map-props-unit check:composites-mount check:composite-interop check:no-free-identifiers check:map-fly-reduced-motion check:mst-clustering check:list-prop-unit check:profiles-mount check:cdn-pins check:no-eval check:popup-escaping check:i18n-treeshake check:pinned-umd check:one-palette:self-test check:no-cross-plugin-imports check:no-cross-plugin-imports:self-test check:map-attribution check:studio-rail check:approx-pin-note check:embedder-keys check:provider-for check:legend-logical-insets check:legend-logical-insets:self-test check:optional-t-equivalence check:text-highlight check:religion-label-not-value check:i18n-stopped-scope check:no-silent-engine check:no-silent-engine:self-test check:regions-uses-library check:shadow-css-parses check:square-map-controls check:preset-config-merge check:instance-config-keys check:frozen-labels check:plural-forms check:region-fill-repaint check:region-paint-single-source check:poster-print-fallback check:posters-exportable check:country-names check:reduced-motion check:no-dead-library check:universal-props check:readme-size check:tree-relative check:leaf-hints check:snippet-engine check:snippet-engine:self-test check:embed-base check:link-coverage check:no-public-binds check:shared-reached check:tree-weight check:no-fleet-names:self-test check:pin-hint-floor:self-test check:poster-sizes:self-test check:shell-header:self-test",
"gates:pre": "node internal/run-parallel.mjs --label=pre -- check:template-literal check:mjs-parse check:sfc-parse check:tab-radius check:synced-css check:doc-scripts check:setup-order check:package-json-unique-keys check:no-repo-pb-hooks check:no-credentials-omit check:no-credentials-omit:self-test check:shadow-reduced-motion check:poster-action-print check:targets check:targets:self-test check:browser-gates-guarded check:pin-selection check:facet-shape check:hardcoded-english:self-test check:list-selection check:selector-fields check:upg-zone-joins check:gospel-set-charts check:gospel-set-fit check:describe-group check:one-scroll-container check:packet-charts check:composite-token-url check:language-tree-layout check:i18n-keys-exist check:i18n-never-translated check:packet-variants check:profile-table check:element-bootstrap check:embed-url-absolute check:frame-target check:language-tree-model check:map-menu-anchor check:selection-kinds check:tiered-points check:whiteboard-projection check:mercator-slice check:ring-vocabulary check:map-props-unit check:mobile-gating check:provide-shadowing check:legend-top-offset check:cdn-cache check:plural-forms check:select-zone-race check:script-registry check:map-control-overlap check:poster-attribution check:board-map-options check:gospel-whiteboard check:packet-map-missing-loud check:poster-layout-optin check:ported-globals-identical check:ring-bands check:packet-a1-structure check:india-states check:batch-selection-export check:zone-title-tier-a check:evangelical-share check:map-labels check:packet-offline check:help-reachable check:gated-not-in-tree check:window-globals-released check:legend-data-contract check:no-internal-role-nouns check:poster-fetch-guard check:people-group-records check:sentence-slots check:popup-href-escaped check:popup-pan-controls check:country-map-refetch check:pane-config-reforward check:viewport-meta check:viewport-meta:self-test check:label-key-coverage check:poster-browser-equiv check:poster-render-pinned check:country-sheet-one-path check:country-sheet-one-path:self-test check:side-lanes check:side-lanes:self-test check:poster-section check:poster-section:self-test check:posterverse-shelf check:host-locale-fetch check:print-frame-reclaim check:click-sheet check:coverage-consistent:chained check:coverage-consistent:poison check:dashboard-filter-a11y check:filter-multivalue check:hover-channel check:kit-options-reachable check:layout-key-namespaced check:legend-mirrors check:map-unmount-race check:no-conflict-markers check:series-isolation check:snapshot-guard check:stale-sweep-claim check:surfaces-read-the-tier check:translator-contacts check:wall-wysiwyg check:wall-print-watch check:wall-no-bg-photos check:wall-pan check:template-i18n check:list-pattern-doc check:shadow-style-labels-unique check:grid-image-loading check:retry-fetch check:panel-sheets check:poster-wall-host-seams check:poster-design-catalogue check:wall-photo-weight check:no-fleet-names check:pin-hint-floor check:poster-sizes check:upg-count check:shell-header check:pg-name-gate",
"gates:pre": "node internal/run-parallel.mjs --label=pre -- check:template-literal check:mjs-parse check:sfc-parse check:tab-radius check:synced-css check:doc-scripts check:setup-order check:package-json-unique-keys check:no-repo-pb-hooks check:no-credentials-omit check:no-credentials-omit:self-test check:shadow-reduced-motion check:poster-action-print check:targets check:targets:self-test check:browser-gates-guarded check:pin-selection check:facet-shape check:hardcoded-english:self-test check:list-selection check:selector-fields check:upg-zone-joins check:gospel-set-charts check:gospel-set-fit check:describe-group check:one-scroll-container check:packet-charts check:composite-token-url check:language-tree-layout check:i18n-keys-exist check:i18n-never-translated check:packet-variants check:profile-table check:element-bootstrap check:embed-url-absolute check:frame-target check:language-tree-model check:map-menu-anchor check:selection-kinds check:tiered-points check:whiteboard-projection check:mercator-slice check:ring-vocabulary check:map-props-unit check:mobile-gating check:provide-shadowing check:legend-top-offset check:cdn-cache check:plural-forms check:select-zone-race check:script-registry check:map-control-overlap check:poster-attribution check:board-map-options check:gospel-whiteboard check:packet-map-missing-loud check:poster-layout-optin check:ported-globals-identical check:ring-bands check:packet-a1-structure check:india-states check:batch-selection-export check:zone-title-tier-a check:evangelical-share check:map-labels check:packet-offline check:help-reachable check:gated-not-in-tree check:window-globals-released check:legend-data-contract check:no-internal-role-nouns check:poster-fetch-guard check:people-group-records check:sentence-slots check:popup-href-escaped check:popup-pan-controls check:country-map-refetch check:pane-config-reforward check:viewport-meta check:viewport-meta:self-test check:label-key-coverage check:poster-browser-equiv check:poster-render-pinned check:country-sheet-one-path check:country-sheet-one-path:self-test check:side-lanes check:side-lanes:self-test check:poster-section check:poster-section:self-test check:posterverse-shelf check:host-locale-fetch check:print-frame-reclaim check:click-sheet check:coverage-consistent:chained check:coverage-consistent:poison check:dashboard-filter-a11y check:filter-multivalue check:hover-channel check:kit-options-reachable check:layout-key-namespaced check:legend-mirrors check:map-unmount-race check:no-conflict-markers check:series-isolation check:snapshot-guard check:stale-sweep-claim check:surfaces-read-the-tier check:translator-contacts check:wall-wysiwyg check:wall-print-watch check:wall-no-bg-photos check:wall-pan check:template-i18n check:list-pattern-doc check:shadow-style-labels-unique check:grid-image-loading check:retry-fetch check:panel-sheets check:poster-wall-host-seams check:poster-design-catalogue check:wall-photo-weight check:no-fleet-names check:pin-hint-floor check:poster-sizes check:upg-count check:shell-header check:pg-name-gate check:upg100-poster-type",
"gen:iso3-to-alpha2": "node library/scripts/generate-iso3-to-alpha2.mjs",
"internet:adm1": "node plugin-designs/cities-internet/scripts/build-adm1-internet.mjs",
"library-index": "node internal/generate-library-index.mjs",
@ -589,6 +590,7 @@
"check:popup-escaping": "the library's pin and region popups render hostile data (an <img onerror>, a <script>, a javascript: URL) as text, never markup: every field goes through escapeHtml/safeUrl (library/utils/html.js). Headless.",
"check:ported-globals-identical": "the DX Life base/_globals.scss rules that shadow-root components used to copy now come from one module (library/styles/portedGlobals.js), and the CSS each component actually INJECTS must be byte-identical to the pre-refactor baseline: it runs each component's setup with stubbed imports and hashes the real useShadowStyles argument, not the source text. Deduplication with a proof that no pixel can change. Node only, no browser.",
"check:pg-name-gate": "a people group's localized name (assets/pplr/pg-names.json) is shown only when it is a transliteration: library/utils/peopleGroupName.js falls back to English for EVERY locale of a row whose Latin-script names are far from the English one in two or more locales (bigram Dice < 0.5), because about a third were machine-translated as words (Balantak → 'Balance', Balo → 'Sac à dos'). A row with fewer than two Latin names cannot be checked and shows English too. Proved on the real table: the 4 known translated rows show English in 7 locales, Balangao Bontoc keeps its names, planted rows AT the threshold (exactly two far → English, one → kept, one Latin name → English), the whole-table fallback stays 30-45% (38.2%), and no file outside the helper reads or indexes pg-names rows (pplr-data-maps carded; the scanner is negative-controlled both ways). Headless.",
"check:upg100-poster-type": "UPG-100's region sections are ONE section on the poster wall and as <dxm-poster-section type=\"upg100-list\">: every zone in clusters.json belongs to a named region (a planted unknown zone falls to Other: the negative control), the 8 promised sections exist, each scope slug is unique and round-trips, each heading has its poster.region_* key in all 11 locales, and the wiring holds (the bundle registers the type and the element; the wall groups through the same regionOf, draws the same zones and its sections are collapsible). Headless.",
"check:pin-selection": "the shared source reader understands BOTH engines: mapbox-gl stores a GeoJSON source _data as the FeatureCollection, maplibre-gl wraps it as { geojson } (or { url } when remote). Reading only the Mapbox shape returned an EMPTY list on MapLibre — the keyless engine public builds use — which silently killed zoomToLegendRow camera fits on three maps and the research packet row selection, with no error because every caller no-ops on no features. Asserts both shapes, that a remote source returns [] AND warns, the serialize fallback, and that selectedPinIds agrees with the reader. Headless, no map. Exit 0 pass, 1 fail.",
"check:popup-href-escaped": "a URL interpolated into an HTML string is escaped before it lands in href= or src=. Written for RegionCountryMap's popup, which escaped every value except its two link URLs -- both built from joinBase(hostAttribute, apiSlug), so a quote in either escaped the attribute. Data URLs, blob URLs, encodeURIComponent and safeUrl() are recognised as safe; anything else needs an href-escaped-ok: reason. 6 self-tests. Source-only, headless.",
"check:poster-action-print": "a poster button opens the print dialog (the rule since 2026-09-28: never a direct download). Two arms: PosterWall's posterAction defaults to 'print' and any consumer opting into 'download' carries a posterAction-download: comment saying why; and no shipped file hand-rolls an <a download> for a poster IMAGE (svg/png/webp/pdf) without first attempting to print, which the prop arm cannot see. Data exports (csv/txt/json) are out of scope. 6 self-tests. Source-only, headless.",

View file

@ -25,7 +25,7 @@ export const STRINGS = {
'tab.cities-internet': 'Cities with Internet', 'sub.cities-internet': 'connectivity of key cities',
'tab.gospel-resources': 'Gospel Resources', 'sub.gospel-resources': 'resources by place',
'tab.regions-dashboard': 'Regions', 'sub.regions-dashboard': 'regions and their countries',
'tab.upg-100': "UPG 100 List Posters", 'sub.upg-100': 'my unreached list + posters',
'tab.upg-100': "UPG-100 List Posters", 'sub.upg-100': 'my unreached list + posters',
navLabel: 'Research maps', meta: '{n} maps', loading: 'Loading {label}…', loadFailed: 'Could not load {label}.',
manifestHint: 'This tab is composed from manifest.json — build the tree, or serve the built tree, to load it.',
close: 'Close', help: 'About this map', desktopOnly: 'desktop only', lab: 'lab', experimentalSub: 'experimental bundle',
@ -46,7 +46,7 @@ export const STRINGS = {
'tab.cities-internet': 'Ciudades con Internet', 'sub.cities-internet': 'conectividad de ciudades clave',
'tab.gospel-resources': 'Recursos del Evangelio', 'sub.gospel-resources': 'recursos por lugar',
'tab.regions-dashboard': 'Regiones', 'sub.regions-dashboard': 'regiones y sus países',
'tab.upg-100': "Carteles de la lista UPG 100", 'sub.upg-100': 'mi lista de no alcanzados + carteles',
'tab.upg-100': "Carteles de la lista UPG-100", 'sub.upg-100': 'mi lista de no alcanzados + carteles',
navLabel: 'Mapas de investigación', meta: '{n} mapas', loading: 'Cargando {label}…', loadFailed: 'No se pudo cargar {label}.',
manifestHint: 'Esta pestaña se compone a partir de manifest.json: compila el árbol o sirve el árbol compilado para cargarla.',
close: 'Cerrar', help: 'Acerca de este mapa', desktopOnly: 'solo escritorio', lab: 'beta', experimentalSub: 'mapa experimental',
@ -67,7 +67,7 @@ export const STRINGS = {
'tab.cities-internet': 'Villes avec Internet', 'sub.cities-internet': 'connectivité des villes clés',
'tab.gospel-resources': "Ressources de l'Évangile", 'sub.gospel-resources': 'ressources par lieu',
'tab.regions-dashboard': 'Régions', 'sub.regions-dashboard': 'régions et leurs pays',
'tab.upg-100': "Affiches de la liste UPG 100", 'sub.upg-100': 'ma liste des non atteints + affiches',
'tab.upg-100': "Affiches de la liste UPG-100", 'sub.upg-100': 'ma liste des non atteints + affiches',
navLabel: 'Cartes de recherche', meta: '{n} cartes', loading: 'Chargement de {label}…', loadFailed: 'Impossible de charger {label}.',
manifestHint: "Cet onglet est composé à partir de manifest.json : construisez l'arborescence ou servez l'arborescence construite pour le charger.",
close: 'Fermer', help: 'À propos de cette carte', desktopOnly: 'ordinateur uniquement', lab: 'bêta', experimentalSub: 'carte expérimentale',
@ -88,7 +88,7 @@ export const STRINGS = {
'tab.cities-internet': 'Städte mit Internet', 'sub.cities-internet': 'Konnektivität wichtiger Städte',
'tab.gospel-resources': 'Evangeliumsressourcen', 'sub.gospel-resources': 'Ressourcen nach Ort',
'tab.regions-dashboard': 'Regionen', 'sub.regions-dashboard': 'Regionen und ihre Länder',
'tab.upg-100': "Poster der UPG 100 Liste", 'sub.upg-100': 'meine Liste der Unerreichten + Poster',
'tab.upg-100': "Poster der UPG-100-Liste", 'sub.upg-100': 'meine Liste der Unerreichten + Poster',
navLabel: 'Forschungskarten', meta: '{n} Karten', loading: '{label} wird geladen…', loadFailed: '{label} konnte nicht geladen werden.',
manifestHint: 'Dieser Tab wird aus manifest.json zusammengesetzt – bauen Sie den Baum oder stellen Sie den gebauten Baum bereit, um ihn zu laden.',
close: 'Schließen', help: 'Über diese Karte', desktopOnly: 'nur Desktop', lab: 'Beta', experimentalSub: 'experimentelle Karte',
@ -109,7 +109,7 @@ export const STRINGS = {
'tab.cities-internet': 'Cidades com Internet', 'sub.cities-internet': 'conectividade das principais cidades',
'tab.gospel-resources': 'Recursos do Evangelho', 'sub.gospel-resources': 'recursos por lugar',
'tab.regions-dashboard': 'Regiões', 'sub.regions-dashboard': 'regiões e seus países',
'tab.upg-100': "Cartazes da lista UPG 100", 'sub.upg-100': 'minha lista de não alcançados + cartazes',
'tab.upg-100': "Cartazes da lista UPG-100", 'sub.upg-100': 'minha lista de não alcançados + cartazes',
navLabel: 'Mapas de pesquisa', meta: '{n} mapas', loading: 'Carregando {label}…', loadFailed: 'Não foi possível carregar {label}.',
manifestHint: 'Esta aba é composta a partir do manifest.json — compile a árvore ou sirva a árvore compilada para carregá-la.',
close: 'Fechar', help: 'Sobre este mapa', desktopOnly: 'só no computador', lab: 'beta', experimentalSub: 'mapa experimental',
@ -132,7 +132,7 @@ export const STRINGS = {
'tab.cities-internet': 'Città con Internet', 'sub.cities-internet': 'connettività delle città chiave',
'tab.gospel-resources': 'Risorse del Vangelo', 'sub.gospel-resources': 'risorse per luogo',
'tab.regions-dashboard': 'Regioni', 'sub.regions-dashboard': 'regioni e i loro paesi',
'tab.upg-100': "Poster della lista UPG 100", 'sub.upg-100': 'la mia lista dei non raggiunti + poster',
'tab.upg-100': "Poster della lista UPG-100", 'sub.upg-100': 'la mia lista dei non raggiunti + poster',
navLabel: 'Mappe di ricerca', meta: '{n} mappe', loading: 'Caricamento di {label}…', loadFailed: 'Impossibile caricare {label}.',
manifestHint: "Questa scheda è composta da manifest.json: compila l'albero o pubblica l'albero compilato per caricarla.",
close: 'Chiudi', help: 'Informazioni su questa mappa', desktopOnly: 'solo desktop', lab: 'beta', experimentalSub: 'mappa sperimentale',
@ -153,7 +153,7 @@ export const STRINGS = {
'tab.cities-internet': 'Orașe cu internet', 'sub.cities-internet': 'conectivitatea orașelor-cheie',
'tab.gospel-resources': 'Resurse ale Evangheliei', 'sub.gospel-resources': 'resurse după loc',
'tab.regions-dashboard': 'Regiuni', 'sub.regions-dashboard': 'regiunile și țările lor',
'tab.upg-100': "Afișe din lista UPG 100", 'sub.upg-100': 'lista mea de neatinși + afișe',
'tab.upg-100': "Afișe din lista UPG-100", 'sub.upg-100': 'lista mea de neatinși + afișe',
navLabel: 'Hărți de cercetare', meta: '{n} hărți', loading: 'Se încarcă {label}…', loadFailed: '{label} nu a putut fi încărcat.',
manifestHint: 'Această filă este compusă din manifest.json — construiți arborele sau serviți arborele construit pentru a o încărca.',
close: 'Închide', help: 'Despre această hartă', desktopOnly: 'doar pe desktop', lab: 'beta', experimentalSub: 'hartă experimentală',
@ -174,7 +174,7 @@ export const STRINGS = {
'tab.cities-internet': 'Города с интернетом', 'sub.cities-internet': 'подключённость ключевых городов',
'tab.gospel-resources': 'Евангельские ресурсы', 'sub.gospel-resources': 'ресурсы по местам',
'tab.regions-dashboard': 'Регионы', 'sub.regions-dashboard': 'регионы и их страны',
'tab.upg-100': "Плакаты списка UPG 100", 'sub.upg-100': 'мой список недостигнутых + плакаты',
'tab.upg-100': "Плакаты списка UPG-100", 'sub.upg-100': 'мой список недостигнутых + плакаты',
navLabel: 'Исследовательские карты', meta: 'Карт: {n}', loading: 'Загрузка: {label}…', loadFailed: 'Не удалось загрузить: {label}.',
manifestHint: 'Эта вкладка собирается из manifest.json — соберите дерево или разместите собранное дерево, чтобы загрузить её.',
close: 'Закрыть', help: 'Об этой карте', desktopOnly: 'только на компьютере', lab: 'бета', experimentalSub: 'экспериментальная карта',
@ -195,7 +195,7 @@ export const STRINGS = {
'tab.cities-internet': 'مدن متصلة بالإنترنت', 'sub.cities-internet': 'اتصال المدن الرئيسية',
'tab.gospel-resources': 'موارد الإنجيل', 'sub.gospel-resources': 'الموارد حسب المكان',
'tab.regions-dashboard': 'المناطق', 'sub.regions-dashboard': 'المناطق ودولها',
'tab.upg-100': "ملصقات قائمة UPG 100", 'sub.upg-100': 'قائمتي لغير المُبشَّرين + ملصقات',
'tab.upg-100': "ملصقات قائمة UPG-100", 'sub.upg-100': 'قائمتي لغير المُبشَّرين + ملصقات',
navLabel: 'خرائط البحث', meta: 'عدد الخرائط: {n}', loading: 'جارٍ تحميل {label}…', loadFailed: 'تعذّر تحميل {label}.',
manifestHint: 'تُبنى علامة التبويب هذه من manifest.json — ابنِ الشجرة أو قدّم الشجرة المبنية لتحميلها.',
close: 'إغلاق', help: 'عن هذه الخريطة', desktopOnly: 'على الحاسوب فقط', lab: 'تجريبي', experimentalSub: 'خريطة تجريبية',
@ -216,7 +216,7 @@ export const STRINGS = {
'tab.cities-internet': 'इंटरनेट वाले शहर', 'sub.cities-internet': 'प्रमुख शहरों की कनेक्टिविटी',
'tab.gospel-resources': 'सुसमाचार संसाधन', 'sub.gospel-resources': 'स्थान के अनुसार संसाधन',
'tab.regions-dashboard': 'क्षेत्र', 'sub.regions-dashboard': 'क्षेत्र और उनके देश',
'tab.upg-100': "UPG 100 सूची पोस्टर", 'sub.upg-100': 'मेरी अप्राप्त सूची + पोस्टर',
'tab.upg-100': "UPG-100 सूची पोस्टर", 'sub.upg-100': 'मेरी अप्राप्त सूची + पोस्टर',
navLabel: 'शोध मानचित्र', meta: '{n} मानचित्र', loading: '{label} लोड हो रहा है…', loadFailed: '{label} लोड नहीं हो सका।',
manifestHint: 'यह टैब manifest.json से बनता है — इसे लोड करने के लिए ट्री बनाएँ या बना हुआ ट्री सर्व करें।',
close: 'बंद करें', help: 'इस नक्शे के बारे में', desktopOnly: 'केवल डेस्कटॉप', lab: 'बीटा', experimentalSub: 'प्रायोगिक मानचित्र',
@ -237,7 +237,7 @@ export const STRINGS = {
'tab.cities-internet': '有互联网的城市', 'sub.cities-internet': '主要城市的网络连接',
'tab.gospel-resources': '福音资源', 'sub.gospel-resources': '按地点划分的资源',
'tab.regions-dashboard': '区域', 'sub.regions-dashboard': '区域及其国家',
'tab.upg-100': "UPG 100 名单海报", 'sub.upg-100': '我的未得之民名单 + 海报',
'tab.upg-100': "UPG-100 名单海报", 'sub.upg-100': '我的未得之民名单 + 海报',
navLabel: '研究地图', meta: '{n} 张地图', loading: '正在加载{label}…', loadFailed: '无法加载{label}。',
manifestHint: '此标签页由 manifest.json 组成——请构建目录树或提供已构建的目录树以加载它。',
close: '关闭', help: '关于此地图', desktopOnly: '仅限桌面', lab: '测试版', experimentalSub: '实验性地图',

View file

@ -0,0 +1,60 @@
/**
* The 'upg100-list' poster type: the UPG-100 zone posters, one section per region. Registered from this plugin
* (index.js, registerPosterType), so <dxm-poster-section type="upg100-list" scope="africa"> draws exactly the section
* the UPG-100 poster wall draws. The same zones (zonesForList, list-aware), the same region of each zone
* (upg100-regions.js), the same headings (poster.region_*), and the same print path (the library's records provider
* with this plugin's selector evaluator, and zone-sheet-print.js for the sheet).
* scope = a region's key in either spelling: the slug ("southeast-asia-oceania") or the English name.
*/
import { zonesForList } from './zones-for-list.js'
import { regionOf, regionScope, REGIONS } from './upg100-regions.js'
import { REGION_KEY } from './legend-tree.js'
import { zoneTitle } from './zone-title.js'
import { evaluate as evaluateSelector } from './selector-evaluator.js'
import { makeZoneSheet } from './zone-sheet-print.js'
import { resolvePeopleGroupList } from '@map/lists/peopleGroupList.js'
import { createPeopleGroupRecords } from '@map/lists/peopleGroupRecords.js'
import { countryName } from '@map/utils/countryName.js'
import { keyedError } from '@map/i18n/keyedError.js'
/**
* Every zone the wall shows for the list in force, its card named in the reader's language. zoneTitle declines
* (null) for a zone it cannot name, and that zone keeps its hand-written label, exactly as on the legend and the
* packet.
*/
export function upg100Zones(profileConfig, locale) {
const z = zonesForList(resolvePeopleGroupList(profileConfig))
return [...(z.lists || []), ...(z.asia_lists || []), ...(z.uncovered_lists || [])]
.filter((l) => l && l.id)
.map((l) => { const title = zoneTitle(l, null, { countryName, locale }); return title ? { ...l, label: title } : l })
}
/** A region's heading in the reader's language (poster.region_*, in all 11 locales); the English key if none. */
export function regionTitle(english, t) {
const key = REGION_KEY[english]
if (!key) return english
const v = t(`poster.${key}`)
return v && v !== `poster.${key}` ? v : english
}
const englishOf = (scope) => REGIONS.find((r) => regionScope(r) === regionScope(scope)) || null
export default {
scopes: () => REGIONS.map(regionScope),
items(scope, locale) {
return upg100Zones(null, locale).filter((l) => regionScope(regionOf(l.id)) === regionScope(scope))
},
title(scope, t) {
const english = englishOf(scope)
return english ? regionTitle(english, t) : String(scope || '')
},
actions({ assetsBase, apiBase, lang, profileConfig }) {
const recordsFor = createPeopleGroupRecords({ apiBase, lang, profileConfig, evaluate: (selector, records) => evaluateSelector(selector, records) })
return {
records: (list) => (apiBase() ? recordsFor(list.selector) : Promise.reject(keyedError('wall.hud.noApi', 'no people-groups service is configured'))),
sheet: makeZoneSheet({ allRecords: () => recordsFor.all(), assetsBase, profileConfig }),
unsupported: () => null,
unit: 'UPG', itemCountKey: 'wall.listCount', eventName: 'doxa-upg-100-list:show-on-map', downloadPrefix: 'doxa-upg-100', cardStocks: true,
}
},
}

View file

@ -0,0 +1,61 @@
// upg100-regions.js — which REGION SECTION each UPG-100 zone belongs to, and that section's scope key. PURE (no
// imports), so the poster wall, the 'upg100-list' poster type (upg100-poster-type.js) and the gate read ONE table.
// Moved here verbatim from poster-wall.vue, which groups by it as before.
// ─── REGIONAL SECTIONS ───────────────────────────────────────────────────────
// clusters.json carries no region field, so the mapping lives here. It is keyed by
// list id rather than derived from the selector: a selector can be a wagf_block, a
// country_codes array or an explicit pg_slugs list, and none of those reliably
// implies the continent a reader expects to browse by.
//
// SE Asia + Oceania are ONE section deliberately (the island chains read as a
// single sweep), and the Americas gathers Brazil, the Andean/Caribbean list and the
// US-bearing scatter list.
export const REGION_OF = {
// Africa
'west-africa': 'Africa', 'sudan': 'Africa', 'east-africa': 'Africa',
'central-africa': 'Africa', 'southern-africa-islands': 'Africa',
// Middle East. Maghreb+Egypt is geographically North AFRICA but belongs here:
// the region is read as a cultural/linguistic sweep.
'maghreb-egypt': 'Middle East',
'middle-east-core': 'Middle East',
// CENTRAL ASIA is its own section: the 55-UPG Pakistan map belongs to Central
// Asia, not the Middle East. It had been folded into the Middle
// East as "the same sweep continuing east", but Pakistan, Afghanistan,
// Uzbekistan, Tajikistan, Kyrgyzstan and Kazakhstan are Central/South Asia —
// filing them under the Middle East misnames six countries to save a heading.
'uncovered-nas-a': 'Central Asia',
// Southeast Asia + Oceania
'laos': 'Southeast Asia + Oceania', 'oceania-indonesia': 'Southeast Asia + Oceania',
'mainland-se-asia-philippines': 'Southeast Asia + Oceania',
// Americas
'brazil': 'Americas', 'andean-caribbean': 'Americas', 'uncovered-scatter': 'Americas',
// Europe
'europe': 'Europe',
// India and China are their OWN sections, not one lump called "Asia". Between
// them they are 1,122 people groups across 12 lists — more than every other
// section combined — so collapsing them hides the two largest prayer fields in
// the dataset behind a single continental label. Matched by id prefix below.
}
/** The section a zone belongs to, by its ENGLISH grouping key (REGION_OF, then the India / China id prefixes). */
export function regionOf(id) {
if (REGION_OF[id]) return REGION_OF[id]
if (String(id).startsWith('asia-india-')) return 'India'
// "China + Mongolia": the northern zone declares Mongolia as a member country (its land is drawn and highlighted),
// so the section heading names both rather than folding a sovereign country under a China label.
if (String(id).startsWith('asia-china-')) return 'China + Mongolia'
return 'Other'
}
/**
* A section's SCOPE for <dxm-poster-section type="upg100-list" scope="…">: its English key slugified the way DX
* Life's /regions does (no diacritics, lowercase, "&"/"+" → a dash, non-alphanumerics → "-"), so "Southeast Asia +
* Oceania" is "southeast-asia-oceania" and the English name itself is accepted too.
*/
export const regionScope = (s) => String(s || '').normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase()
.replace(/['’.]/g, '').replace(/&/g, ' and ').replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'other'
/** Every section's English key, in a stable order (the wall itself sorts its sections by size). */
export const REGIONS = ['India', 'China + Mongolia', 'Africa', 'Middle East', 'Central Asia', 'Southeast Asia + Oceania', 'Americas', 'Europe', 'Other']
export default { REGION_OF, regionOf, regionScope, REGIONS }

View file

@ -1,4 +1,6 @@
import { defineMapElement } from '@map/elements/defineMapElement.js'
import { registerPosterType } from '@map/components/poster/posterTypes.js'
import { registerPosterSectionElement } from '@map/elements/posterSectionElement.js'
/**
* plugin-designs/my-upg-100-list/index.js
*
@ -64,4 +66,11 @@ if (typeof customElements !== 'undefined') {
}
}
// ★ THE 'upg100-list' POSTER TYPE, registered from this plugin (no plugin code in the library): one UPG-100 region
// section as an element, <dxm-poster-section type="upg100-list" scope="africa">, drawing the same section the poster
// wall draws (data/upg100-poster-type.js). The element is registered here too (a no-op when another bundle on the
// page did it first), so a page that loads only this bundle can show it.
registerPosterType('upg100-list', () => import('./data/upg100-poster-type.js'))
registerPosterSectionElement()
export default Upg100ListMapElement

View file

@ -1,4 +1,4 @@
{
"_comment": "The printable half of UPG-100: a wall of prayer-card posters, one per 100-list entry, with the three print paths. Declared so the Studio rail names it rather than falling back to a humanized id (check:studio-rail).",
"label": "UPG 100 List Posters — Poster Wall"
"label": "UPG-100 List Posters — Poster Wall"
}

View file

@ -12,7 +12,7 @@
* its records provider.
*
* WHAT COULD NOT BE SHARED, and why each is here rather than in the component:
* REGION_OF / regionFor — the 100-list's own continental taxonomy, keyed by list id because a
* regionFor (REGION_OF in data/upg100-regions.js) — the 100-list's own continental taxonomy, keyed by list id because a
* selector can be a wagf_block, a country_codes array or an explicit
* pg_slugs list and none of those implies a continent.
* fetchListRecords — knows the people-groups API, the selector evaluator AND the pg_slugs
@ -41,7 +41,6 @@
import { computed, inject, ref } from 'vue'
import { useOptionalT, useOptionalI18n } from '@map/composables/useOptionalT.js'
// The page's people-group LIST (library/lists/): every people-group fetch below keeps only its groups.
import { resolvePeopleGroupList } from '@map/lists/peopleGroupList.js'
import PosterWall from '@map/components/poster/PosterWall.vue'
import { resolveAssetsBase } from '@map/utils/embedBase.js'
// The reader's language, for the DATA fetch below. Not for interface text — that goes through t().
@ -49,18 +48,15 @@ import { getRuntimeLocale, detectLocale } from '@map/i18n/index.js'
// The list's total for the intro, from the funnel (never a number written into a string; see data/upg-total.js).
import visionFunnel from '../../data/people-groups/vision-funnel.json'
import { upgTotal, countInSentence } from './data/upg-total.js'
// Named imports: only the list arrays ship in the bundle; the file's bookkeeping fields stay out.
import { zonesForList } from './data/zones-for-list.js'
// The SAME normalize+evaluate pipeline the sibling map profile uses to turn the live
// /people-groups/list payload + a list's `selector` into the exact rows that belong to it.
import { createPeopleGroupRecords } from '@map/lists/peopleGroupRecords.js'
import { makeZoneSheet } from './data/zone-sheet-print.js'
import { REGION_KEY } from './data/legend-tree.js'
import { regionOf } from './data/upg100-regions.js'
// The zones (list-aware, each named in the reader's language) and each region's heading: the 'upg100-list' poster
// type's own functions, so this wall and <dxm-poster-section type="upg100-list"> draw the same cards.
import { upg100Zones, regionTitle } from './data/upg100-poster-type.js'
import { keyedError } from '@map/i18n/keyedError.js'
// A zone's title in the reader's language (tier A: its country; others keep their label) — the same
// generator the map's legend and the packet use, so a card, its alt text and its print say one name.
import { zoneTitle } from './data/zone-title.js'
import { countryName } from '@map/utils/countryName.js'
import { evaluate as evaluateSelector } from './data/selector-evaluator.js'
// The table the zone map sheets were generated from (generate.mjs labels each country with it), so a
@ -82,41 +78,7 @@ const API_BASE = (typeof window !== 'undefined' && window.MAP_APP_API_URL)
|| import.meta.env.VITE_API_BASE_URL
|| ''
// ─── REGIONAL SECTIONS ───────────────────────────────────────────────────────
// clusters.json carries no region field, so the mapping lives here. It is keyed by
// list id rather than derived from the selector: a selector can be a wagf_block, a
// country_codes array or an explicit pg_slugs list, and none of those reliably
// implies the continent a reader expects to browse by.
//
// SE Asia + Oceania are ONE section deliberately (the island chains read as a
// single sweep), and the Americas gathers Brazil, the Andean/Caribbean list and the
// US-bearing scatter list.
const REGION_OF = {
// Africa
'west-africa': 'Africa', 'sudan': 'Africa', 'east-africa': 'Africa',
'central-africa': 'Africa', 'southern-africa-islands': 'Africa',
// Middle East. Maghreb+Egypt is geographically North AFRICA but belongs here:
// the region is read as a cultural/linguistic sweep.
'maghreb-egypt': 'Middle East',
'middle-east-core': 'Middle East',
// CENTRAL ASIA is its own section: the 55-UPG Pakistan map belongs to Central
// Asia, not the Middle East. It had been folded into the Middle
// East as "the same sweep continuing east", but Pakistan, Afghanistan,
// Uzbekistan, Tajikistan, Kyrgyzstan and Kazakhstan are Central/South Asia —
// filing them under the Middle East misnames six countries to save a heading.
'uncovered-nas-a': 'Central Asia',
// Southeast Asia + Oceania
'laos': 'Southeast Asia + Oceania', 'oceania-indonesia': 'Southeast Asia + Oceania',
'mainland-se-asia-philippines': 'Southeast Asia + Oceania',
// Americas
'brazil': 'Americas', 'andean-caribbean': 'Americas', 'uncovered-scatter': 'Americas',
// Europe
'europe': 'Europe',
// India and China are their OWN sections, not one lump called "Asia". Between
// them they are 1,122 people groups across 12 lists — more than every other
// section combined — so collapsing them hides the two largest prayer fields in
// the dataset behind a single continental label. Matched by id prefix below.
}
// ─── REGIONAL SECTIONS: data/upg100-regions.js (moved there so the 'upg100-list' poster type reads the same table) ─
// ⚠ TAKES AN ID, while the shared wall's groupBy takes the whole ITEM. The template
// adapts it — `:group-by="(item) => regionFor(item.id)"` — rather than changing this
// signature, because the id is what the taxonomy is keyed by and every prefix rule
@ -128,19 +90,11 @@ const REGION_OF = {
// grouping — and the heading a reader sees is resolved here, per locale, through REGION_KEY
// (data/legend-tree.js), the one table the legend's region rows translate through as well. Every
// heading has a poster.region_* key in all 11 locales, India and Other included.
const regionLabel = (english) => {
const key = REGION_KEY[english]
return key ? t(`poster.${key}`) : english // no key yet -> the English heading, not a raw key
}
const regionFor = (id) => {
if (REGION_OF[id]) return regionLabel(REGION_OF[id])
if (id.startsWith('asia-india-')) return regionLabel('India')
// "China + Mongolia": the northern zone declares Mongolia as a member country
// (its land is drawn and highlighted), so the section heading names both rather
// than folding a sovereign country under a China label.
if (id.startsWith('asia-china-')) return regionLabel('China + Mongolia')
return regionLabel('Other')
}
const regionFor = (id) => regionTitle(regionOf(id), t)
// ★ COLLAPSIBLE, LIKE COUNTRY POSTERS (each region section is the shared PosterSection, through the wall). Every
// section starts OPEN: a reader who knew the wall finds it as before, and can now fold away the regions they are
// not praying for. (Country Posters starts its small regions shut; UPG-100's regions are all large.)
const allOpen = () => false // no key yet -> the English heading, not a raw key
// One flat list of the zones the map paints — for WHICHEVER list is showing.
//
// ★ THROUGH zonesForList, not a static clusters.json import (pattern work, 2026-09-27). This wall already
@ -156,21 +110,15 @@ const regionFor = (id) => {
// this list IS, and the old comment was describing the wrong thing.
const { locale: wallLocale } = useOptionalI18n('')
const items = computed(() => {
const z = zonesForList(resolvePeopleGroupList(profileConfig))
// The i18n locale REF, read here so this computed re-runs on a runtime language switch: getRuntimeLocale()
// is a plain getter, and a computed that reads only it is resolved once and never again (a frozen label).
const l = wallLocale && (wallLocale.value ?? wallLocale)
const locale = (typeof l === 'string' && l) || getRuntimeLocale() || detectLocale()
return [
...(z.lists || []),
...(z.asia_lists || []),
...(z.uncovered_lists || []),
].filter(l => l && l.id)
// ★ THE CARD'S NAME IN THE READER'S LANGUAGE. item.label is the Show-on-map button's accessible
// name, every poster's alt text and tooltip, the print HUD's title and the printed documents' title
// — all five were English in every locale. zoneTitle declines (null) for a zone it cannot name, and
// that zone keeps its hand-written label, exactly as on the legend and the packet.
.map(l => { const title = zoneTitle(l, null, { countryName, locale }); return title ? { ...l, label: title } : l })
// ★ THE CARD'S NAME IN THE READER'S LANGUAGE (item.label is the Show-on-map button's accessible name, every
// poster's alt text and tooltip, the print HUD's title and the printed documents' title). The zones and their
// names come from the 'upg100-list' poster type's own function, so this wall and <dxm-poster-section
// type="upg100-list"> can never show different cards.
return upg100Zones(profileConfig, locale)
})
// ─── THE RECORDS PROVIDER — now the library's (lists/peopleGroupRecords.js) ─────────
@ -292,6 +240,8 @@ const wallTag = computed(() => t('messages.upg100WallTag'))
download-prefix="doxa-upg-100"
:columns-control="true"
:min-card-px="150"
:collapsible="true"
:collapsed-by="allOpen"
/>
<!-- min-card-px 150: "Posters per row: 2" now SHOWS two on a phone. The shared clamp (210px) forced one at
390 and silently overrode the select, which read 2 (2026-09-30: work like the country posters,

View file

@ -1,4 +1,4 @@
{
"_comment": "The map half of UPG-100: the zoned list of unengaged people groups, with the semantic-tree legend and the packet/poster exports. Declared so the Studio rail names it rather than falling back to a humanized id (check:studio-rail).",
"label": "UPG 100 List Posters — Zoned Map"
"label": "UPG-100 List Posters — Zoned Map"
}

View file

@ -1,7 +1,7 @@
{
"stage": "production",
"type": "nested-elements-mfe",
"label": "UPG 100 List Posters",
"label": "UPG-100 List Posters",
"composes": ["my-upg-100-list/upg-100-list", "my-upg-100-list/poster-wall"],
"note": "Composite MFE built on the pane-wrapper layout (imitates the shell's 'upg-100-list' panes: map at [0,0], Prayer Lists at [1,0]). Makes this bundle MFE-class (tier 1) in the plugin gallery. See eco-dx (internal): PS001-composition-model."
}

View file

@ -15,7 +15,7 @@
export const STRINGS = {
en: {
'sec.posters': 'Posters', 'sec.experimental': 'Experimental',
'tab.upg-100': 'UPG 100 List Posters', 'sub.upg-100': 'my unreached list + posters',
'tab.upg-100': 'UPG-100 List Posters', 'sub.upg-100': 'my unreached list + posters',
'tab.country-posters': 'Country Posters', 'sub.country-posters': 'a poster for every country',
'tab.poster-design': 'Poster Design', 'sub.poster-design': 'every poster style and size',
'tab.wall-of-people-groups': 'Wall of People Groups',
@ -29,7 +29,7 @@ export const STRINGS = {
},
es: {
'sec.posters': 'Carteles', 'sec.experimental': 'Experimental',
'tab.upg-100': 'Carteles de la lista UPG 100', 'sub.upg-100': 'mi lista de no alcanzados + carteles',
'tab.upg-100': 'Carteles de la lista UPG-100', 'sub.upg-100': 'mi lista de no alcanzados + carteles',
'tab.country-posters': 'Carteles por país', 'sub.country-posters': 'un cartel para cada país',
'tab.poster-design': 'Diseño de carteles', 'sub.poster-design': 'todos los estilos y tamaños de cartel',
'tab.wall-of-people-groups': 'Muro de los pueblos',
@ -43,7 +43,7 @@ export const STRINGS = {
},
fr: {
'sec.posters': 'Affiches', 'sec.experimental': 'Expérimental',
'tab.upg-100': 'Affiches de la liste UPG 100', 'sub.upg-100': 'ma liste des non atteints + affiches',
'tab.upg-100': 'Affiches de la liste UPG-100', 'sub.upg-100': 'ma liste des non atteints + affiches',
'tab.country-posters': 'Affiches par pays', 'sub.country-posters': 'une affiche pour chaque pays',
'tab.poster-design': 'Conception d’affiches', 'sub.poster-design': 'tous les styles et formats d’affiche',
'tab.wall-of-people-groups': 'Mur des peuples',
@ -57,7 +57,7 @@ export const STRINGS = {
},
de: {
'sec.posters': 'Poster', 'sec.experimental': 'Experimentell',
'tab.upg-100': 'Poster der UPG 100 Liste', 'sub.upg-100': 'meine Liste der Unerreichten + Poster',
'tab.upg-100': 'Poster der UPG-100-Liste', 'sub.upg-100': 'meine Liste der Unerreichten + Poster',
'tab.country-posters': 'Länderposter', 'sub.country-posters': 'ein Poster für jedes Land',
'tab.poster-design': 'Postergestaltung', 'sub.poster-design': 'alle Posterstile und -größen',
'tab.wall-of-people-groups': 'Wand der Volksgruppen',
@ -71,7 +71,7 @@ export const STRINGS = {
},
pt: {
'sec.posters': 'Cartazes', 'sec.experimental': 'Experimental',
'tab.upg-100': 'Cartazes da lista UPG 100', 'sub.upg-100': 'minha lista de não alcançados + cartazes',
'tab.upg-100': 'Cartazes da lista UPG-100', 'sub.upg-100': 'minha lista de não alcançados + cartazes',
'tab.country-posters': 'Cartazes por país', 'sub.country-posters': 'um cartaz para cada país',
'tab.poster-design': 'Design de cartazes', 'sub.poster-design': 'todos os estilos e tamanhos de cartaz',
'tab.wall-of-people-groups': 'Mural dos povos',
@ -85,7 +85,7 @@ export const STRINGS = {
},
it: {
'sec.posters': 'Poster', 'sec.experimental': 'Sperimentale',
'tab.upg-100': 'Poster della lista UPG 100', 'sub.upg-100': 'la mia lista dei non raggiunti + poster',
'tab.upg-100': 'Poster della lista UPG-100', 'sub.upg-100': 'la mia lista dei non raggiunti + poster',
'tab.country-posters': 'Poster per paese', 'sub.country-posters': 'un poster per ogni paese',
'tab.poster-design': 'Design dei poster', 'sub.poster-design': 'tutti gli stili e i formati dei poster',
'tab.wall-of-people-groups': 'Muro dei popoli',
@ -99,7 +99,7 @@ export const STRINGS = {
},
ro: {
'sec.posters': 'Afișe', 'sec.experimental': 'Experimental',
'tab.upg-100': 'Afișe din lista UPG 100', 'sub.upg-100': 'lista mea de neatinși + afișe',
'tab.upg-100': 'Afișe din lista UPG-100', 'sub.upg-100': 'lista mea de neatinși + afișe',
'tab.country-posters': 'Afișe pe țări', 'sub.country-posters': 'un afiș pentru fiecare țară',
'tab.poster-design': 'Design de afișe', 'sub.poster-design': 'toate stilurile și dimensiunile de afiș',
'tab.wall-of-people-groups': 'Zidul popoarelor',
@ -113,7 +113,7 @@ export const STRINGS = {
},
ru: {
'sec.posters': 'Плакаты', 'sec.experimental': 'Экспериментальное',
'tab.upg-100': 'Плакаты списка UPG 100', 'sub.upg-100': 'мой список недостигнутых + плакаты',
'tab.upg-100': 'Плакаты списка UPG-100', 'sub.upg-100': 'мой список недостигнутых + плакаты',
'tab.country-posters': 'Плакаты по странам', 'sub.country-posters': 'плакат для каждой страны',
'tab.poster-design': 'Дизайн плакатов', 'sub.poster-design': 'все стили и размеры плакатов',
'tab.wall-of-people-groups': 'Стена народов',
@ -127,7 +127,7 @@ export const STRINGS = {
},
ar: {
'sec.posters': 'ملصقات', 'sec.experimental': 'تجريبي',
'tab.upg-100': 'ملصقات قائمة UPG 100', 'sub.upg-100': 'قائمتي لغير المُبشَّرين + ملصقات',
'tab.upg-100': 'ملصقات قائمة UPG-100', 'sub.upg-100': 'قائمتي لغير المُبشَّرين + ملصقات',
'tab.country-posters': 'ملصقات الدول', 'sub.country-posters': 'ملصق لكل دولة',
'tab.poster-design': 'تصميم الملصقات', 'sub.poster-design': 'كل أنماط الملصقات وأحجامها',
'tab.wall-of-people-groups': 'جدار الشعوب',
@ -141,7 +141,7 @@ export const STRINGS = {
},
hi: {
'sec.posters': 'पोस्टर', 'sec.experimental': 'प्रायोगिक',
'tab.upg-100': 'UPG 100 सूची पोस्टर', 'sub.upg-100': 'मेरी अप्राप्त सूची + पोस्टर',
'tab.upg-100': 'UPG-100 सूची पोस्टर', 'sub.upg-100': 'मेरी अप्राप्त सूची + पोस्टर',
'tab.country-posters': 'देश पोस्टर', 'sub.country-posters': 'हर देश के लिए एक पोस्टर',
'tab.poster-design': 'पोस्टर डिज़ाइन', 'sub.poster-design': 'हर पोस्टर शैली और आकार',
'tab.wall-of-people-groups': 'जनसमूहों की दीवार',
@ -155,7 +155,7 @@ export const STRINGS = {
},
zh: {
'sec.posters': '海报', 'sec.experimental': '实验性',
'tab.upg-100': 'UPG 100 名单海报', 'sub.upg-100': '我的未得之民名单 + 海报',
'tab.upg-100': 'UPG-100 名单海报', 'sub.upg-100': '我的未得之民名单 + 海报',
'tab.country-posters': '国家海报', 'sub.country-posters': '每个国家一张海报',
'tab.poster-design': '海报设计', 'sub.poster-design': '所有海报样式与尺寸',
'tab.wall-of-people-groups': '民族之墙',

View file

@ -929,7 +929,7 @@
"bundle": "my-upg-100-list",
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"output": "dx-maps/my-upg-100-list/my-upg-100-list.js",
"integrity": "sha384-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT",
"integrity": "sha384-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q",
"elements": [
"my-upg-100-list-map"
],
@ -952,7 +952,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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"provider\":\"maplibre\",\"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-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -968,8 +968,8 @@
"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": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<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-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<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-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -985,8 +985,8 @@
"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": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<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-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<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-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
}
]

View file

@ -929,7 +929,7 @@
"bundle": "my-upg-100-list",
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"output": "dx-maps/my-upg-100-list/my-upg-100-list.js",
"integrity": "sha384-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT",
"integrity": "sha384-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q",
"elements": [
"my-upg-100-list-map"
],
@ -952,7 +952,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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"provider\":\"maplibre\",\"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-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -968,8 +968,8 @@
"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": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<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-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<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-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -985,8 +985,8 @@
"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": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<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-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<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-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
}
]

File diff suppressed because one or more lines are too long

View file

@ -67,7 +67,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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT" crossorigin="anonymous"></script>
<script src="../my-upg-100-list.js" integrity="sha384-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -76,7 +76,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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT" crossorigin="anonymous"></script>
<script src="../my-upg-100-list.js" integrity="sha384-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -82,7 +82,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-wqGkce90Mk4Dsb5HfOxpamV+vhIh2/W6vtzTTi/gqub5DeZgxKgHg+XzN+36RRRT" crossorigin="anonymous"></script>
<script src="../my-upg-100-list.js" integrity="sha384-CUhGS9/Bdh0HwbbVKldAV7BC7Ljw8GRAWp+gOia5+mbPkTb5nK/mrlmbNX9JR12Q" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order: