Merge origin/development (d81a6ab92, P0b landed) into upg100/unmount-race; rebuild my-upg-100-list from the merged source, and regenerate the tree and SRI

This commit is contained in:
Doxa Maps 2026-09-30 22:24:58 +00:00
commit 11dd21b04c
19 changed files with 498 additions and 199 deletions

View file

@ -13,7 +13,7 @@
> bundle `parameterized` (cap-2) no matter how light it looks, and a `meta.json` `type`
> declares tiers 3/4/5.
Generated from 25 bundle(s).
Generated from 26 bundle(s).
### One canonical exemplar per tier (generated — quote these)
@ -93,4 +93,5 @@ Generated from 25 bundle(s).
|---|---|---|
| `doxa-maps-spa` | `doxa-maps-spa` | `nested-mfe-spa` |
| `plugin-studio` | `plugin-studio` | `nested-mfe-spa` |
| `posterverse` | `posterverse` | `nested-mfe-spa` |

View file

@ -1,7 +1,8 @@
/**
* countrySheet.js — a country's map sheet, GENERATED in the browser at the click.
*
* SHARED (@map/packet/countrySheet.js). Its caller is the regions dashboard's regions-list.
* SHARED (@map/packet/countrySheet.js). Its callers are the regions dashboard's regions-list and the
* Country Posters wall (country-poster-wall.vue), which used to define its own inline copy.
*
* ⚠ THE MOVE HERE WAS NEVER FINISHED, and it cost a real defect. This module's comment used to claim
* two consumers -- the country-poster wall and <doxa-country-map> -- and a CENSUS of the tree found
@ -14,7 +15,8 @@
* `country` without a region -- so countryRegionColor(undefined) returned the old flat teal and
* warned. The same country then printed HUED from Country Posters and TEAL from the Regions tab,
* which is exactly the "two different posters for one country" the hue change exists to refuse.
* The copy is deleted and regions-list imports this. Do not re-copy it: a duplicate of this file is
* The copy is deleted, and regions-list and the wall both import this (check:country-sheet-one-path
* refuses a caller that draws a country sheet any other way). Do not re-copy it: a duplicate of this file is
* indistinguishable from it until one of them is edited, and then it is a silent divergence.
*
* The print standard is generate, store only previews: no country sheet is shipped, and none should
@ -52,12 +54,18 @@
* not introduced by the one-definition change: the plugin-local copy regions-list used before it
* passed no series either. The wall was never affected because it computes its own.
*
* Returns undefined when the item has no sheet tier, so a row without a poster keeps the renderer's
* own default rather than a fabricated position.
* Returns undefined when the item is not in the list (a host's country with no poster), so that row
* keeps the renderer's own default rather than a fabricated position.
*
* A null sheet is a tier too: India (sheet null, too many groups for any paper size) is its own
* 1-of-1 series. Skipping it printed "map 1 of 0" on India's packet page 1 from the Regions tab
* while the wall's own copy printed "map 1 of 1" -- the two paths disagreeing again.
* Every null-sheet country shares that ONE oversized series: a second would make India "map 1 of 2".
* check:country-sheet-one-path fails when that happens, so it is decided, not drifted into.
*/
export function seriesFor(countries, item) {
if (!item || !item.sheet || !Array.isArray(countries)) return undefined
const tier = countries.filter((x) => x.sheet === item.sheet)
if (!item || !Array.isArray(countries)) return undefined
const tier = countries.filter((x) => (x.sheet ?? null) === (item.sheet ?? null))
const index = tier.findIndex((x) => x.id === item.id) + 1
if (!index) return undefined
return { totalGroups: tier.reduce((a, x) => a + (x.count || 0), 0), totalLists: tier.length, index }

View file

@ -49,6 +49,8 @@
"check:composite-token-url": "node internal/check-composite-token-url.mjs",
"check:composites-mount": "node internal/check-composites-mount.mjs",
"check:country-names": "node internal/check-country-names.mjs",
"check:country-sheet-one-path": "node plugin-designs/country-posters/scripts/check-country-sheet-one-path.mjs",
"check:country-sheet-one-path:self-test": "node plugin-designs/country-posters/scripts/check-country-sheet-one-path.mjs --self-test",
"check:coverage-consistent": "node internal/check-gospel-coverage-consistent.mjs",
"check:coverage-consistent:chained": "VERIFY_MAX_AGE_DAYS=36500 node internal/check-gospel-coverage-consistent.mjs",
"check:coverage-consistent:poison": "node internal/check-gospel-coverage-consistent.mjs --poison",
@ -345,7 +347,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:done-evidence check:script-flags check:backlog-status 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:backlog-refs 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",
"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-new-driver-references 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: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:dxlife check:wall-wysiwyg check:wall-print-watch check:wall-no-bg-photos check:template-i18n check:list-pattern-doc check:shadow-style-labels-unique check:grid-image-loading check:retry-fetch",
"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-new-driver-references 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: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:dxlife 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",
"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",
@ -399,6 +401,7 @@
"check:wall-wysiwyg": "node plugin-designs/wall-of-people-groups/scripts/check-wall-wysiwyg.mjs",
"check:wall-print-watch": "node plugin-designs/wall-of-people-groups/scripts/check-wall-print-watch.mjs",
"check:wall-no-bg-photos": "node plugin-designs/wall-of-people-groups/scripts/check-wall-no-bg-photos.mjs",
"check:wall-pan": "node plugin-designs/wall-of-people-groups/scripts/check-wall-pan.mjs",
"check:template-i18n": "node plugin-designs/template-bundle/scripts/check-template-i18n.mjs",
"check:snippets-draw": "node internal/check-snippets-draw.mjs",
"check:snippets-draw:mapbox": "node internal/check-snippets-draw.mjs --mapbox",
@ -421,6 +424,7 @@
"check:wall-wysiwyg": "the Wall's screen IS its poster: the Bless view's on-screen poster and its print come from one layout, so for every preset (3x4ft, 2x3ft, 5x8ft) the sheets, the 2,107 card rects, the card text, the verse reference and the chrome agree. Two-sided on planted layout defects. Headless.",
"check:wall-print-watch": "the Wall's HD poster print never prints silently incomplete: with fake timers and a fake frame, the watch counts photos as they load, counts the ones that could not, and reports both. Two-sided on planted printWatch copies. Headless.",
"check:wall-no-bg-photos": "the Wall's store downloads no photos on its own (it used to test all 932, 132 MB, on every visit): the REAL store runs through Vite against the committed fixtures/pray-list-sample.json with fetch stubbed and every Image request counted. Two-sided with the old background test planted. Headless, no network.",
"check:wall-pan": "the Wall pans and zooms with the pointer 1:1: the REAL WallCanvas methods (through Vite) with d3-zoom's transform arithmetic, over 12 fits and zooms: a pan moves every card exactly as far as the pointer, a zoom keeps the point under the pointer, toWorld inverts toScreen, and a fling never loses the wall. Two-sided: the old transform-inside-the-fit formulas are planted and caught. Headless.",
"check:template-i18n": "the starter template every new plugin copies renders its text from the catalogue: profile B, server-rendered with the REAL template.json in en, ar and zh, takes its heading, note and sentence from the page's language. Two-sided with the English catalogue served as Arabic. Headless (SSR).",
"check:coverage-consistent:chained": "every clause of check:coverage-consistent EXCEPT the link-verification age (VERIFY_MAX_AGE_DAYS set out of reach): the chains run what depends on the code and data, and leave what depends on the calendar to the on-demand run, so the gates cannot turn red on a date with no change.",
"check:viewport-meta": "every generated page declares <meta name=\"viewport\"> with width=device-width. Without it a browser lays the page out at the 980px desktop fallback even when the viewport is set to 390, so a mobile probe silently measures a viewport no phone has and still passes (measured: innerWidth 980 without the tag, 390 with it). width=device-width is required specifically, because a meta carrying only initial-scale still lays out at 980. Checked on the BUILT tree, not the generator template. Fixed-size print sheets are exempt by their stated shape (a .stage with a three-digit px width), and a page that must render at a fixed desktop width carries a viewport-meta-ok: reason. 8 self-tests. Source-only, headless.",
@ -445,6 +449,8 @@
"check:composite-token-url": "a composite embedded BARE (no outer ProfileLoader) must honour a tokenUrl-only config: it reads tokenUrl, forwards it, and asks the token service only when no token is given. The expectation is derived from ProfileLoader, not restated. Headless; in gates:pre.",
"check:composites-mount": "every capability-4/5 composite's OWN setup() and mounted hooks run without throwing, in en and ar, headless (no browser): vite loads each composite as its bundle entry defines it (configureApp, and ProfileLoader's provides where the entry mounts ProfileLoader), and @vue/runtime-core mounts it on a no-op renderer. Exists because 08f89f55 shipped two composites calling getRuntimeLocale/detectLocale/RTL_LOCALES with no import: the build was green, setup threw a ReferenceError in every locale, and Big Picture and Simple Research rendered nothing. Proves setup runs; cannot prove the children render.",
"check:country-names": "every ISO 3166-1 alpha-3 our data uses must resolve to a localized country name. Guards the JOIN, not Intl: library/data/iso3-to-alpha2.json drifting from library/data/countries.json makes a country render as a bare code, which still looks like a value. Checks en/ar/zh (ar is our only RTL locale; zh makes an untranslated Latin code unmistakable) and asserts BOTH directions of drift. Carries two negative arms — an unassigned code and a malformed one — and FAILS if either resolves, because a coverage count cannot otherwise tell a hit from a lookup that returns its input.",
"check:country-sheet-one-path": "a country sheet is drawn through ONE path, @map/packet/countrySheet.js, so one country cannot print two posters. Parses (comments cannot count) every plugin source naming generateCountrySheet/makeCountrySheet: a direct generateCountrySheet in code FAILS, every makeCountrySheet call must pass `countries` (the series list), and both known callers (the Country Posters wall, regions-list) must be found. Also runs seriesFor over the real country-posters.json with named answers: India 1 of 1, every 3x3 country N of the 3x3 tier with no repeat, a code absent from the data no series.",
"check:country-sheet-one-path:self-test": "plants each defect check:country-sheet-one-path guards (a direct generateCountrySheet call, makeCountrySheet without countries, the old guard that skipped India, a position given to an absent code) and requires each to FAIL; a comment naming generateCountrySheet must NOT.",
"check:coverage-consistent": "the gospel-resources surfaces must agree: no resource on an ISO RESERVED code (und/mul/mis/zxx), every resourced code NAMED, table reach recounted off the pins, no invented URL, tiers reconcile. Static, sub-second. Self-test: `bun run check:coverage-consistent:poison`, all 12 clauses (A-L) must fail. Clause L is the one that is not about consistency: it fails when the link-verification record goes stale, because 'link checked' is a claim about the present tense. Written after the same drift defect was found by hand three times.",
"check:csv-shape": "the export must OPEN as a table: header on line 0, every row matching. Run the `check:csv-shape:self-test` script for the NEGATIVE test (forces the provenance comment back to line 0 IN MEMORY and requires this gate to REJECT it) — the header used to claim 'NEGATIVE-TESTED' with no way to re-run it.",
"check:dashboard-filter-a11y": "the dashboard's cross-filter is operable and audible: every filter chip is a <button type=\"button\"> with an aria-label naming the ACTION (a filter that can be set by keyboard must be clearable by keyboard), the shell carries exactly ONE always-rendered polite role=\"status\" region so a brush that changes a number far from the control is announced once rather than six times or not at all, and no resize handle's accessible name is a raw English literal. AST over the parsed templates plus the built bundle — no browser (rega's alone).",

View file

@ -48,6 +48,7 @@ import { getRuntimeLocale, detectLocale } from '@map/i18n/index.js'
// library/. Generated by library/scripts/posters/emit-countries.mjs, which now writes there.
import data from '@map/data/country-posters.json'
import { resolveAssetsBase } from '@map/utils/embedBase.js'
import { makeCountrySheet } from '@map/packet/countrySheet.js'
// The regions catalogue holds the not-yet sentence a host's country gets when no poster exists (all eleven locales);
// its keys are English sentences with dots, so it is read by literal key, the way regions-list.vue reads it.
import { useRegionsI18n } from '@map/i18n/useRegionsI18n.js'
@ -125,23 +126,20 @@ const recordsFor = createPeopleGroupRecords({
profileConfig,
})
const countryRecords = (c) => recordsFor({ type: 'country', values: [c.iso3] })
// ★ GENERATED AT THE CLICK: the country's sheet is drawn in the browser from its people groups and the
// world boundaries (packet/posterSheets.js — the same generator the Node script runs), for the poster
// print (letter, vector) and the packet's page 1. No stored sheet exists for a country; this is the path.
// The series facts are the ones generate.mjs states in country mode: map N of M over the countries on
// the same sheet size, and their total groups.
// ★ GENERATED AT THE CLICK, through the ONE shared path (@map/packet/countrySheet.js, which the Regions
// tab uses too): the country's sheet is drawn in the browser from its people groups and the world
// boundaries, for the poster print (letter, vector) and the packet's page 1. No stored sheet exists for a
// country. The series facts (map N of M over the countries on the same sheet size) come from the same
// list, so this wall and the Regions tab print the same numbers for one country.
// ⚠ THE SHEET GETS THE DATA'S OWN RECORD, not the card: the generated poster is English by recorded
// decision (series.json english_only_note), so it must not receive a localized label, and the series index
// is found by id because a language switch rebuilds the card objects.
async function countrySheet(card, format) {
const c = byId.get(card.id) || card
const [{ generateCountrySheet }, { ISO3_NAME }, records] = await Promise.all([
import('@map/packet/posterSheets.js'), import('@map/data/iso3-name.js'), countryRecords(c),
])
const tier = (data.countries || []).filter((x) => x.sheet === c.sheet)
const series = { totalGroups: tier.reduce((a, x) => a + (x.count || 0), 0), totalLists: tier.length, index: tier.findIndex((x) => x.id === c.id) + 1 }
return generateCountrySheet({ country: c, records, assetsBase: assetsBase.value, ISO3_NAME, format, series })
}
const sheetForRecord = makeCountrySheet({
records: recordsFor,
assetsBase: () => assetsBase.value,
countries: data.countries || [],
})
const countrySheet = (card, format) => sheetForRecord(byId.get(card.id) || card, format)
// The name table the generated sheet was labelled from, so a packet in another language relabels page 1's
// country names (the same seam the UPG-100 wall passes).
const iso3Names = () => import('@map/data/iso3-name.js').then((m) => m.ISO3_NAME)

View file

@ -0,0 +1,156 @@
#!/usr/bin/env node
// check:country-sheet-one-path — a country's map sheet is drawn through ONE path, so one country
// cannot print two different posters.
//
// WHY: two callers draw a country sheet (the Country Posters wall and the Regions tab's regions-list).
// Each once had its own wrapper around generateCountrySheet, and they drifted twice: the Regions tab
// printed a country in flat teal while the wall printed it in its region's hue, and the Regions tab
// printed India's packet page 1 as "map 1 of 0" while the wall said "map 1 of 1". Both now go through
// @map/packet/countrySheet.js (makeCountrySheet + seriesFor).
//
// ARM A (structure, over the TREE): every plugin file whose CODE (parsed, so comments cannot count)
// names generateCountrySheet is a violation; every caller of makeCountrySheet passes `countries`, so
// its "map N of M" is computed from the same list; and at least the two known callers are found (a
// census that finds fewer is NOT MEASURED, never a pass).
// ARM B (behaviour, over the real library/data/country-posters.json): seriesFor gives named answers:
// India (sheet null) is 1 of 1, every 3x3 country is N of the 3x3 tier with no repeated N, a code
// absent from the data gets no series.
//
// Exit 0 pass, 1 fail, 75 not measured. `--self-test` plants each defect and requires its arm to fail.
import { readFileSync, readdirSync, statSync } from 'node:fs'
import { join, relative, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { parse as parseSfc, babelParse } from '@vue/compiler-sfc'
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..')
const PD = join(ROOT, 'plugin-designs')
const KNOWN_CALLERS = ['plugin-designs/country-posters/country-poster-wall.vue', 'plugin-designs/regions-dashboard/regions-list.vue']
function scriptsOf(file, src) {
if (!file.endsWith('.vue')) return [src]
const { descriptor, errors } = parseSfc(src, { filename: file })
if (errors.length) throw new Error(`${file}: SFC parse error: ${errors[0].message || errors[0]}`)
return [descriptor.script, descriptor.scriptSetup].filter(Boolean).map((b) => b.content)
}
function walk(node, visit) {
if (!node || typeof node.type !== 'string') return
visit(node)
for (const k of Object.keys(node)) {
if (k === 'loc' || k === 'start' || k === 'end' || k === 'leadingComments' || k === 'trailingComments') continue
const v = node[k]
if (Array.isArray(v)) v.forEach((c) => c && typeof c.type === 'string' && walk(c, visit))
else if (v && typeof v.type === 'string') walk(v, visit)
}
}
// -> { names: Set of identifier names used in code, makeCalls: [{ hasCountries }] }
function codeFacts(file, src) {
const names = new Set()
const makeCalls = []
for (const code of scriptsOf(file, src)) {
const ast = babelParse(code, { sourceType: 'module', plugins: ['typescript'] })
walk(ast.program, (n) => {
if (n.type === 'Identifier') names.add(n.name)
if (n.type === 'CallExpression' && n.callee.type === 'Identifier' && n.callee.name === 'makeCountrySheet') {
const arg = n.arguments[0]
const hasCountries = !!(arg && arg.type === 'ObjectExpression'
&& arg.properties.some((p) => p.key && (p.key.name === 'countries' || p.key.value === 'countries')))
makeCalls.push({ hasCountries })
}
})
}
return { names, makeCalls }
}
function listSources(dir, out = []) {
for (const e of readdirSync(dir)) {
if (e === 'node_modules' || e.startsWith('.')) continue
const p = join(dir, e)
const st = statSync(p)
if (st.isDirectory()) listSources(p, out)
else if (/\.(vue|js|mjs)$/.test(e) && !/\/scripts\//.test(p)) out.push(p)
}
return out
}
// ARM A over a { relPath: source } map. Returns failure strings; `callers` gets the files that call makeCountrySheet.
export function armA(files, callers = []) {
const fails = []
for (const [rel, src] of Object.entries(files)) {
if (!/generateCountrySheet|makeCountrySheet/.test(src)) continue // a text prefilter; the parse decides
const { names, makeCalls } = codeFacts(rel, src)
if (names.has('generateCountrySheet')) fails.push(`${rel}: draws a country sheet directly (generateCountrySheet in code); use makeCountrySheet from @map/packet/countrySheet.js`)
if (makeCalls.length) callers.push(rel)
makeCalls.forEach((c, i) => { if (!c.hasCountries) fails.push(`${rel}: makeCountrySheet call #${i + 1} passes no \`countries\`, so its "map N of M" is not the wall's`) })
}
return fails
}
// ARM B: named expectations for seriesFor over the real data.
export function armB(seriesFor, countries) {
const fails = []
const by = (iso) => countries.find((c) => c.iso3 === iso)
const ind = by('IND')
const s = ind && seriesFor(countries, ind)
const oversized = countries.filter((c) => (c.sheet ?? null) === null)
if (oversized.length > 1) fails.push(`${oversized.length} countries have no sheet size (${oversized.map((c) => c.iso3).join(', ')}): they now share ONE oversized series, so India prints "map 1 of ${oversized.length}". Decide that deliberately, then update this expectation.`)
if (!ind) fails.push('India is missing from country-posters.json')
else if (!s || s.index !== 1 || s.totalLists !== 1 || s.totalGroups !== ind.count) fails.push(`India (sheet ${JSON.stringify(ind.sheet)}) should be map 1 of 1 with ${ind.count} groups; got ${JSON.stringify(s)}`)
const t3 = countries.filter((c) => c.sheet === '3x3')
const seen = new Set()
for (const c of t3) {
const r = seriesFor(countries, c)
if (!r || r.totalLists !== t3.length || r.index < 1 || r.index > t3.length) { fails.push(`${c.iso3} (3x3) should be N of ${t3.length}; got ${JSON.stringify(r)}`); break }
seen.add(r.index)
}
if (seen.size && seen.size !== t3.length) fails.push(`3x3 tier: ${seen.size} distinct indexes for ${t3.length} countries`)
const absent = seriesFor(countries, { id: 'country-zzz', iso3: 'ZZZ', label: 'ZZZ', count: 3 })
if (absent !== undefined) fails.push(`a country absent from the data should get no series; got ${JSON.stringify(absent)}`)
if (seriesFor(null, ind) !== undefined) fails.push('seriesFor with no list should return undefined')
return fails
}
async function main() {
const selfTest = process.argv.includes('--self-test')
const { seriesFor } = await import(join(ROOT, 'library/packet/countrySheet.js'))
const data = JSON.parse(readFileSync(join(ROOT, 'library/data/country-posters.json'), 'utf8'))
const countries = data.countries || []
if (countries.length < 170) { console.log(`NOT MEASURED: country-posters.json parsed ${countries.length} countries (floor 170)`); process.exitCode = 75; return }
const files = {}
for (const p of listSources(PD)) files[relative(ROOT, p)] = readFileSync(p, 'utf8')
if (selfTest) {
const wall = KNOWN_CALLERS[0]
const cases = [
['direct generateCountrySheet call', () => armA({ ...files, [wall]: files[wall].replace('<script setup>', "<script setup>\nimport { generateCountrySheet } from '@map/packet/posterSheets.js'\ngenerateCountrySheet({})") })],
['makeCountrySheet without countries', () => armA({ ...files, [wall]: files[wall].replace(/countries: data\.countries \|\| \[\],/, '') })],
['India skipped (the old guard)', () => armB((l, it) => (!it || !it.sheet ? undefined : seriesFor(l, it)), countries)],
['absent code given a position', () => armB((l, it) => seriesFor(l, it) || { index: 1, totalLists: 1, totalGroups: 0 }, countries)],
['a second no-sheet country joins India', () => armB(seriesFor, countries.map((c) => (c.iso3 === 'CHN' ? { ...c, sheet: null } : c)))],
]
let bad = 0
for (const [name, run] of cases) {
const f = run()
console.log(`${f.length ? '✓ caught' : '✗ MISSED'} ${name}${f.length ? ` -> ${f[0]}` : ''}`)
if (!f.length) bad++
}
// The negative control: a comment naming the forbidden call must NOT fail.
const commented = armA({ ...files, [wall]: files[wall].replace('<script setup>', '<script setup>\n// generateCountrySheet(x) is not called here') })
console.log(`${commented.length ? '✗ FALSE RED' : '✓ ignored'} a comment naming generateCountrySheet`)
if (commented.length) bad++
process.exitCode = bad ? 1 : 0
return
}
const callers = []
const fails = [...armA(files, callers), ...armB(seriesFor, countries)]
const missing = KNOWN_CALLERS.filter((k) => !callers.includes(k))
if (missing.length) fails.push(`known callers not found calling makeCountrySheet: ${missing.join(', ')}`)
if (fails.length) { fails.forEach((f) => console.log(`FAIL ${f}`)); process.exitCode = 1; return }
const ind = seriesFor(countries, countries.find((c) => c.iso3 === 'IND'))
console.log(`PASS check:country-sheet-one-path — ${Object.keys(files).length} plugin sources parsed-or-skipped, makeCountrySheet callers: ${callers.join(', ')}; seriesFor over ${countries.length} countries (India ${ind.index} of ${ind.totalLists})`)
}
main().catch((e) => { console.error(`FAIL ${e.stack || e}`); process.exitCode = 1 })

View file

@ -0,0 +1,103 @@
#!/usr/bin/env node
/**
* check-wall-pan — the Wall pans and zooms with the pointer, 1 : 1. Headless.
*
* d3-zoom on a <canvas> reports its transform in the canvas's own CSS px, and wallCanvas.js applies it AFTER
* the "meet" fit of the world into the canvas. It used to apply it inside the fit, so every pan moved the wall
* by only the fit scale k0 of the pointer (measured on development 6e1a33534: a 200 px mouse drag panned 34 px
* at 1440; a 120 × 200 px finger drag 14 × 23 px on a phone) and a wheel zoom drifted off the pointer.
* This runs the REAL WallCanvas methods (through Vite, so @map resolves) with d3's own transform arithmetic
* and asserts, over several fits and zooms:
* - a pan of d px in d3's space moves every card d px on screen;
* - a zoom about a pointer keeps the world point under that pointer;
* - toWorld inverts toScreen;
* - constrain() keeps the wall over the centre of the view after a fling, and leaves a resting view alone.
* Two-sided: the old formulas (transform inside the fit) are planted and must fail the pan and zoom arms.
* EXIT 0 pass · 1 fail
*/
import { resolve, dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { createServer } from 'vite'
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../../..')
const server = await createServer({ root: ROOT, configFile: join(ROOT, 'vite.config.js'), server: { middlewareMode: true, hmr: false, ws: false }, appType: 'custom', logLevel: 'error', optimizeDeps: { noDiscovery: true, include: [] } })
// d3-zoom's ZoomTransform arithmetic (d3-zoom/src/transform.js): translate() works in pre-scale units.
class T {
constructor(k, x, y) { this.k = k; this.x = x; this.y = y }
translate(x, y) { return new T(this.k, this.x + this.k * x, this.y + this.k * y) }
invert(p) { return [(p[0] - this.x) / this.k, (p[1] - this.y) / this.k] }
}
// d3's zoom about a pointer p: the point under p (in d3's space) stays under p.
const zoomAbout = (t, k, p) => { const q = t.invert(p); return new T(k, p[0] - q[0] * k, p[1] - q[1] * k) }
/** A WallCanvas with no DOM: the prototype's own methods, over a fitted world. */
function wall(W, cssW, cssH, worldW, worldH) {
const w = Object.create(W.prototype)
w.mode = 'social'; w.sp = null; w.o = { worldW, worldH }; w.cssW = cssW; w.cssH = cssH
w.k0 = Math.min(cssW / worldW, cssH / worldH); w.ox = (cssW - worldW * w.k0) / 2; w.oy = (cssH - worldH * w.k0) / 2
w.t = new T(1, 0, 0)
return w
}
function run(W, plant = false) {
const errs = []
if (plant) { // the formulas before the fix: d3's transform applied inside the fit
Object.defineProperty(W.prototype, 'tx', { configurable: true, get() { return this.ox + this.t.x * this.k0 } })
Object.defineProperty(W.prototype, 'ty', { configurable: true, get() { return this.oy + this.t.y * this.k0 } })
}
const cases = [[1440, 793, 3456, 4608], [390, 696, 5760, 9216], [1184, 791, 4000, 3000], [390, 696, 3000, 4000]]
let checked = 0
for (const [cssW, cssH, worldW, worldH] of cases) {
for (const k of [1, 2.5, 9]) {
const w = wall(W, cssW, cssH, worldW, worldH)
w.t = zoomAbout(w.t, k, [cssW * 0.3, cssH * 0.6])
const pt = [worldW * 0.37, worldH * 0.61], s0 = w.toScreen(...pt)
// pan: a drag of (120, -200) px is t.translate(120 / k, -200 / k) in d3
w.t = w.t.translate(120 / k, -200 / k)
const s1 = w.toScreen(...pt)
const ratio = [(s1[0] - s0[0]) / 120, (s1[1] - s0[1]) / -200]
if (Math.abs(ratio[0] - 1) > 1e-9 || Math.abs(ratio[1] - 1) > 1e-9) errs.push(`pan ${cssW}×${cssH} world ${worldW}×${worldH} zoom ${k}: the wall moved ${ratio.map((r) => r.toFixed(3)).join(' × ')} of the pointer, not 1`)
// zoom about a pointer: the world point under it stays
const p = [cssW * 0.71, cssH * 0.23], before = w.toWorld(...p)
w.t = zoomAbout(w.t, k * 1.4, p)
const after = w.toScreen(...before)
if (Math.hypot(after[0] - p[0], after[1] - p[1]) > 1e-6) errs.push(`zoom ${cssW}×${cssH} zoom ${k}: the point under the pointer drifted ${Math.hypot(after[0] - p[0], after[1] - p[1]).toFixed(1)} px`)
const back = w.toScreen(...w.toWorld(...p))
if (Math.hypot(back[0] - p[0], back[1] - p[1]) > 1e-6) errs.push('toWorld does not invert toScreen')
// constrain: a fling five views away still leaves the wall over the centre; a resting view is untouched
const rest = w.t
if (w.constrain(rest) !== rest) errs.push(`constrain moved a view that already covers the centre (${cssW}×${cssH}, zoom ${k})`)
for (const [fx, fy] of [[5, 0], [-5, 0], [0, 5], [0, -5]]) {
w.t = w.constrain(rest.translate(fx * cssW / rest.k, fy * cssH / rest.k))
const [x0, y0] = w.toScreen(0, 0), [x1, y1] = w.toScreen(worldW, worldH)
if (!(x0 <= cssW / 2 + 1e-6 && x1 >= cssW / 2 - 1e-6 && y0 <= cssH / 2 + 1e-6 && y1 >= cssH / 2 - 1e-6)) errs.push(`a fling (${fx}, ${fy}) views away lost the wall (${cssW}×${cssH}, zoom ${k})`)
}
checked++
}
}
if (plant) { delete W.prototype.tx; delete W.prototype.ty }
return { errs, checked }
}
const fails = []
let real = null
try {
const { WallCanvas } = await server.ssrLoadModule('/plugin-designs/wall-of-people-groups/src/wallCanvas.js')
const own = { tx: Object.getOwnPropertyDescriptor(WallCanvas.prototype, 'tx'), ty: Object.getOwnPropertyDescriptor(WallCanvas.prototype, 'ty') }
if (!own.tx || !own.ty) fails.push('WallCanvas has no tx/ty getters: this check reads the wrong file or the renderer changed shape')
else {
real = run(WallCanvas)
fails.push(...real.errs)
if (real.checked < 12) fails.push(`only ${real.checked} of 12 cases ran`)
const planted = run(WallCanvas, true)
Object.defineProperty(WallCanvas.prototype, 'tx', own.tx); Object.defineProperty(WallCanvas.prototype, 'ty', own.ty)
if (!planted.errs.some((e) => /^pan /.test(e))) fails.push('SELF-TEST: the old in-fit transform was not caught by the pan arm')
if (!planted.errs.some((e) => /^zoom /.test(e))) fails.push('SELF-TEST: the old in-fit transform was not caught by the zoom arm')
}
} catch (e) { fails.push('could not run WallCanvas: ' + e.message) }
await server.close()
if (fails.length) { console.log('WALL-PAN: FAIL'); for (const f of fails) console.log(' - ' + f); process.exit(1) }
console.log(`WALL-PAN: PASS — ${real.checked} fits × zooms: a pan moves the wall 1:1 with the pointer, a zoom keeps the point under the pointer, toWorld inverts toScreen, and a fling never loses the wall; the old in-fit transform is caught.`)
process.exit(0)

View file

@ -75,7 +75,20 @@ export class WallCanvas {
this.ctx = this.canvas.getContext('2d')
this.icons = Object.fromEntries(Object.entries(ICON).map(([k, d]) => [k, new Path2D(d)]))
const d3 = wallD3()
this.zoom = d3.zoom().scaleExtent([0.1, 20]).filter((e) => !e.ctrlKey && !e.button)
// d3's transform lives in the canvas's own CSS px (d3.pointer on a <canvas> is element px, unlike the old
// SVG, whose viewBox made it world units), so it is applied AFTER the "meet" fit: screen = t(fit(world)).
// Multiplying it by the fit scale instead moved the wall by only k0 of the pointer (measured on
// development 6e1a33534: a 200 px drag panned 34 px at 1440, a 120 × 200 px finger drag 14 × 23 px on a
// phone), so the wall could barely be panned.
// A ctrl-wheel is a trackpad pinch (or ctrl + mouse wheel): it zooms the wall. Filtering it out let the
// browser zoom the whole page instead. Its step is capped, so one mouse notch is at most ~1.4×.
this.zoom = d3.zoom().scaleExtent([0.1, 20])
.filter((e) => (!e.ctrlKey || e.type === 'wheel') && !e.button)
.wheelDelta((e) => {
const d = -e.deltaY * (e.deltaMode === 1 ? 0.05 : e.deltaMode ? 1 : 0.002)
return e.ctrlKey ? Math.max(-0.5, Math.min(0.5, d * 5)) : d
})
.constrain((t) => this.constrain(t))
.on('zoom', (e) => { this.t = e.transform; this.request() })
this.sel = d3.select(this.canvas).call(this.zoom).on('dblclick.zoom', null)
this._click = (e) => this.onClick(e)
@ -140,17 +153,31 @@ export class WallCanvas {
this.request()
}
/** Screen px of one world unit, and world → screen. */
/** Screen px of one world unit, and world → screen: the "meet" fit first, then d3's transform (CSS px). */
get scale() { return this.k0 * this.t.k }
toScreen(x, y) { return [this.ox + (x * this.t.k + this.t.x) * this.k0, this.oy + (y * this.t.k + this.t.y) * this.k0] }
toWorld(px, py) { return [((px - this.ox) / this.k0 - this.t.x) / this.t.k, ((py - this.oy) / this.k0 - this.t.y) / this.t.k] }
get tx() { return this.t.x + this.t.k * this.ox }
get ty() { return this.t.y + this.t.k * this.oy }
toScreen(x, y) { return [this.tx + x * this.scale, this.ty + y * this.scale] }
toWorld(px, py) { return [(px - this.tx) / this.scale, (py - this.ty) / this.scale] }
/** Open at a zoom where one card is `cardPx` wide (the old wall opened at ~96 px). */
/**
* Keep the wall findable: however far it is panned, it still covers the middle of the view (a zoomed-out
* wall smaller than the view may move, but never off it). Without this a fast fling left an empty grey table.
*/
constrain(t) {
const W = this.worldW * this.k0, H = this.worldH * this.k0, cx = this.cssW / 2, cy = this.cssH / 2
const x0 = t.x + t.k * this.ox, y0 = t.y + t.k * this.oy
const dx = x0 > cx ? cx - x0 : x0 + t.k * W < cx ? cx - x0 - t.k * W : 0
const dy = y0 > cy ? cy - y0 : y0 + t.k * H < cy ? cy - y0 - t.k * H : 0
return dx || dy ? t.translate(dx / t.k, dy / t.k) : t // d3's translate() is in pre-scale units
}
/** Open at a zoom where one card is `cardPx` wide (the old wall opened at ~96 px), world top-left in place. */
startView(cardPx = 96) {
if (this.posterOn) return this.fitAll() // the poster opens whole: what you see is what prints
if (!this.grid) return
const k = Math.max(1, Math.min(20, cardPx / (this.grid.cw * this.k0)))
this.sel.call(this.zoom.transform, wallD3().zoomIdentity.scale(k))
this.sel.call(this.zoom.transform, wallD3().zoomIdentity.translate(this.ox * (1 - k), this.oy * (1 - k)).scale(k))
}
resetZoom() { this.sel.transition().duration(750).call(this.zoom.transform, wallD3().zoomIdentity) }
@ -177,7 +204,7 @@ export class WallCanvas {
ctx.setTransform(1, 0, 0, 1, 0, 0)
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
if (!this.grid) return
const s = this.scale, tx = this.ox + this.t.x * this.k0, ty = this.oy + this.t.y * this.k0
const s = this.scale, tx = this.tx, ty = this.ty
ctx.setTransform(this.dpr * s, 0, 0, this.dpr * s, this.dpr * tx, this.dpr * ty)
if (this.posterOn) return this.drawPoster(ctx, s, tx, ty)
const cardPx = this.grid.cw * s

View file

@ -76,7 +76,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <country-posters-map> custom element. -->
<script src="../country-posters.js" integrity="sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh" crossorigin="anonymous"></script>
<script src="../country-posters.js" integrity="sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -67,7 +67,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <country-posters-map> custom element. -->
<script src="../country-posters.js" integrity="sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh" crossorigin="anonymous"></script>
<script src="../country-posters.js" integrity="sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -81,7 +81,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <country-posters-map> custom element. -->
<script src="../country-posters.js" integrity="sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh" crossorigin="anonymous"></script>
<script src="../country-posters.js" integrity="sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

View file

@ -200,7 +200,7 @@
"bundle": "country-posters",
"scriptUrl": "./country-posters/country-posters.js",
"output": "dx-maps/country-posters/country-posters.js",
"integrity": "sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh",
"integrity": "sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0",
"elements": [
"country-posters-map"
],
@ -223,8 +223,8 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/countries-map/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=\"./country-posters/country-posters.js\" integrity=\"sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh\" 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<country-posters-map profile-config='{\"profile\":\"countries-map\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<country-posters-map profile-config='{\"profile\":\"countries-map\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0\" 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<country-posters-map profile-config='{\"profile\":\"countries-map\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<country-posters-map profile-config='{\"profile\":\"countries-map\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
},
{
@ -240,7 +240,7 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/country-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=\"./country-posters/country-posters.js\" integrity=\"sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<country-posters-map profile-config='{\"profile\":\"country-poster-wall\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<country-posters-map profile-config='{\"profile\":\"country-poster-wall\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
},
{
@ -256,8 +256,8 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh\" 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<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0\" 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<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
}
]
@ -1180,7 +1180,7 @@
"bundle": "regions-dashboard",
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"output": "dx-maps/regions-dashboard/regions-dashboard.js",
"integrity": "sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj",
"integrity": "sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx",
"elements": [
"regions-dashboard"
],
@ -1203,8 +1203,8 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/region-dashboards/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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj\" 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<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>",
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx\" 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<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>",
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
@ -1220,7 +1220,7 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/regions-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
@ -1236,8 +1236,8 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/regions-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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj\" 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<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>",
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx\" 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<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>",
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
}
]
@ -1473,7 +1473,7 @@
"bundle": "wall-of-people-groups",
"scriptUrl": "./wall-of-people-groups/wall-of-people-groups.js",
"output": "dx-maps/wall-of-people-groups/wall-of-people-groups.js",
"integrity": "sha384-jXcu2Fpvms5zKTuyxRQ1oZG7jciYNwC1+KOpUYXMlm5u59l3SGJOLxN3vbXvt5c1",
"integrity": "sha384-S2g83dVn7Vb2ynBlin0ySD8rO/cFEdA60yPYJ+04ObqzXmiojWOZ5ufGPj4URG9t",
"elements": [
"wall-of-people-groups"
],
@ -1492,7 +1492,7 @@
"scriptUrl": "./wall-of-people-groups/wall-of-people-groups.js",
"embed": {
"iframe": "<iframe src=\"./wall-of-people-groups/wall-of-people-groups/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=\"./wall-of-people-groups/wall-of-people-groups.js\" integrity=\"sha384-jXcu2Fpvms5zKTuyxRQ1oZG7jciYNwC1+KOpUYXMlm5u59l3SGJOLxN3vbXvt5c1\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<wall-of-people-groups profile-config='{\"profile\":\"wall-of-people-groups\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></wall-of-people-groups>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./wall-of-people-groups/wall-of-people-groups.js\" integrity=\"sha384-S2g83dVn7Vb2ynBlin0ySD8rO/cFEdA60yPYJ+04ObqzXmiojWOZ5ufGPj4URG9t\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<wall-of-people-groups profile-config='{\"profile\":\"wall-of-people-groups\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></wall-of-people-groups>"
},
"bundle": "wall-of-people-groups"
}

View file

@ -200,7 +200,7 @@
"bundle": "country-posters",
"scriptUrl": "./country-posters/country-posters.js",
"output": "dx-maps/country-posters/country-posters.js",
"integrity": "sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh",
"integrity": "sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0",
"elements": [
"country-posters-map"
],
@ -223,8 +223,8 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/countries-map/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=\"./country-posters/country-posters.js\" integrity=\"sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh\" 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<country-posters-map profile-config='{\"profile\":\"countries-map\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<country-posters-map profile-config='{\"profile\":\"countries-map\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0\" 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<country-posters-map profile-config='{\"profile\":\"countries-map\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<country-posters-map profile-config='{\"profile\":\"countries-map\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
},
{
@ -240,7 +240,7 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/country-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=\"./country-posters/country-posters.js\" integrity=\"sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<country-posters-map profile-config='{\"profile\":\"country-poster-wall\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<country-posters-map profile-config='{\"profile\":\"country-poster-wall\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
},
{
@ -256,8 +256,8 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh\" 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<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-HBTXhF44gVtdoLCfPwV5zIWNlyNtV0X96REAfMR5nub0wZ1KznB9LAJgLNWZ1tYh\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0\" 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<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-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=\"./country-posters/country-posters.js\" integrity=\"sha384-bMGgtFg/If1Fgbug2AbgpFSlAM44IvvNQewrfB30e8e+UqP/1yR4gVK4seN3LZz0\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
}
]
@ -1180,7 +1180,7 @@
"bundle": "regions-dashboard",
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"output": "dx-maps/regions-dashboard/regions-dashboard.js",
"integrity": "sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj",
"integrity": "sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx",
"elements": [
"regions-dashboard"
],
@ -1203,8 +1203,8 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/region-dashboards/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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj\" 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<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>",
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx\" 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<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>",
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
@ -1220,7 +1220,7 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/regions-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
@ -1236,8 +1236,8 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/regions-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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj\" 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<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>",
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx\" 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<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>",
"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=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
}
]
@ -1473,7 +1473,7 @@
"bundle": "wall-of-people-groups",
"scriptUrl": "./wall-of-people-groups/wall-of-people-groups.js",
"output": "dx-maps/wall-of-people-groups/wall-of-people-groups.js",
"integrity": "sha384-jXcu2Fpvms5zKTuyxRQ1oZG7jciYNwC1+KOpUYXMlm5u59l3SGJOLxN3vbXvt5c1",
"integrity": "sha384-S2g83dVn7Vb2ynBlin0ySD8rO/cFEdA60yPYJ+04ObqzXmiojWOZ5ufGPj4URG9t",
"elements": [
"wall-of-people-groups"
],
@ -1492,7 +1492,7 @@
"scriptUrl": "./wall-of-people-groups/wall-of-people-groups.js",
"embed": {
"iframe": "<iframe src=\"./wall-of-people-groups/wall-of-people-groups/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=\"./wall-of-people-groups/wall-of-people-groups.js\" integrity=\"sha384-jXcu2Fpvms5zKTuyxRQ1oZG7jciYNwC1+KOpUYXMlm5u59l3SGJOLxN3vbXvt5c1\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<wall-of-people-groups profile-config='{\"profile\":\"wall-of-people-groups\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></wall-of-people-groups>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./wall-of-people-groups/wall-of-people-groups.js\" integrity=\"sha384-S2g83dVn7Vb2ynBlin0ySD8rO/cFEdA60yPYJ+04ObqzXmiojWOZ5ufGPj4URG9t\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<wall-of-people-groups profile-config='{\"profile\":\"wall-of-people-groups\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></wall-of-people-groups>"
},
"bundle": "wall-of-people-groups"
}

View file

@ -76,7 +76,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <regions-dashboard> custom element. -->
<script src="../regions-dashboard.js" integrity="sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

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 <regions-dashboard> custom element. -->
<script src="../regions-dashboard.js" integrity="sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -77,7 +77,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <regions-dashboard> custom element. -->
<script src="../regions-dashboard.js" integrity="sha384-CbTFafR7IJutd4DhEHviJtmThroMMzAEude0SN9U3K0GWwhsL38ZFZyZ7EqX5yZj" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-ip4uMMacs2WBhvxncgJl309qFPWbkX2Zr3bKpXXNoMBPM2TILjTpNcd9x5IRrRFx" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

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 <wall-of-people-groups> custom element. -->
<script src="../wall-of-people-groups.js" integrity="sha384-jXcu2Fpvms5zKTuyxRQ1oZG7jciYNwC1+KOpUYXMlm5u59l3SGJOLxN3vbXvt5c1" crossorigin="anonymous"></script>
<script src="../wall-of-people-groups.js" integrity="sha384-S2g83dVn7Vb2ynBlin0ySD8rO/cFEdA60yPYJ+04ObqzXmiojWOZ5ufGPj4URG9t" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order: