Merge commit '1d8f5f1cc' into poster-design-plugin/experimental

This commit is contained in:
Doxa Maps 2026-10-03 05:07:33 +00:00
commit 8b30be2481
22 changed files with 325 additions and 674 deletions

View file

@ -57,7 +57,6 @@ Generated from 30 bundle(s).
| `poster-design` | `poster-sizes` | `single` |
| `poster-design` | `poster-styles` | `single` |
| `prayer-walk-planner` | `prayer-walk-planner` | `single` |
| `regions-dashboard` | `country-poster-sections` | `single` |
| `regions-dashboard` | `region-dashboards` | `single` |
| `regions-dashboard` | `regions-list` | `single` |

View file

@ -8,7 +8,7 @@
"neg": { "leaf": "regions-dashboard/regions-list/index.html", "text": "View country posters" },
"sanctioned": [
{
"match": "^(Select view|Regions List|Dashboard|Country Posters)$", "flags": "i",
"match": "^(Select view|Regions List|Dashboard)$", "flags": "i",
"what": "the SELECT VIEW tab strip — sanctioned addition #1",
"ruling": "the tabs added, and what the dashboard tab shows before a region or country is selected",
"date": "2026-09-24", "card": "SPEC-REGIONS-IS-A-CLONE-PLUS-EXACTLY-TWO-ADDITIONS"

View file

@ -92,12 +92,21 @@ const largeOf = (item) => (item && LARGE_SHEETS[String(item.iso3 || '').toUpperC
*/
// WHAT of a whole country is withheld: its POSTER, and/or its ROWS (its prayer list, packet and cards).
// India's whole-country poster is withheld EVERYWHERE BY DEFAULT (it is not released yet). It prints only in an
// explicit PREVIEW context: the Vite DEV server (the pilot's Plugin Studio, where it is reviewed), whose element
// bootstrap sets globalThis.DXM_PREVIEW_UNRELEASED. The read is gated on import.meta.env.DEV too, so every BUILT bundle
// compiles it away: no page, embed or console can set a global and print it from production. Never by a URL
// parameter. Its rows (about a thousand pages) stay withheld everywhere.
// explicit PREVIEW context, which needs ALL of:
// - the Vite DEV server (the pilot), whose element bootstrap sets globalThis.DXM_PREVIEW_UNRELEASED;
// - an explicit OPT-IN on that page: ?preview=india in its URL, or localStorage 'dxm-preview' containing 'india'.
// The pilot runs in dev mode, so dev mode alone must NOT show it (the pilot shows what the release shows).
// The whole read is gated on import.meta.env.DEV first, so every BUILT bundle compiles it away (the opt-in included):
// no page, URL, embed or console can print it from production. Its rows (about a thousand pages) stay withheld
// everywhere.
export const WITHHELD = { IND: { poster: true, rows: true, preview: true } }
export const previewUnreleased = () => Boolean(import.meta.env && import.meta.env.DEV && globalThis.DXM_PREVIEW_UNRELEASED === true)
export const PREVIEW_KEY = 'india'
export function previewOptedIn() {
const has = (v) => String(v || '').split(',').map((x) => x.trim()).includes(PREVIEW_KEY)
try { if (new URLSearchParams(globalThis.location?.search || '').getAll('preview').some(has)) return true } catch (_) { /* no URL */ }
try { return has(globalThis.localStorage?.getItem('dxm-preview')) } catch (_) { return false }
}
export const previewUnreleased = () => Boolean(import.meta.env && import.meta.env.DEV && globalThis.DXM_PREVIEW_UNRELEASED === true && previewOptedIn())
const withheldOf = (item) => (item && !item.indiaState && WITHHELD[String(item.iso3 || '').toUpperCase()]) || null
// No caller can open it: the preview state is read HERE, never passed in (so a built bundle cannot print it).
export function posterWithheld(item) { const w = withheldOf(item); return Boolean(w?.poster) && !(w.preview && previewUnreleased()) }

View file

@ -35,6 +35,7 @@ import { buildPaneColumn, PANE_GRID_STYLES } from '@map/layouts/pane-wrapper/pan
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
import ViewSelect from '@map/components/ViewSelect.vue'
import { countryName } from '@map/utils/countryName.js'
import { previewOptedIn } from '@map/packet/countrySheet.js'
import { getRuntimeLocale, detectLocale } from '@map/i18n/index.js'
import ShareButton from '@map/components/map-controls/ShareButton.vue'
import { useI18n } from 'vue-i18n'
@ -70,8 +71,9 @@ const spec = computed(() => ({
// strip desynchronises from the scroll column.
panes: [
{ id: 'wall', label: t('tabs.countryPosters'), at: [0, 0], config: { profile: 'country-poster-wall' } },
// the same DEV-gated read as countrySheet.js previewUnreleased(), INLINE so every build drops the pane entirely
...(import.meta.env && import.meta.env.DEV && globalThis.DXM_PREVIEW_UNRELEASED === true ? [INDIA_PANE] : []),
// the same DEV-gated read as countrySheet.js previewUnreleased() (dev server AND the explicit opt-in), INLINE so
// every build drops the pane entirely
...(import.meta.env && import.meta.env.DEV && globalThis.DXM_PREVIEW_UNRELEASED === true && previewOptedIn() ? [INDIA_PANE] : []),
{ id: 'map', label: t('tabs.map'), at: [2, 0], config: { profile: 'countries-map' } },
],
// The switcher lives in this element's own header, so the layout's "… below ↓"
@ -80,9 +82,10 @@ const spec = computed(() => ({
}))
// INDIA: the whole-India poster (66x66 by default) on its own tab, the same wall filtered to India, labelled with
// India's own name in the reader's language (Intl). Shown ONLY in a preview context (countrySheet.js
// previewUnreleased(): the Plugin Studio on the pilot), because the poster is not released; everywhere else the tab
// is absent and India's card keeps the withheld sentence.
// India's own name in the reader's language (Intl). Shown ONLY in an opted-in preview (countrySheet.js
// previewUnreleased(): the pilot's dev server AND ?preview=india or localStorage 'dxm-preview'), because the poster is
// not released; everywhere else (the pilot without the opt-in included) the tab is absent and India's card keeps the
// withheld sentence.
const INDIA_PANE = { id: 'india', label: countryName('IND', getRuntimeLocale() || detectLocale() || 'en') || 'India', at: [1, 0], config: { profile: 'country-poster-wall', countries: ['IND'] } }
const stage = ref(null)

View file

@ -221,7 +221,7 @@ export async function armG(cs, srcs, mfeSrc = '') {
if (!/rowsWithheld\((?:c|item)\) \? (?:withheld\(\)|Promise\.reject\(keyedError\('messages\.countryPosterTooMany')/.test(src)) fails.push(`${name}: withheld ROWS are not withheld (its list/packet/cards would print)`)
if (/sheetWithheld\(/.test(src)) fails.push(`${name}: still reads sheetWithheld() (ambiguous: poster or rows?)`)
}
if (mfeSrc && !/\.\.\.\(import\.meta\.env && import\.meta\.env\.DEV && globalThis\.DXM_PREVIEW_UNRELEASED === true \? \[INDIA_PANE\] : \[\]\)/.test(mfeSrc)) fails.push('country-posters-mfe: the India tab is not gated on the DEV-only preview read')
if (mfeSrc && !/\.\.\.\(import\.meta\.env && import\.meta\.env\.DEV && globalThis\.DXM_PREVIEW_UNRELEASED === true && previewOptedIn\(\) \? \[INDIA_PANE\] : \[\]\)/.test(mfeSrc)) fails.push('country-posters-mfe: the India tab is not gated on the DEV-only preview read AND the explicit opt-in (previewOptedIn())')
// the BUILT tree never mentions the flag (every read is compiled away)
try {
const pub = join(ROOT, 'public/dx-maps')
@ -298,7 +298,8 @@ async function main() {
['an opener argument comes back', async () => armG({ ...CS, posterWithheld: (it, open) => CS.posterWithheld(it) }, lists(files[wall]), MFE)],
['the preview read without DEV (a global opens production)', async () => armG({ ...CS, previewUnreleased: () => globalThis.DXM_PREVIEW_UNRELEASED === true }, lists(files[wall]), MFE)],
['India\'s rows un-withheld', async () => armG({ ...CS, rowsWithheld: () => false }, lists(files[wall]), MFE)],
['the India tab shown without the preview flag', async () => armG(CS, lists(files[wall]), MFE.replace('...(import.meta.env && import.meta.env.DEV && globalThis.DXM_PREVIEW_UNRELEASED === true ? [INDIA_PANE] : []),', 'INDIA_PANE,'))],
['the India tab shown without the preview flag', async () => armG(CS, lists(files[wall]), MFE.replace('...(import.meta.env && import.meta.env.DEV && globalThis.DXM_PREVIEW_UNRELEASED === true && previewOptedIn() ? [INDIA_PANE] : []),', 'INDIA_PANE,'))],
['the India tab shown on the pilot by dev mode alone', async () => armG(CS, lists(files[wall]), MFE.replace(' && previewOptedIn() ? [INDIA_PANE]', ' ? [INDIA_PANE]'))],
['the wall prints the list of a country whose rows are withheld', async () => armG(CS, lists(files[wall].replace('rowsWithheld(c) ? withheld() : ', '')))],
['the library type prints withheld rows', () => armH(TYPE.replace('rowsWithheld(c) ? ', 'false ? '))],
['the library type shows a withheld poster', () => armH(TYPE.replace('posterWithheld(c) ||', 'false ||'))],

View file

@ -51,17 +51,31 @@ async function arms({ types, country, element, sectionSrc, viewSrc, cs }) {
if (!/countryPosterTooMany/.test(String(why))) fails.push(`C: withheld India's rows are not withheld (${why})`)
if (fetched) fails.push('C: withheld India fetched records')
}
// C2. THE PREVIEW, under Vite (import.meta.env.DEV is true here, as on the pilot's dev server): only with the global
// set does India's whole-country poster open, at 60x96; its rows stay withheld; without it, withheld.
// C2. THE PREVIEW, under Vite (import.meta.env.DEV is true here, as on the pilot's dev server): DEV MODE ALONE (the
// global set by the dev bootstrap) does NOT open India: the pilot shows what the release shows. Only with the
// explicit opt-in too (?preview=india, or localStorage 'dxm-preview') does the poster open, at 60x96; its rows
// stay withheld; without the global, withheld.
const was = globalThis.DXM_PREVIEW_UNRELEASED
const loc = Object.getOwnPropertyDescriptor(globalThis, 'location'), ls = Object.getOwnPropertyDescriptor(globalThis, 'localStorage')
const setLoc = (search) => Object.defineProperty(globalThis, 'location', { value: { search }, configurable: true, writable: true })
const setLs = (v) => Object.defineProperty(globalThis, 'localStorage', { value: { getItem: (k) => (k === 'dxm-preview' ? v : null) }, configurable: true, writable: true })
try {
globalThis.DXM_PREVIEW_UNRELEASED = true
setLoc(''); setLs(null)
if (!cs.posterWithheld({ iso3: 'IND' }) || cs.largeSheet({ iso3: 'IND' })) fails.push('C2: dev mode ALONE (no opt-in) opens India: the pilot would show the withheld poster')
setLs('india')
if (cs.posterWithheld({ iso3: 'IND' })) fails.push("C2: localStorage 'dxm-preview'='india' does not open the preview")
setLs(null); setLoc('?lang=en&preview=india')
const big = cs.largeSheet({ iso3: 'IND' })
if (cs.posterWithheld({ iso3: 'IND' }) || !big || big.format !== '60x96') fails.push(`C2: in a DEV preview India's poster does not open at 60x96 (${big && big.format})`)
if (!cs.rowsWithheld({ iso3: 'IND' })) fails.push("C2: the preview also released India's rows")
delete globalThis.DXM_PREVIEW_UNRELEASED
if (!cs.posterWithheld({ iso3: 'IND' })) fails.push('C2: without the preview global India is not withheld')
} finally { if (was === undefined) delete globalThis.DXM_PREVIEW_UNRELEASED; else globalThis.DXM_PREVIEW_UNRELEASED = was }
} finally {
if (was === undefined) delete globalThis.DXM_PREVIEW_UNRELEASED; else globalThis.DXM_PREVIEW_UNRELEASED = was
if (loc) Object.defineProperty(globalThis, 'location', loc); else delete globalThis.location
if (ls) Object.defineProperty(globalThis, 'localStorage', ls); else delete globalThis.localStorage
}
// D
const fake = (attrs) => ({ getAttribute: (n) => (n in attrs ? attrs[n] : null), hasAttribute: (n) => n in attrs })
const d0 = element.posterSectionConfig(fake({ scope: 'africa' }))
@ -121,6 +135,7 @@ try {
["a registry without 'country'", { ...real, types: { ...types, posterTypeNames: () => [] } }, /^A:/],
['a region key without "&" → "and"', { ...real, country: { ...country, items: (s, l) => (/-and-/.test(String(s)) ? [] : country.items(s, l)) } }, /^B:/],
['the preview ignored under DEV', { ...real, cs: { ...cs, posterWithheld: () => true, largeSheet: () => null } }, /^C2:/],
['dev mode alone opens India (no opt-in)', { ...real, cs: { ...cs, posterWithheld: () => false, largeSheet: () => ({ format: '60x96', formats: ['60x96'] }) } }, /^C2: dev mode ALONE/],
['a section that uses a name it does not inject', { ...real, sectionSrc: sectionSrc.replace('</template>', '{{ notProvided }}</template>') }, /^E:/],
['an element config that drops show-header', { ...real, element: { posterSectionConfig: (el) => { const c = element.posterSectionConfig(el); delete c.showHeader; return c } } }, /^D: show-header="false"/],
['a view that does not pass show-header to the wall', { ...real, viewSrc: viewSrc.replace(':section-heads="showHeader"', '') }, /^F:/],

View file

@ -1,5 +0,0 @@
{
"type": "single",
"label": "Regions — country posters by region",
"note": "The Regions dashboard's third view: one collapsible <dxm-poster-section type=\"country\"> per region (the library's element, the same cards and print options as the Country Posters wall), starting shut, in the page's locale. The regions are the ones the poster data files its countries under, in the dashboard's region order."
}

View file

@ -1,66 +0,0 @@
<script setup>
/**
* @description Country posters by region: one collapsible poster section per region (the library's <dxm-poster-section>), the Regions dashboard's third view.
*
* country-poster-sections.vue — the Regions dashboard's THIRD view, "Country Posters", beside the regions list and the
* region dashboards. One <dxm-poster-section type="country"> per region, collapsible and starting shut, in the page's
* locale.
*
* ★ THE ELEMENT IS THE LIBRARY'S (library/elements/posterSectionElement.js): the same section, cards and print options as
* the Country Posters wall. This bundle only registers it (a second registration on one page is a no-op) and places it.
*
* ★ THE SECTIONS ARE THE REGIONS THE POSTERS ARE FILED UNDER. The country type groups its cards by the poster data's own
* region (library/data/country-posters.json), so the list of sections comes from that same data, in the dashboard's
* fixed region order (REGION_ORDER). That way every country with a poster lands in exactly one section; a country the
* data files under no WAGF region gets the type's "Other" section instead of disappearing. The scope keys go through
* the type's own regionKey, so this page and the element can never spell a region two ways.
*/
import { computed, h, inject, ref } from 'vue'
import { registerPosterSectionElement } from '@map/elements/posterSectionElement.js'
import { regionKey } from '@map/components/poster/types/countryPosterType.js'
import posterData from '@map/data/country-posters.json'
import { REGION_ORDER } from '@map/colors/wagf-region.js'
import { resolveAssetsBase } from '@map/utils/embedBase.js'
import { getRuntimeLocale, detectLocale } from '@map/i18n/index.js'
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
registerPosterSectionElement()
const profileConfig = inject('profileConfig', ref(null))
const cfg = computed(() => profileConfig.value || {})
const locale = computed(() => cfg.value.locale || cfg.value.lang || cfg.value.languageCode || getRuntimeLocale() || detectLocale() || 'en')
// The people-groups service the Regions list prints from (regions-list.vue's prayBaseUrl), so a section's prayer list
// and cards come from the same records as the list's own country posters.
const apiBase = computed(() => cfg.value.prayBaseUrl || cfg.value.apiBaseUrl || 'https://pray.doxa.life')
const scopes = computed(() => {
const inData = new Set((posterData.countries || []).map((c) => regionKey(c.region)))
const ordered = REGION_ORDER.map(regionKey).filter((k) => inData.has(k))
return [...ordered, ...[...inData].filter((k) => !ordered.includes(k)).sort()]
})
const section = (scope) => h('dxm-poster-section', {
key: scope,
type: 'country',
scope,
locale: locale.value,
collapsed: '',
'assets-base': resolveAssetsBase(cfg.value),
'api-base-url': apiBase.value,
...(cfg.value.isDark === true ? { 'is-dark': '' } : {}),
})
const Page = () => h('div', { class: 'cps' }, h('div', { class: 'cps__inner' }, scopes.value.map(section)))
useShadowStyles(
// The pane gives this element its whole box; the page scrolls here, and the sections stack in it.
':host{ display:block; height:100%; }' +
'.cps{ height:100%; overflow-y:auto; -webkit-overflow-scrolling:touch; box-sizing:border-box; padding:16px 12px 32px; }' +
'.cps__inner{ max-width:1180px; margin:0 auto; display:flex; flex-direction:column; gap:12px; }' +
'.cps__inner > *{ display:block; }',
'country-poster-sections'
)
</script>
<template>
<Page />
</template>

View file

@ -61,8 +61,8 @@ import { DXLIFE_TOKENS } from './dxlife-tokens.js'
//
// NOTHING HERE IS REBUILT. Each region's posters are the library's <dxm-poster-section type="country">
// (library/elements/posterSectionElement.js), the same section, cards and print options as the Country Posters
// wall and the Regions dashboard's third view, so the list is composed from the shared element rather than
// drawing a wall of its own. This file supplies only the toggle and the region.
// wall, so the list is composed from the shared element rather than drawing a wall of its own. This file supplies
// only the toggle and the region.
import RegionSectionCard from '@map/components/regions/RegionSectionCard.vue'
import { resolveAssetsBase } from '@map/utils/embedBase.js'
import { registerPosterSectionElement } from '@map/elements/posterSectionElement.js'
@ -309,9 +309,8 @@ const postersOpen = (region) => openPosters.value.has(region.slug)
// the country record and reusing selectCountry() is what makes the button open the dashboard
// tab for that country: the requirement is that the view-on-map button opens the country
// dashboard page for that country.
// The library's poster sections name themselves 'poster-section-country-<region>' (PosterSectionView.vue). In the
// Regions composite this list is always mounted, so it also answers the third view's sections (Country Posters):
// ONE handler for both, which keeps the region context in the selection.
// The library's poster sections name themselves 'poster-section-country-<region>' (PosterSectionView.vue); selecting
// through selectCountry() keeps the region context in the selection.
function onPosterShowOnMap(ev) {
const d = ev?.detail || {}
if (!String(d.instanceId || '').startsWith('poster-section-country-')) return

View file

@ -24,7 +24,7 @@
* listens for, and scrolls to tab 2. That is the same seam upg-100-mfe uses for the poster
* wall's 'show-on-map', and it keeps each pane under its own ProfileLoader/Pinia.
*/
import { ref, computed, inject, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
import { ref, computed, inject, onMounted, onBeforeUnmount } from 'vue'
import { usePaneConfig } from '@map/composables/usePaneConfig.js'
import { buildPaneColumn, PANE_GRID_STYLES } from '@map/layouts/pane-wrapper/pane-wrapper.js'
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
@ -47,11 +47,8 @@ import MapInfoButton from '@map/components/map-controls/MapInfoButton.vue'
// them to 97 and fail the gate. The moment someone adds these three strings to all locales,
// the strip localises with no code change here.
import { useRegionsI18n } from '@map/i18n/useRegionsI18n.js'
// The third view's label is the gallery's own tab name for country posters (tabs.countryPosters, all eleven locales).
import { useOptionalT } from '@map/composables/useOptionalT.js'
const { t } = useRegionsI18n()
const tKey = useOptionalT('')
const cfg = inject('profileConfig', ref(null))
const uiStore = inject('uiStore', null)
const isDark = computed(() => !!uiStore?.isDark)
@ -73,8 +70,6 @@ const spec = computed(() => ({
panes: [
{ id: 'list', label: t('Regions List'), at: [0, 0], config: { profile: 'regions-list' } },
{ id: 'dashboard', label: t('Region Dashboards'), at: [1, 0], config: { profile: 'region-dashboards' } },
// THE THIRD VIEW: country posters, one collapsible section per region (the library's <dxm-poster-section>).
{ id: 'posters', label: tKey('tabs.countryPosters'), at: [2, 0], config: { profile: 'country-poster-sections' } },
],
// The View switcher lives in this element's own header, so the layout's "… below ↓" pill
// would be a second, redundant control (same call upg-100-mfe makes).
@ -151,13 +146,6 @@ function go(id) {
column?.scrollTo(id)
}
// On a phone the three tabs scroll sideways (see the 600px rule below): keep the current one in view.
const hdr = ref(null)
watch(view, () => nextTick(() => {
const b = hdr.value && hdr.value.querySelector('.seg button[aria-pressed="true"]')
if (b && b.scrollIntoView) b.scrollIntoView({ inline: 'center', block: 'nearest' })
}))
// ── tab 1 -> tab 2: forward the selection, then swap the visible pane ───────
const SELECT_EVENT = 'doxa-regions-dashboard:select'
@ -181,10 +169,6 @@ function onCountrySelected(e) {
forwardSelection({ regionSlug: d.region?.slug || '', countrySlug: d.slug || '' })
}
// A card's "Show on map" in the third view (Country Posters) opens that country's dashboard: the Regions list pane
// (always mounted here) answers every poster section's event with its own selectCountry(), which arrives above as
// 'country-selected'. One handler for both views (regions-list.vue onPosterShowOnMap).
onMounted(() => {
if (!stage.value) return
column = buildPaneColumn(spec.value, { host: stage.value })
@ -250,14 +234,6 @@ useShadowStyles(SHADOW_BOX_SIZING_RESET + PANE_GRID_STYLES + '\n' +
// ON A PHONE the centred view switcher (about 290 px at 390) leaves no room for two buttons at one end, so the
// ⓘ takes the header's START edge, where the floating ⓘ sat before; Share keeps the end.
'@media (max-width: 600px){ .rmfe .hdr .hdr-btns > :first-child{ position:absolute; inset-inline-start:12px; top:50%; transform:translateY(-50%); } }' +
// THREE VIEWS DO NOT FIT A PHONE'S HEADER (measured at 390: the tabs need about 390 px and ran under the corner
// buttons). The switcher keeps the room between the two 36 px buttons (12 + 36 + 8 on each side) and its tab row
// scrolls sideways, every label whole; the current tab is scrolled into view on each change. A fieldset is
// min-content wide by default, hence min-width:0. Desktop is unchanged.
'@media (max-width: 600px){ .rmfe .hdr .viewsel{ min-width:0; max-width:calc(100% - 112px); }' +
' .rmfe .hdr .viewsel .seg{ overflow-x:auto; scrollbar-width:none; scroll-snap-type:x proximity; -webkit-overflow-scrolling:touch; }' +
' .rmfe .hdr .viewsel .seg::-webkit-scrollbar{ display:none; }' +
' .rmfe .hdr .viewsel .seg button{ flex:0 0 auto; scroll-snap-align:center; } }' +
// Stage: the pane-wrapper column mounts here (its .pane-col is absolute).
'.rmfe .stage{ position:relative; flex:1 1 auto; min-height:0; }' +
'.pane > .pane-mount > *{ position:absolute; inset:0; width:100%; height:100%; display:block; }',
@ -267,7 +243,7 @@ useShadowStyles(SHADOW_BOX_SIZING_RESET + PANE_GRID_STYLES + '\n' +
<template>
<div class="rmfe">
<header ref="hdr" class="hdr">
<header class="hdr">
<ViewSelect
:views="spec.panes"
:current="view"

View file

@ -2,7 +2,7 @@
This folder is GENERATED by `bun run build`; do not edit it by hand. It holds exactly one thing:
- **`dx-maps/`** — the output folder: 30 plugin bundles and 46 pages, self-contained.
- **`dx-maps/`** — the output folder: 30 plugin bundles and 45 pages, self-contained.
Copy this one folder to any web host (or open it from disk) and it works.
- `dx-maps/index.html` — the front page: the Plugin Studio, every plugin in one place.
- `dx-maps/<plugin>/<plugin>.js` — a plugin's bundle (a custom element; load it with a `<script>` tag).

View file

@ -3,7 +3,7 @@
"generatedFrom": "plugin-designs/*/*.vue",
"embedBase": ".",
"bundleCount": 30,
"profileCount": 46,
"profileCount": 45,
"runtime": {
"apiBaseUrl": "https://pray.doxa.life"
},
@ -1277,7 +1277,7 @@
"bundle": "poster-design",
"scriptUrl": "./poster-design/poster-design.js",
"output": "dx-maps/poster-design/poster-design.js",
"integrity": "sha384-8ma38d8X5WOwsDXKjPFFx8Edr7w6bDsrLjYQIf/m6zCu9VWO2uogLYWqDbaEIjj7",
"integrity": "sha384-hiRS9PFXm3IHABow+MMmBh4VYVldRxUQSnx7b8wh3H1UW4N+Dq22fTV/oWGGvSP8",
"elements": [
"poster-design"
],
@ -1300,7 +1300,7 @@
"scriptUrl": "./poster-design/poster-design.js",
"embed": {
"iframe": "<iframe src=\"./poster-design/poster-design-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./poster-design/poster-design.js\" integrity=\"sha384-8ma38d8X5WOwsDXKjPFFx8Edr7w6bDsrLjYQIf/m6zCu9VWO2uogLYWqDbaEIjj7\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-design-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./poster-design/poster-design.js\" integrity=\"sha384-hiRS9PFXm3IHABow+MMmBh4VYVldRxUQSnx7b8wh3H1UW4N+Dq22fTV/oWGGvSP8\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-design-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
}
},
{
@ -1316,7 +1316,7 @@
"scriptUrl": "./poster-design/poster-design.js",
"embed": {
"iframe": "<iframe src=\"./poster-design/poster-sizes/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=\"./poster-design/poster-design.js\" integrity=\"sha384-8ma38d8X5WOwsDXKjPFFx8Edr7w6bDsrLjYQIf/m6zCu9VWO2uogLYWqDbaEIjj7\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-sizes\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./poster-design/poster-design.js\" integrity=\"sha384-hiRS9PFXm3IHABow+MMmBh4VYVldRxUQSnx7b8wh3H1UW4N+Dq22fTV/oWGGvSP8\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-sizes\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
}
},
{
@ -1332,7 +1332,7 @@
"scriptUrl": "./poster-design/poster-design.js",
"embed": {
"iframe": "<iframe src=\"./poster-design/poster-styles/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=\"./poster-design/poster-design.js\" integrity=\"sha384-8ma38d8X5WOwsDXKjPFFx8Edr7w6bDsrLjYQIf/m6zCu9VWO2uogLYWqDbaEIjj7\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-styles\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./poster-design/poster-design.js\" integrity=\"sha384-hiRS9PFXm3IHABow+MMmBh4VYVldRxUQSnx7b8wh3H1UW4N+Dq22fTV/oWGGvSP8\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-styles\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
}
}
]
@ -1617,7 +1617,7 @@
"bundle": "regions-dashboard",
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"output": "dx-maps/regions-dashboard/regions-dashboard.js",
"integrity": "sha384-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v",
"integrity": "sha384-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww",
"elements": [
"regions-dashboard"
],
@ -1627,22 +1627,6 @@
],
"stage": "production",
"profiles": [
{
"profile": "country-poster-sections",
"stage": "experimental",
"label": "Regions — country posters by region",
"file": "country-poster-sections.vue",
"description": "Country posters by region: one collapsible poster section per region (the library's <dxm-poster-section>), the Regions dashboard's third view.",
"element": "regions-dashboard",
"type": "single",
"isMap": false,
"iframeUrl": "./regions-dashboard/country-poster-sections/index.html",
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/country-poster-sections/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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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\":\"country-poster-sections\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
"profile": "region-dashboards",
"stage": "experimental",
@ -1656,8 +1640,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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww\" 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-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww\" 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>"
}
},
{
@ -1673,7 +1657,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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww\" 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>"
}
},
{
@ -1689,8 +1673,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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww\" 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-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww\" 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>"
}
}
]

View file

@ -3,7 +3,7 @@
"generatedFrom": "plugin-designs/*/*.vue",
"embedBase": ".",
"bundleCount": 30,
"profileCount": 46,
"profileCount": 45,
"runtime": {
"apiBaseUrl": "https://pray.doxa.life"
},
@ -1277,7 +1277,7 @@
"bundle": "poster-design",
"scriptUrl": "./poster-design/poster-design.js",
"output": "dx-maps/poster-design/poster-design.js",
"integrity": "sha384-8ma38d8X5WOwsDXKjPFFx8Edr7w6bDsrLjYQIf/m6zCu9VWO2uogLYWqDbaEIjj7",
"integrity": "sha384-hiRS9PFXm3IHABow+MMmBh4VYVldRxUQSnx7b8wh3H1UW4N+Dq22fTV/oWGGvSP8",
"elements": [
"poster-design"
],
@ -1300,7 +1300,7 @@
"scriptUrl": "./poster-design/poster-design.js",
"embed": {
"iframe": "<iframe src=\"./poster-design/poster-design-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./poster-design/poster-design.js\" integrity=\"sha384-8ma38d8X5WOwsDXKjPFFx8Edr7w6bDsrLjYQIf/m6zCu9VWO2uogLYWqDbaEIjj7\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-design-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./poster-design/poster-design.js\" integrity=\"sha384-hiRS9PFXm3IHABow+MMmBh4VYVldRxUQSnx7b8wh3H1UW4N+Dq22fTV/oWGGvSP8\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-design-mfe\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
}
},
{
@ -1316,7 +1316,7 @@
"scriptUrl": "./poster-design/poster-design.js",
"embed": {
"iframe": "<iframe src=\"./poster-design/poster-sizes/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=\"./poster-design/poster-design.js\" integrity=\"sha384-8ma38d8X5WOwsDXKjPFFx8Edr7w6bDsrLjYQIf/m6zCu9VWO2uogLYWqDbaEIjj7\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-sizes\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./poster-design/poster-design.js\" integrity=\"sha384-hiRS9PFXm3IHABow+MMmBh4VYVldRxUQSnx7b8wh3H1UW4N+Dq22fTV/oWGGvSP8\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-sizes\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
}
},
{
@ -1332,7 +1332,7 @@
"scriptUrl": "./poster-design/poster-design.js",
"embed": {
"iframe": "<iframe src=\"./poster-design/poster-styles/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=\"./poster-design/poster-design.js\" integrity=\"sha384-8ma38d8X5WOwsDXKjPFFx8Edr7w6bDsrLjYQIf/m6zCu9VWO2uogLYWqDbaEIjj7\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-styles\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./poster-design/poster-design.js\" integrity=\"sha384-hiRS9PFXm3IHABow+MMmBh4VYVldRxUQSnx7b8wh3H1UW4N+Dq22fTV/oWGGvSP8\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<poster-design profile-config='{\"profile\":\"poster-styles\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></poster-design>"
}
}
]
@ -1617,7 +1617,7 @@
"bundle": "regions-dashboard",
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"output": "dx-maps/regions-dashboard/regions-dashboard.js",
"integrity": "sha384-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v",
"integrity": "sha384-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww",
"elements": [
"regions-dashboard"
],
@ -1627,22 +1627,6 @@
],
"stage": "production",
"profiles": [
{
"profile": "country-poster-sections",
"stage": "experimental",
"label": "Regions — country posters by region",
"file": "country-poster-sections.vue",
"description": "Country posters by region: one collapsible poster section per region (the library's <dxm-poster-section>), the Regions dashboard's third view.",
"element": "regions-dashboard",
"type": "single",
"isMap": false,
"iframeUrl": "./regions-dashboard/country-poster-sections/index.html",
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/country-poster-sections/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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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\":\"country-poster-sections\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
"profile": "region-dashboards",
"stage": "experimental",
@ -1656,8 +1640,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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww\" 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-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww\" 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>"
}
},
{
@ -1673,7 +1657,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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww\" 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>"
}
},
{
@ -1689,8 +1673,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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v\" 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-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww\" 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-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww\" 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>"
}
}
]

View file

@ -73,7 +73,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <poster-design> custom element. -->
<script src="../poster-design.js" integrity="sha384-8ma38d8X5WOwsDXKjPFFx8Edr7w6bDsrLjYQIf/m6zCu9VWO2uogLYWqDbaEIjj7" crossorigin="anonymous"></script>
<script src="../poster-design.js" integrity="sha384-hiRS9PFXm3IHABow+MMmBh4VYVldRxUQSnx7b8wh3H1UW4N+Dq22fTV/oWGGvSP8" 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 <poster-design> custom element. -->
<script src="../poster-design.js" integrity="sha384-8ma38d8X5WOwsDXKjPFFx8Edr7w6bDsrLjYQIf/m6zCu9VWO2uogLYWqDbaEIjj7" crossorigin="anonymous"></script>
<script src="../poster-design.js" integrity="sha384-hiRS9PFXm3IHABow+MMmBh4VYVldRxUQSnx7b8wh3H1UW4N+Dq22fTV/oWGGvSP8" 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 <poster-design> custom element. -->
<script src="../poster-design.js" integrity="sha384-8ma38d8X5WOwsDXKjPFFx8Edr7w6bDsrLjYQIf/m6zCu9VWO2uogLYWqDbaEIjj7" crossorigin="anonymous"></script>
<script src="../poster-design.js" integrity="sha384-hiRS9PFXm3IHABow+MMmBh4VYVldRxUQSnx7b8wh3H1UW4N+Dq22fTV/oWGGvSP8" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -1,250 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- THIS PAGE IS OURS. The only thing that knows a document belongs to the plugin is the page
the generator writes, so it says so here. library/i18n reads it before reflecting an RTL
locale on <html dir>; nothing else sets it, so a PARTNER page defaults to "not ours" and
is never touched. Absence must mean restraint — an embedded plugin flipping a partner's
whole <html> because a reader followed a ?lang=ar link is the bug this prevents. -->
<script>window.MAP_OWNS_PAGE = true;</script>
<title>country-poster-sections · regions-dashboard</title>
<link rel="icon" href="data:,">
<!-- NON-MAP leaf (app-shell / composite / grid / card / chart-table): NO map peer.
This element draws no map tiles, so it needs no Mapbox/MapLibre engine and MUST NOT
gate on a token. Any nested MAP (in a composite/shell) renders in its own iframe leaf,
which loads its own map peer + token. A peer here would be dead weight + imply a gate. -->
<style>
/* BARE full-page map — no chrome. The custom element IS the page, so the
browser URL shares the map itself.
HEIGHT IN svh, NOT inset:0. A fixed box with inset:0 follows the phone's DYNAMIC viewport, so the map
(and a legend sheet sized from it) changes height every time the address bar hides or shows. 100svh is
the viewport WITH the bar shown and never changes; when the bar hides, the page background shows below
instead of the map resizing. On a desktop svh = the viewport, so nothing moves there. The 100% before it
is the fallback for a browser without svh, which would otherwise size the box to its content.
--profile-min-h:0 opts out of ProfileLoader's 100dvh floor, which would grow the element again. */
html, body { height: 100%; margin: 0; background: #0a0e15; }
#slot, regions-dashboard { position: fixed; inset: 0 auto auto 0; width: 100%; height: 100%; height: 100svh; --profile-min-h: 0; display: block; }
#status { position: fixed; inset: 0; z-index: 2; display: grid; place-items: center;
padding: 24px; text-align: center; color: #9aa7b8;
font: 13px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace; }
#status.err { color: #f87171; }
/* ── PRINT, BOTH LEAF SHAPES ────────────────────────────────────────────────────────────
Two things every generated leaf got wrong on paper, because no generated page has ever
carried an @media print rule (measured: 0 across the tree).
The background is #0a0e15 — a dark page, printed. Browsers drop background colours by
default, but a reader who ticks "Background graphics" to get the MAP also gets the page
flooded black, and that is the reader who most wants the printout.
#status is the LOADING OVERLAY: position:fixed, inset:0, over everything. On paper it is
a full sheet reading "loading…" above the content that did in fact load. It is hidden
only while it is NOT an error — an error still prints, because a blank sheet with the
explanation suppressed is worse than a sheet that says what went wrong. */
@media print {
html, body { height: auto; background: #fff; }
#status:not(.err) { display: none; }
/* ★ RELEASE THE FIXED HOST, MEASURED (a print check on a035408e2). The leaf pins both the
slot and the element with position:fixed; inset:0. A fixed element is painted once, on the
first page, so the printed document was exactly ONE viewport: 900px tall, while the content
continued to y=1753. Every plugin whose leaf is taller than a screen has been printing its
top screenful and silently dropping the rest — the dashboard printed its stats and its map,
then blank to the bottom of the sheet.
min-height, not a released height alone: a full-bleed map leaf takes its SIZE from this rule,
so height:auto with nothing else can leave the element a zero-height box and print an empty
page — a worse failure than the one being fixed, and the discriminator is not isMap
(region-dashboards is isMap:true and is a scrolling dashboard). The floor keeps a definite
box for the map case while letting a taller document grow onto page two. */
#slot, regions-dashboard { position: static; inset: auto; width: 100%; height: auto; min-height: 14cm; }
}
</style>
</head>
<body>
<div id="slot"></div>
<div id="status">loading…</div>
<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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
// 1. prop — a token hardcoded into this page's profile-config (config.tk)
// 2. ?tk= URL param — token carried in the shared link
// 3. baked token — opt-in literal token inlined at build time (build-config.token)
// A token from rungs 1-3 is used DIRECTLY (no network). Otherwise a token
// *endpoint* is resolved and fetched:
// 4. window.MAP_TOKEN_URL override 5. configured TOKEN_SRC URL 6. same-origin /api/maps/token
// TOKEN_SRC is treated as DATA, never eval'd: the literal "window.MAP_TOKEN_URL"
// means "read that global"; anything else is used as a URL — so both a global
// name and a plain URL are safe (no SyntaxError footgun).
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"country-poster-sections","dataSource":"pray-tools","instanceId":"regions-dashboard-country-poster-sections","assetsBase":"../../assets"};
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)
var TOKEN_FREE = true;
// A token-free COMPOSITE still nests plugins, and a nested Mapbox map reads window.MAP_TOKEN
// rather than this page's profile-config. With no baked token (the public copy), it must get
// one from ?tk= or a pasted token, or be asked for one — see the rungs below.
var NESTS_MAPS = false;
var TOKEN_SRC = "window.MAP_TOKEN_URL";
var BAKED_TOKEN = "";
// Expose the baked token as window.MAP_TOKEN so a BAKED composite (a compiled element that mounts
// a map component directly, with no ProfileLoader/profile-config wrapper) still finds a token —
// useMapInstance falls back to window.MAP_TOKEN. No effect when BAKED_TOKEN is empty.
// A token the HOST set before this page ran outranks the baked one (measured: it used to lose).
var HOST_TOKEN = (typeof window.MAP_TOKEN === 'string' && window.MAP_TOKEN) || '';
if (BAKED_TOKEN && typeof window !== 'undefined' && !window.MAP_TOKEN) { window.MAP_TOKEN = BAKED_TOKEN; }
var DEFAULT_TOKEN_URL = '/api/maps/token';
function fail(msg) { if (status) { status.className = 'err'; status.textContent = '⚠ ' + msg; } }
// No token anywhere on the ladder → ask ONCE, store locally, remount. No dead ends.
function askToken() {
if (!status) return;
status.className = 'err';
status.innerHTML = 'map needs a Mapbox token — ' +
'<input id="tkIn" type="password" placeholder="paste pk.… (stays in this browser)" ' +
'style="font:12px ui-monospace,monospace;padding:6px 8px;border-radius:6px;border:1px solid #223047;background:#0e1623;color:#eef2f7;width:min(320px,70vw)"> ' +
'<button id="tkGo" style="font:700 11px ui-monospace,monospace;padding:7px 12px;border-radius:999px;border:0;cursor:pointer;background:linear-gradient(90deg,#46d4ff,#b9a6f5);color:#0a0e15">use it</button>';
var go = document.getElementById('tkGo');
if (go) go.addEventListener('click', function () {
var v = (document.getElementById('tkIn').value || '').trim();
if (!v) return;
try { localStorage.setItem('MAPS_STAGING_TK', v); } catch (e) {}
mount(v);
});
}
/* ★ RELEASE THE LOAD BACKDROP WHEN THE ELEMENT MOUNTS (BUG-GOSPEL-MAP-BLACK-RECTANGLE).
html/body carry background:#0a0e15 so the light #status text (#9aa7b8) is readable while the
bundle loads. That backdrop is LOAD-STATE CHROME, but it outlived its moment: any gap the
mounted element does not cover shows it through, because every layer above body is
transparent. On gospel-resources/resources-map that produced a 352x126 DARK RECTANGLE between
the legend card and the detail panel — MEASURED rgb(8,12,18), i.e. the page background, NOT an
unpainted canvas as first supposed. Clearing it here (the one place we already know the
element is up) is a one-shot style write — no resize, no repaint loop. Keep it a one-shot
write: do NOT turn this into a per-frame or per-event handler (a resize loop strobes the screen). */
function done() {
if (status && status.parentNode) { status.parentNode.removeChild(status); }
document.documentElement.style.background = '#f3f3f1';
document.body.style.background = '#f3f3f1';
}
function mount(token) {
if (!token && !TOKEN_FREE) { return askToken(); }
// Nested maps (a composite's children) read window.MAP_TOKEN, not this element's config.
if (token && typeof window !== 'undefined' && !window.MAP_TOKEN) { window.MAP_TOKEN = token; }
try {
var cfg = token ? Object.assign({}, BASE_CONFIG, { tk: token }) : BASE_CONFIG;
var el = document.createElement("regions-dashboard");
el.setAttribute('profile-config', JSON.stringify(cfg));
slot.innerHTML = '';
slot.appendChild(el);
done();
} catch (e) { fail(e && e.message ? e.message : String(e)); }
}
function qp(name) {
try { return new URLSearchParams(location.search).get(name) || ''; }
catch (e) { return ''; }
}
function extractToken(data) {
if (typeof data === 'string') return data.trim();
if (data && typeof data === 'object') return data.token || data.tk || data.accessToken || '';
return '';
}
// Rungs 1-3b: an actual token → mount directly, no fetch.
// 2b = localStorage: the paste-once store shared with the staging pages
// (MAPS_STAGING_TK) — paste a token ONCE anywhere in the tree, every page uses it.
var stored = '';
try { stored = localStorage.getItem('MAPS_STAGING_TK') || ''; } catch (e) {}
var urlTk = qp('tk');
if (urlTk) { try { localStorage.setItem('MAPS_STAGING_TK', urlTk); } catch (e) {} }
var directToken = (BASE_CONFIG && BASE_CONFIG.tk) || urlTk || stored || HOST_TOKEN || BAKED_TOKEN;
// PROVIDER — the same ladder as resolveMapProvider (library/composables/useMapProvider.js):
// profile-config.provider → ?provider= → window.MAP_PROVIDER → 'auto'. An explicit engine wins,
// and 'auto' draws with MapLibre whether or not a token is available (the element decides that).
// This page only decides whether to FIND a token first: when one is on offer (a rung above, a
// host-set window.MAP_TOKEN, or a token endpoint) it resolves it, since place search uses it on
// either engine; with none, it mounts at once, keyless: no token prompt, no request to Mapbox.
var ASKED = String((BASE_CONFIG && BASE_CONFIG.provider) || qp('provider') || window.MAP_PROVIDER || '').toLowerCase().trim();
var EXPLICIT = (ASKED === 'mapbox' || ASKED === 'maplibre') ? ASKED : '';
var HAS_TOKEN = !!(directToken || (typeof window.MAP_TOKEN === 'string' && window.MAP_TOKEN));
var HAS_ENDPOINT = !!(window.MAP_TOKEN_URL || (TOKEN_SRC && TOKEN_SRC !== 'window.MAP_TOKEN_URL'));
if (EXPLICIT === 'maplibre' || (!EXPLICIT && !HAS_TOKEN && !HAS_ENDPOINT)) { TOKEN_FREE = true; }
if (TOKEN_FREE) {
if (directToken && typeof window !== 'undefined' && !window.MAP_TOKEN) { window.MAP_TOKEN = directToken; }
mount('');
// A token-free composite with no token anywhere: its content renders, but its nested maps
// cannot. Ask once; the token is stored for the whole tree and the page reloads with it.
// Only when Mapbox was ASKED for: under 'auto' the nested maps draw with MapLibre instead.
if (NESTS_MAPS && !directToken && EXPLICIT === 'mapbox') {
var bar = document.createElement('div');
bar.id = 'status';
bar.setAttribute('style', 'position:fixed;left:12px;right:12px;bottom:12px;z-index:2147483000;padding:10px 12px;border-radius:10px;background:#0e1623;color:#eef2f7;font:13px system-ui,sans-serif;box-shadow:0 6px 24px rgba(0,0,0,.25)');
document.body.appendChild(bar);
status = bar;
askToken();
var goBtn = document.getElementById('tkGo');
if (goBtn) goBtn.addEventListener('click', function () {
var v = (document.getElementById('tkIn').value || '').trim();
if (v) { location.reload(); }
});
}
return;
}
if (directToken) { return mount(directToken); }
// Rungs 4-6: resolve the token ENDPOINT candidates and try them IN ORDER — the first
// one that answers with a token wins. Order: window.MAP_TOKEN_URL override → the
// configured TOKEN_SRC (an ABSOLUTE url, so a tree hosted on a CDN away from the API
// still finds it) → same-origin /api/maps/token (dev, or the site hosting both).
// A single hard-coded pick used to kill the page when its one url 404'd or was
// blocked by CORS; a shared link must work wherever the tree is hosted.
var candidates = [];
function addCandidate(u) { if (u && candidates.indexOf(u) === -1) candidates.push(u); }
addCandidate(window.MAP_TOKEN_URL);
addCandidate(TOKEN_SRC && TOKEN_SRC !== 'window.MAP_TOKEN_URL' ? TOKEN_SRC : '');
addCandidate(DEFAULT_TOKEN_URL);
function fetchToken(i, errors) {
if (i >= candidates.length) {
// Every endpoint failed. Under 'auto' that means no token: draw with MapLibre, keyless.
if (!EXPLICIT) { TOKEN_FREE = true; return mount(''); }
// Mapbox was asked for: say which endpoints failed, and still offer the paste-once box.
askToken();
if (status) {
var d = document.createElement('div');
d.textContent = '⚠ Token fetch failed from ' + candidates.join(', ') + ' — set window.MAP_TOKEN_URL or pass ?tk=. (' + errors.join(' | ') + ')';
status.insertBefore(d, status.firstChild);
}
return;
}
var url = candidates[i];
return fetch(url)
.then(function (r) {
if (!r.ok) throw new Error(url + ' → HTTP ' + r.status);
var ct = r.headers.get('content-type') || '';
return ct.indexOf('json') !== -1 ? r.json() : r.text();
})
.then(function (data) {
var tk = extractToken(data);
if (!tk) throw new Error(url + ' → no token in response');
mount(tk);
})
.catch(function (e) {
errors.push(e && e.message ? e.message : String(e));
return fetchToken(i + 1, errors);
});
}
fetchToken(0, []);
})();
</script>
</body>
</html>

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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww" 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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -78,7 +78,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-LUb5JU9YwVHrw7EJnIGcpSu+Tr56M/m0FdmzGrCzETZ94giVhF4ZffkbfRXjvu2v" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-qe3f3jw8Yu3fdfWb2RGAQF49vZxIPyLoVgFxp0D8nKFfwpHqd3c36JhNI/g1Vxww" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order: