Merge origin/main into the studio branch
Some checks failed
build-gate / build (push) Has been cancelled

The two repos carry the same work under different commit hashes, so this
branch had drifted 30 commits behind while looking 8 ahead. Pushing it would
have DELETED 315 lines of newer upstream work, including
check-maplibre-layer-drops.mjs entirely and the current versions of six
library/ files.

Both conflicts were textual, not semantic: package.json's script map is
key-for-key identical to remote's (verified before resolving, not assumed),
and check-packet-render.mjs is byte-identical on both sides — add/add
artifacts of two repos that built the same file in separate histories.

This also retires the divergence finding committed a moment ago. It was
measured against this repo's STALE checkout rather than against main; the
merge brings library/ to byte-identical with wt-packet and
check:poster-prints — which failed with "printPacket is not a function" —
now passes. The durable part of that finding is the absolute-path bug, and
that is already recorded where it matters, in the gates themselves.

check:i18n-parity, check:locale-reachable, check:poster-prints,
check:tabs-localized and check:no-abs-paths all pass on the merged tree.
This commit is contained in:
doxa-maps-88655c70 2026-09-24 06:29:57 +00:00
commit cf33a79c32
73 changed files with 2337 additions and 776 deletions

View file

@ -143,6 +143,8 @@ and a change here can break other maps.
`import … from '@map/composables/useMapSelection.js'`
- **useMapTheme** — useMapTheme.js — shared light/dark theme for every map profile.
`import … from '@map/composables/useMapTheme.js'`
- **usePosterPrints** — usePosterPrints.js — THE print actions every poster wall shares.
`import … from '@map/composables/usePosterPrints.js'`
- **usePplrInstance** — usePplrInstance.js — per-map "instance store" mediator.
`import … from '@map/composables/usePplrInstance.js'`
- **usePrayedLocally** — usePrayedLocally.js — the "my dot glows" encouragement loop.

View file

@ -1,68 +0,0 @@
# FINDING — library/ has diverged two-ways from wt-packet, and absolute paths were hiding it
**Found** 2026-09-24, while making `check-i18n-parity` repo-relative.
**Status:** path bugs FIXED; the code divergence is REPORTED, NOT RESOLVED — it needs a decision.
## What was hiding it
Three gates in this repo defaulted `REPO` to a hardcoded
`/home/lk10x/Workspace/eco-dx/root-doxa-maps/wt-packet`:
- `check-i18n-parity.mjs`
- `check-locale-reachable.mjs`
- `check-poster-prints.mjs`
`doxa-maps-plugin-studio` and `wt-packet` are **separate repos, not worktrees of one**. So each of
these gates opened the *other* repo, graded *its* files, and printed PASS for a tree it had never
read. Not a portability nit — a gate pointed at the wrong target reports the target's health while
saying nothing about its subject. All three are now
`resolve(dirname(fileURLToPath(import.meta.url)), '..')`.
The moment they read their own tree, two real problems surfaced.
## 1. The locale tree — FIXED (it was a strict subset)
`it/ro/zh` were 103 keys behind, and every other locale was short too, including
`buttons.json:share` and `shareSteps` — the exact orphan `check-i18n-parity`'s own header describes
it as having been written to catch. The bug it exists for had reappeared in a second repo, unseen.
Before copying anything, the direction was **measured**: zero keys existed only here, zero
translations disagreed. A strict subset, so a forward copy was provably lossless. Both repos now
report `162 key(s) of known translation debt` — `regions.json` in it/ro/zh, and nothing else.
## 2. library/ — NOT FIXED, and must NOT be copied the same way
`check-poster-prints` fails here with `pk.printPacket is not a function`: this repo's
`usePosterPrints.js` predates the prayer-packet action. The tempting move is the one that worked
for the catalogs — copy wt-packet's version over. **Do not**, without reading each file.
The same measurement that cleared the catalogs *fails* for these. Every one of the six has lines
that exist ONLY here:
| file | lines only in wt-packet | lines only in studio |
|---|---|---|
| `library/components/poster/PosterWall.vue` | 12 | 9 |
| `library/composables/useCountryOutline.js` | 45 | 3 |
| `library/composables/useMapClustering.js` | 1 | 1 |
| `library/composables/useMapLayers.js` | 46 | 9 |
| `library/composables/useMapProvider.js` | 16 | 3 |
| `library/composables/usePosterPrints.js` | 33 | 1 |
That is **two-way divergence, not staleness**. A wholesale copy would silently delete studio-side
work — the identical action that was correct for `locales/` is destructive here. What made the
locale sync safe was not that it looked similar; it was the proof that nothing would be lost.
## What a resolver needs to decide
1. Is this repo a **consumer** of wt-packet's library (→ reconcile per hunk, then keep it synced by
a mechanism rather than by hand), or does it legitimately **own** a fork of these six files
(→ then the shared gates should not be shared, and this finding closes)?
2. `usePosterPrints.js` is the concrete instance: is `printPacket` wanted here? If yes, port it
with the 1 studio-only line preserved. If no, `check:poster-prints` should not run in this repo.
3. `check:poster-prints`, `check:locale-reachable`, `check:i18n-parity` and `check:tabs-localized`
are all present here but **absent from `gates:post`**, so none of them gate this repo's build.
`check:no-abs-paths` DOES run, which is why the path fixes were required rather than optional.
Until (1) is answered, the four gates above are runnable by hand and honest about what they find —
which is strictly better than the previous state, where three of them passed by reading someone
else's files.

View file

@ -0,0 +1,136 @@
#!/usr/bin/env node
/**
* check-maplibre-layer-drops.mjs — MapLibre must not SILENTLY DROP a layer.
*
* THE DEFECT CLASS, found twice in one flight and invisible to every other gate:
* MapLibre validates a layer spec and, if any property is unknown or misplaced, REJECTS THE WHOLE
* LAYER. addLayer() does NOT throw — it accepts the call, emits an `error` EVENT on the map, and
* silently omits the layer. getLayer() then returns undefined and the map renders without it. So
* the symptom is "a thing is missing", with no exception, no failed request, and no console error
* from the app's own code. Three ticks of instrumenting addLayer() found nothing, because the
* failure never travels through addLayer's return path.
*
* MEASURED instances, both real and both shipped:
* layers.regions-fill.paint.fill-emissive-strength: unknown property
* -> *-emissive-strength is a Mapbox GL v3 LIGHTING property. The WAGF region fills were
* absent on every MapLibre map while Mapbox showed them.
* layers.apg-pins.paint.circle-sort-key: unknown property "circle-sort-key"
* -> circle-sort-key is a LAYOUT property, written into paint. Mapbox tolerated the
* misplacement; MapLibre dropped the layer, so ALL 12,379 pins on all-people-groups
* vanished under the keyless engine.
*
* WHAT IT ASSERTS: load every isMap leaf in the built manifest with ?provider=maplibre, listen to
* the map's own `error` event, and fail on any message in the layer/source-dropping family
* (unknown property / does not exist / is required / Expected / invalid). Other errors are
* REPORTED but not failed — a tile 404 is a different problem and should not be smuggled in here.
*
* ★ IT IS A REAL CONTROL, NOT DECORATION: run against the tree before the fixes it reports
* 1 of 17 leaves dropping, and 0 of 17 after. It has been seen both red and green on the same
* codebase, which is the only thing that makes a green meaningful.
*
* SKIPS CLEANLY (exit 0) when the server is unreachable. An UNMEASURED check is not a FAILED one —
* check:filter-width prints "FAIL" when it cannot reach its server, and that is how a gate teaches
* people to ignore it.
*
* Usage: bun run serve (or any server on BASE_URL), then:
* node internal/check-maplibre-layer-drops.mjs
* BASE_URL=http://127.0.0.1:4399 node internal/check-maplibre-layer-drops.mjs
*/
import { chromium } from 'playwright'
import { readFileSync, existsSync } from 'node:fs'
import { resolve, join, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
// Portable by construction — see check-no-absolute-paths.mjs. Never hardcode a worktree.
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const BASE = String(process.env.BASE_URL || 'http://127.0.0.1:4173').replace(/\/+$/, '')
const MANIFEST = join(ROOT, 'public', 'doxa-maps', 'manifest.json')
const DROP_RE = /unknown property|does not exist|is required|Expected|invalid/i
if (!existsSync(MANIFEST)) {
console.log('MAPLIBRE-LAYER-DROPS: SKIP — no built manifest (run `bun run tree` first).')
process.exit(0)
}
const manifest = JSON.parse(readFileSync(MANIFEST, 'utf8'))
const leaves = []
for (const b of manifest.bundles || []) {
for (const p of b.profiles || []) if (p.isMap) leaves.push([b.bundle, p.profile])
}
if (!leaves.length) {
console.log('MAPLIBRE-LAYER-DROPS: SKIP — the manifest declares no isMap leaf.')
process.exit(0)
}
// Capture the map's error events by wrapping whichever engine global the bundle loads at runtime.
const INIT = () => {
window.__mapErrs = []
const wrap = (ns) => {
if (!ns || ns.__wrappedForDrops) return ns
const Orig = ns.Map
function Patched(...a) {
const m = new Orig(...a)
try {
m.on('error', (ev) => {
const t = String((ev && ev.error && ev.error.message) || (ev && ev.message) || '')
if (t) window.__mapErrs.push(t.slice(0, 160))
})
} catch (_) { /* an engine without .on must not break the page */ }
return m
}
Patched.prototype = Orig.prototype
ns.Map = Patched
ns.__wrappedForDrops = true
return ns
}
for (const name of ['maplibregl', 'mapboxgl']) {
let v
Object.defineProperty(window, name, {
configurable: true, get() { return v }, set(nv) { v = wrap(nv) },
})
}
}
console.log(`MAPLIBRE-LAYER-DROPS: ${leaves.length} isMap leaf/leaves at ${BASE}`)
const browser = await chromium.launch({
args: ['--use-gl=swiftshader', '--enable-unsafe-swiftshader', '--ignore-gpu-blocklist'],
})
const offenders = []
let unreachable = 0
for (const [bundle, profile] of leaves) {
const page = await browser.newPage({ viewport: { width: 1100, height: 760 } })
await page.addInitScript(INIT)
const url = `${BASE}/doxa-maps/${bundle}/${profile}/index.html?provider=maplibre`
try {
await page.goto(url, { waitUntil: 'networkidle', timeout: 60000 })
await page.waitForTimeout(9000)
const errs = await page.evaluate(() => [...new Set(window.__mapErrs || [])])
const drops = errs.filter((e) => DROP_RE.test(e))
if (drops.length) {
offenders.push({ leaf: `${bundle}/${profile}`, drops })
console.log(` ✗ ${bundle}/${profile} — ${drops[0]}`)
} else {
console.log(` ok ${bundle}/${profile}`)
}
} catch (e) {
unreachable++
console.log(` · ${bundle}/${profile} — UNMEASURED (${String(e.message).slice(0, 60)})`)
}
await page.close()
}
await browser.close()
if (unreachable === leaves.length) {
console.log('MAPLIBRE-LAYER-DROPS: SKIP — nothing was reachable at ' + BASE + '. Start `bun run serve`.')
process.exit(0)
}
if (offenders.length) {
console.error(`\nMAPLIBRE-LAYER-DROPS: FAIL — ${offenders.length} leaf/leaves silently drop a layer under MapLibre.`)
for (const o of offenders) for (const d of o.drops) console.error(` ${o.leaf}: ${d}`)
console.error('\n MapLibre rejects a whole layer for ONE unknown or misplaced property, without throwing.')
console.error(' Engine-only paint (e.g. *-emissive-strength) belongs behind emissivePaint(map, kind);')
console.error(' layout properties (e.g. circle-sort-key) belong in `layout`, not `paint`.')
process.exit(1)
}
console.log(`\nMAPLIBRE-LAYER-DROPS: PASS — ${leaves.length - unreachable} leaf/leaves, no layer dropped by MapLibre.`)

View file

@ -2,6 +2,19 @@
/**
* check-sfc-script-parses.mjs — every .vue script block must actually PARSE.
*
* ⚠ IT IMPORTS `@vue/compiler-sfc`, so it needs an INSTALLED node_modules. Unlike its ~20 sibling
* check:* gates, which use only Node built-ins and therefore run in a bare worktree, this one
* dies with ERR_MODULE_NOT_FOUND if deps are missing — and it is the FIRST pre-gate to do so, so
* its failure is what a dependency-less worktree looks like from the build log. Measured
* 2026-09-24 in wt-packet: `node_modules/` was entirely absent, `bun run build` reported
* "6/7 pre gates passed — check:sfc-parse FAILED" on a tree with ZERO parse errors, and the real
* error (`Cannot find package '@vue/compiler-sfc'`) was hidden by the parallel runner.
* If you see this gate fail with ERR_MODULE_NOT_FOUND, run `bun install --frozen-lockfile` —
* do NOT chase a parse bug, and do NOT switch the shebang to bun. Switching runtimes only
* APPEARS to fix it: bun falls back to a global module cache and resolves the import on a tree
* that has no node_modules at all, so this gate goes green while all 23 bundle builds still fail
* on `Cannot find package 'vite'`. That is a masked environment fault, not a fix.
*
* THE GAP THIS CLOSES. `check:template-literal` catches a stray backtick inside a CSS *comment*
* within a template literal, but NOT one in LIVE CSS — and a live-CSS backtick breaks the build the
* same way. Proven both directions on 2026-09-21 (see

View file

@ -1474,9 +1474,16 @@ function main() {
// the engine whether the family is usable.
// Small and self-contained: a woff2 pair is ~22KB, and the tree's self-contained promise
// is exactly why it has to travel with it.
// ★ images/ MUST be staged for the same reason fonts/ must (see the note above). The
// regions clone copies DX-life's worldmap.svg watermark, which their UupgsList sets inline
// as a background-image on its root (UupgsList.vue:451-454, background-size 60% /
// background-position top / min-height 400px). A leaf resolves assetsBase to <tree>/assets,
// so the URL is fetched from INSIDE the tree; with images/ absent from this allowlist it
// 404s and the watermark is simply not there, with no error anywhere — the background just
// does not paint, which is even quieter than the font failure was.
const assetDirs = DEST_CONFIG.bundlePosters
? ['previews', 'posters', 'fonts']
: ['previews', 'fonts']
? ['previews', 'posters', 'fonts', 'images']
: ['previews', 'fonts', 'images']
for (const dirName of assetDirs) {
const src = join(pubAssets, dirName)
if (!existsSync(src)) { console.warn(`[generate-tree] WARN missing tree asset dir: assets/${dirName}`); continue }

View file

@ -228,7 +228,10 @@ async function exportPoster(item) {
// than offering an action that cannot work.
// The wall follows the app's locale: the card deck and its QR codes are localised,
// and packet-strings.json falls back per key.
const { locale: wallLocale } = useI18n()
// `t` for the wall's own labels, `locale` for the card deck's language. Both come
// from the SAME instance so a label and a printed deck can never disagree about
// which language the reader chose.
const { t, locale: wallLocale } = useI18n()
// ⚠ ONE exportState, not two. The composable owns a ref of its own; if the HUD
// keeps rendering the wall's while the print actions write to the composable's, a
// card-deck print shows NO progress and its errors vanish silently — the mechanism
@ -440,10 +443,10 @@ useShadowStyles(
:class="{ 'is-last': lastShown === item.id }" :data-list-id="item.id">
<button type="button" class="tape tape-h"
:aria-label="`Show ${item.label} on the map`" @click="showOnMap(item)">
:aria-label="t('buttons.showOnMapAria', { label: item.label })" @click="showOnMap(item)">
<span class="hcount">{{ item.count }} {{ unit }}</span>
<span class="hsep">·</span>
<span class="hlabel">Show on map</span>
<span class="hlabel">{{ t('buttons.showOnMap') }}</span>
</button>
<div class="main">
@ -465,14 +468,14 @@ useShadowStyles(
</div>
<fieldset class="tape pfs">
<legend>Print Options</legend>
<button type="button" class="pbtn" @click="downloadPacket(item)">Prayer List</button>
<legend>{{ t('buttons.printOptions') }}</legend>
<button type="button" class="pbtn" @click="downloadPacket(item)">{{ t('buttons.prayerList') }}</button>
<!-- CARD DECK — only when this wall can supply rows. A button that
cannot work is worse than an absent one, so it is gated on the
records provider rather than shown and then failing at click. -->
<button v-if="canPrintRows" type="button" class="pbtn"
@click="prints.printCardDeck(item)">Card Deck</button>
<button type="button" class="pbtn" @click="exportPoster(item)">Poster Map</button>
@click="prints.printCardDeck(item)">{{ t('buttons.cardDeck') }}</button>
<button type="button" class="pbtn" @click="exportPoster(item)">{{ t('buttons.posterMap') }}</button>
</fieldset>
</div>
</div>
@ -485,12 +488,12 @@ useShadowStyles(
<template v-if="exportState.phase === 'error'">
<div class="modal-err">{{ exportState.message }}</div>
<button type="button" class="modal-btn" @click="dismissExport">Close</button>
<button type="button" class="modal-btn" @click="dismissExport">{{ t('buttons.close') }}</button>
</template>
<template v-else-if="exportState.phase === 'soon'">
<div class="modal-soon">{{ exportState.message }}</div>
<button type="button" class="modal-btn" @click="dismissExport">Close</button>
<button type="button" class="modal-btn" @click="dismissExport">{{ t('buttons.close') }}</button>
</template>
<template v-else>

View file

@ -31,6 +31,9 @@
* outline.clearCountry()
*/
import { resolveAssetsBase } from '../utils/embedBase.js'
import { emissivePaint } from './useMapProvider.js'
const SOURCE_ID = 'doxa-country-outline'
const LAYER_ID = 'doxa-country-outline-line'
@ -124,12 +127,51 @@ export function useCountryOutline(getMap, opts = {}) {
// Swap any stale source, then (re)create the singleton outline layer.
clearCountry()
try {
m.addSource(SOURCE_ID, { type: 'vector', url: COUNTRY_BOUNDARIES_URL })
// ── COUNTRY POLYGONS, PER ENGINE ────────────────────────────────────────────────────────
// ★ COUNTRY_BOUNDARIES_URL IS A MAPBOX-HOSTED VECTOR TILESET, AND MAPLIBRE CANNOT FETCH IT.
// It throws "Fetch API cannot load mapbox://mapbox.country-boundaries-v1. URL scheme
// 'mapbox' is not supported" and then draws everything else perfectly, so the country
// outline is simply ABSENT with no visible failure. MEASURED on country-posters-mfe the
// moment it landed: engine swapped, 14 -> 4 mapbox requests, canvas fine, and this error in
// the console. THREE consumers share this composable — doxa-simple-map, countries-map and
// research-map — so the fix belongs here, once, not three times.
// Same shape already proven in DashboardMapPanel and RegionCountryMap.
//
// The ENGINE is read off the live map rather than guessed from config: the container carries
// maplibregl-map or mapboxgl-map, which is a fact about the instance in hand. Consumers call
// useCountryOutline(() => map.value) with no options, so there is no provider to pass in.
const isMaplibre = (() => {
try { return !!m.getContainer?.()?.classList?.contains('maplibregl-map') } catch (_) { return false }
})()
if (isMaplibre) {
// Add EMPTY first, then setData after the fetch, so addLayer below stays SYNCHRONOUS and
// the outline keeps its place in the layer order.
m.addSource(SOURCE_ID, { type: 'geojson', data: { type: 'FeatureCollection', features: [] } })
fetch(`${resolveAssetsBase(null)}/boundaries/world-adm0.geojson`)
.then((r) => r.json())
.then((gj) => {
// The tileset names the ISO field iso_3166_1_alpha_3; the geojson names it iso3.
// countryFilter() reads the tileset name, so normalise ONCE here and every filter
// downstream keeps reading the single name it always read.
for (const f of gj.features || []) {
if (f.properties && f.properties.iso3) f.properties.iso_3166_1_alpha_3 = f.properties.iso3
}
const live = typeof getMap === 'function' ? getMap() : null
const src = live && live.getSource(SOURCE_ID)
if (src) src.setData(gj)
})
.catch((e) => console.warn('[country-outline] boundaries failed to load', e))
} else {
m.addSource(SOURCE_ID, { type: 'vector', url: COUNTRY_BOUNDARIES_URL })
}
m.addLayer({
id: LAYER_ID,
type: 'line',
source: SOURCE_ID,
'source-layer': SOURCE_LAYER,
// 'source-layer' applies to VECTOR TILE sources only — MapLibre rejects a layer that
// declares one on a geojson source ("does not need a source-layer").
...(isMaplibre ? {} : { 'source-layer': SOURCE_LAYER }),
filter,
layout: { 'line-join': 'round', 'line-cap': 'round' },
// Outline only — no fill layer — so pins / labels under the country
@ -140,7 +182,7 @@ export function useCountryOutline(getMap, opts = {}) {
'line-opacity': lineOpacity,
// Bypass Standard v3 scene-lighting so the outline keeps its colour on the
// night preset instead of darkening to near-black (mirror of useMapLayers.js:248).
'line-emissive-strength': 1,
...emissivePaint(m, 'line'),
},
})
} catch (_) {

View file

@ -544,7 +544,7 @@ export function useMapClustering(options = {}) {
],
// Bypass Standard v3 scene-lighting so MST/network lines keep their colour
// on the night preset instead of darkening (mirror useMapLayers.js:248).
'line-emissive-strength': 1,
...emissivePaint(map, 'line'),
'line-opacity': 0.5
},
layout: {

View file

@ -4,6 +4,7 @@
// Import Vue functions from NPM package
import { ref, toRaw } from 'vue';
import { resolveAssetsBase } from '../utils/embedBase.js'
import { emissivePaint } from './useMapProvider.js';
// Import utilities
@ -416,23 +417,55 @@ export function useMapLayers(options = {}) {
? 'language-family-pins'
: undefined;
map.addSource('regions', {
type: 'vector',
url: 'mapbox://mapbox.country-boundaries-v1'
});
// ── REGION POLYGONS, PER ENGINE ────────────────────────────────────────────────────
// ★ SECOND SITE OF THE SAME DEFECT. mapbox://mapbox.country-boundaries-v1 is a
// Mapbox-hosted VECTOR TILESET; MapLibre cannot fetch a mapbox:// URL and throws
// Fetch API cannot load mapbox://mapbox.country-boundaries-v1. URL scheme "mapbox"
// then renders everything else correctly with this fill simply MISSING. Fixing the
// country-OUTLINE composable cleaned doxa-simple-map and research-map but left
// countries-map (and the new country-posters-mfe that nests it) still throwing —
// measured, which is how this second site was found at all.
// The keyless equivalent already ships: assets/boundaries/world-adm0.geojson.
// Engine read off the live map (its container carries maplibregl-map), not guessed.
const _isMaplibre = (() => {
try { return !!map.getContainer?.()?.classList?.contains('maplibregl-map') } catch (_) { return false }
})();
if (_isMaplibre) {
// EMPTY first so the addLayer below stays synchronous and keeps its z-order slot
// (regions → shadow → pins → hitbox); setData once the fetch lands.
map.addSource('regions', { type: 'geojson', data: { type: 'FeatureCollection', features: [] } });
fetch(`${resolveAssetsBase(null)}/boundaries/world-adm0.geojson`)
.then((r) => r.json())
.then((gj) => {
// Tileset field is iso_3166_1_alpha_3; the geojson's is iso3. Normalise ONCE
// so every colour/filter expression downstream reads the name it always read.
for (const f of gj.features || []) {
if (f.properties && f.properties.iso3) f.properties.iso_3166_1_alpha_3 = f.properties.iso3;
}
const src = map.getSource('regions');
if (src) src.setData(gj);
})
.catch((e) => console.warn('[map-layers] region boundaries failed to load', e));
} else {
map.addSource('regions', {
type: 'vector',
url: 'mapbox://mapbox.country-boundaries-v1'
});
}
map.addLayer({
id: 'regions-fill',
type: 'fill',
source: 'regions',
'source-layer': 'country_boundaries',
// VECTOR-TILE only; MapLibre rejects a layer declaring source-layer on geojson.
...(_isMaplibre ? {} : { 'source-layer': 'country_boundaries' }),
paint: {
'fill-color': fillColorExpr,
'fill-opacity': colorScheme === 'none' ? 0.1 : 0.7,
'fill-antialias': true,
// Standard-style night lighting darkens custom layers — emit full colour
// so region fills keep their colour in dark mode (doxa dark-mode fix).
'fill-emissive-strength': 1,
...emissivePaint(map, 'fill'),
'fill-opacity-transition': { duration: 300 }
}
}, beforeId);
@ -441,7 +474,11 @@ export function useMapLayers(options = {}) {
id: 'regions-border',
type: 'line',
source: 'regions',
'source-layer': 'country_boundaries',
// Same rule as regions-fill above: VECTOR-TILE only. This sibling kept the literal
// and so was still dropped by MapLibre after the fill was fixed —
// Source layer "country_boundaries" does not exist on source
// which surfaces ONLY on the map's error event, never from addLayer().
...(_isMaplibre ? {} : { 'source-layer': 'country_boundaries' }),
paint: {
// Crisp per-region outline: each country border is drawn in its own
// region hue at full opacity. Internal (same-region) borders blend
@ -452,7 +489,7 @@ export function useMapLayers(options = {}) {
'line-width': 1,
'line-opacity': 0.9,
// Emit full colour so the border stays visible on the night preset.
'line-emissive-strength': 1
...emissivePaint(map, 'line')
}
}, beforeId);
@ -545,7 +582,7 @@ export function useMapLayers(options = {}) {
'line-width': 0.75,
'line-opacity': 0.5,
// Emit full colour so connection lines stay visible on the night preset.
'line-emissive-strength': 1
...emissivePaint(map, 'line')
}
}, 'language-family-pins'); // Add below the pins layer

View file

@ -63,7 +63,20 @@ export function isMapboxMap(map) {
/** Mapbox-Standard-only lighting paint props, per engine. MapLibre rejects layers whose
* paint carries unknown properties (the whole layer is dropped → invisible pins), so
* spread this instead of writing 'circle-emissive-strength' literally. */
export function emissivePaint(map) {
return isMapboxMap(map) ? { 'circle-emissive-strength': 1 } : {}
* spread this instead of writing '<kind>-emissive-strength' literally.
*
* ★ `kind` EXISTS BECAUSE THE CIRCLE CASE WAS NOT THE ONLY ONE. This helper was hardcoded to
* 'circle', while fill, line and clustering layers still wrote the literal — so those layers kept
* being dropped by MapLibre for exactly the reason written above. MEASURED on countries-map by
* listening to the map's own `error` event, which is the ONLY place it surfaces:
* layers.regions-fill.paint.fill-emissive-strength: unknown property
* layers.regions-border.paint.line-emissive-strength: unknown property
* addLayer() does NOT throw for this — it accepts the call, emits an error event, and silently
* omits the layer. getLayer() then returns undefined and the map simply renders without it, which
* is why it read as "the fills do not paint" rather than as an error.
* @param {object} map the live map instance
* @param {'circle'|'fill'|'line'} [kind='circle']
*/
export function emissivePaint(map, kind = 'circle') {
return isMapboxMap(map) ? { [`${kind}-emissive-strength`]: 1 } : {}
}

View file

@ -164,5 +164,37 @@ export function usePosterPrints(opts = {}) {
} catch (e) { fail(item, kind, e); }
}
return { exportState, dismiss, printPoster, printList, printCardDeck };
// ── 4. THE PRAYER PACKET ──────────────────────────────────────────────────
// The full booklet: map one-pager, people groups 20-per-page with photos, the 12
// prayer points, the prayer wheel. Shares the renderer with the build-time
// generator (library/packet/packet-render.js), so a printed packet and a
// generated one cannot diverge.
//
// The MAP PAGE is optional by design: `mapSvg` is supplied by the caller because
// only the bundle knows where its posters are served from. If it cannot be
// fetched the packet still prints — a cover without the map beats no packet.
async function printPacket(item, { mapSvg = '' } = {}) {
if (busy()) return;
const kind = 'Prayer Packet';
set(item, kind, 'fetch', 'fetching people groups', 30);
try {
const data = await rows(item);
const [{ createPacketRenderer }, strings] = await Promise.all([
import('../packet/packet-render.js'),
opts.strings ? opts.strings() : import('../scripts/posters/packet-strings.json').then((m) => m.default || m),
]);
const R = createPacketRenderer({ strings, lang: lang() });
// Photos stay as URLs. The Node generator base64-inlines them so its file is
// self-contained offline; in a browser the print frame fetches them, and
// inlining ~95 images client-side would stall the tab for no gain.
const photos = new Map(
data.filter((g) => g.image_url).map((g) => [g.slug, g.image_url]),
);
set(item, kind, 'render', `printing ${data.length} people groups`, 70);
openPrintFrame(R.buildPacket(item, data, photos, mapSvg), { autoprint: true });
done(item, kind);
} catch (e) { fail(item, kind, e); }
}
return { exportState, dismiss, printPoster, printList, printCardDeck, printPacket };
}

View file

@ -58,10 +58,6 @@
"name": "platform-reachability",
"rows": 2625
},
{
"name": "field-access-visas",
"rows": 1146
},
{
"name": "gaps-and-opportunities",
"rows": 2106

View file

@ -142,7 +142,10 @@
"check:legend-source": "node internal/check-legend-matches-source.mjs # the numbers the maps SHOW must match the numbers the live SOURCE has. Every other gate checks INTERNAL consistency — a page can agree with itself perfectly while its legend has stopped describing reality. Offline SKIPs (exit 0); only a reachable endpoint that disagrees fails.",
"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:wp-embed check:doc-scripts",
"gates:post": "node internal/run-parallel.mjs --label=post -- 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",
"build:bundles": "node internal/run-parallel.mjs --bundles"
"build:bundles": "node internal/run-parallel.mjs --bundles",
"check:maplibre-drops": "node internal/check-maplibre-layer-drops.mjs",
"gates:post": "node internal/run-parallel.mjs --label=post -- 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:tabs-localized": "node internal/check-tabs-localized.mjs # a chosen locale must CHANGE the rendered tab text. check:i18n-parity compares catalogs to each OTHER, so it cannot tell a shipped translation from a dead one; tabs.json is reached only via a DYNAMIC key (SemanticTreeLegend.vue:40), invisible to any grep. Renders it and reads the result."
},
"devDependencies": {
"@capacitor/android": "^7.6.9",

View file

@ -185,6 +185,18 @@ function addLayer(fc) {
m.addSource('apg', { type: 'geojson', data: fc })
m.addLayer({
id: 'apg-pins', type: 'circle', source: 'apg',
// ★ circle-sort-key IS A LAYOUT PROPERTY, NOT PAINT — and putting it in paint cost this
// layer entirely under MapLibre. Mapbox tolerated the misplacement; MapLibre validates the
// spec and rejects the WHOLE layer for one unknown paint property, so every pin on this map
// vanished with nothing thrown. FOUND by listening to the map's own `error` event across
// every isMap leaf, which is the only place it surfaces:
// layers.apg-pins.paint.circle-sort-key: unknown property "circle-sort-key"
// Same failure shape as the *-emissive-strength drops fixed alongside this; the sort order
// itself is unchanged, it just now lives where the style spec says it belongs.
layout: {
// DOXA above frontier above unreached above reached — the assignment stays visible.
'circle-sort-key': ['match', ['get', 'category'], 'doxa', 4, 'frontier', 3, 'unreached', 2, 1],
},
paint: {
'circle-color': ['match', ['get', 'category'],
'doxa', CAT_COLOR.doxa, 'frontier', CAT_COLOR.frontier,
@ -195,8 +207,6 @@ function addLayer(fc) {
'circle-stroke-opacity': 0.85,
'circle-radius': ['interpolate', ['linear'], ['zoom'], 0, 2.2, 4, 3.4, 8, 6, 12, 9],
'circle-opacity': 0.92,
// DOXA above frontier above unreached above reached — the assignment stays visible.
'circle-sort-key': ['match', ['get', 'category'], 'doxa', 4, 'frontier', 3, 'unreached', 2, 1],
},
})
m.on('mouseenter', 'apg-pins', () => { m.getCanvas().style.cursor = 'pointer' })

View file

@ -441,7 +441,11 @@ const mapTheme = useMapTheme(uiStore)
const FEATURES = {
doxaRegions: true,
adoption: false, // Adoption tab hidden per UX request; wiring kept warm (flip to true to restore)
share: true, // Share button enabled — parameterized share control on every map
// The map-level ShareButton is GONE, not flagged off — country-posters-mfe.vue's
// header owns sharing for this bundle. See the note at its former site in the
// toolbar. This flag is kept only so the FEATURES shape stays stable for any
// other consumer reading it.
share: false,
hamburgerMenu: false, // canonical default — emit/listen mismatch + drawer surplus
// Per QA building-round-1 R3 A4: clear the geocoder text on tab switch by
// default; flip to true to preserve the previous tab's query when returning.
@ -2137,9 +2141,14 @@ onBeforeUnmount(() => {
<LocationButton :map="map" :is-dark="isDark" />
<FullscreenButton :map-container="mapContainer" :is-dark="isDark" />
<ThemeToggleButton :is-dark="isDark" @toggle="handleToggleTheme" />
<!-- Share button hidden behind FEATURES.share (glitch — PR gate). All
ShareButton code kept warm; flip FEATURES.share=true to restore. -->
<ShareButton v-if="FEATURES.share" :is-dark="isDark" :embed-path="'country-posters/countries-map/index.html'" />
<!-- ShareButton intentionally OMITTED; country-posters-mfe.vue's header owns
sharing for this bundle, exactly as upg-100-mfe does for the 100-list.
Rendering both gave the bundle TWO share affordances on one surface — the
BUG-UPG100-DOUBLE-SHARE state the 100-list already fixed once, caught here
by check:share-policy rather than by a reader seeing two buttons.
REMOVED, not flag-gated: a `v-if="false"` button is dead code that still
reads as an affordance to every reader and every counter. A map embedded
WITHOUT the MFE header would add one back deliberately. -->
</MapToolbar>
<!-- Fly + Clusters floating toolbar — sibling of the legend card, mounted

View file

@ -2,6 +2,11 @@
/**
* country-posters-mfe.vue — Country Posters as a TWO-TAB element.
*
* @element country-posters-mfe
* @description Country Posters as ONE two-tab element — the countries map and the printable
* poster wall behind a single view switcher, structured like the UPG-100 list. The switcher is
* the library's shared ViewSelect, not a third hand-rolled copy.
*
* Driver: "Country Posters is supposed to have two tabs, structured like the
* UPG-100 list."
*

View file

@ -38,6 +38,8 @@
*/
import { computed, inject, ref, watch, onBeforeUnmount } from 'vue'
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
import { usePosterPrints } from '@map/composables/usePosterPrints.js'
import { openPrintFrame } from '@map/composables/printInPlace.js'
import { useI18n } from 'vue-i18n'
// Export-modal geometry — see the note at .modal-scrim below, and library/utils/viewportScrim.js.
import { useViewportScrim } from '@map/utils/viewportScrim.js'
@ -339,34 +341,13 @@ const { scrimRef, scrimStyle } = useViewportScrim(exportState)
// "popup blocked -> fall back to opening the raw image" branch every caller carried is now dead.
// The returned object keeps a truthy `.document`-less shape only so existing `if (!w)` guards stay
// harmless; callers should no longer rely on a popup-blocked null.
function openPrintWindow(title, bodyHtml, { autoprint = false } = {}) {
const frame = document.createElement('iframe')
// Off-screen rather than display:none — a display:none iframe does not lay out in every engine,
// and a zero-height layout can print a blank first page.
frame.setAttribute('aria-hidden', 'true')
frame.style.cssText = 'position:fixed;right:0;bottom:0;width:1px;height:1px;opacity:0;border:0'
document.body.appendChild(frame)
const doc = frame.contentDocument
if (!doc) { frame.remove(); return null } // no document -> caller keeps its fallback
doc.open()
doc.write(bodyHtml)
if (autoprint) {
// Appended AFTER the caller's markup so it runs once the document is parsed —
// matches the <img onload> timing the poster path already relies on.
doc.write(
'<script>window.addEventListener("load",function(){setTimeout(function(){window.focus();window.print()},150)})</' + 'script>')
}
doc.close()
// Reclaim the node once the dialog has been dismissed. `afterprint` is the honest signal; the
// timeout is a floor for engines that never fire it, so a click can never leak a frame per press.
const drop = () => { if (frame.parentNode) frame.remove() }
try { frame.contentWindow.addEventListener('afterprint', () => setTimeout(drop, 0)) } catch { /* cross-doc guard */ }
setTimeout(drop, 60000)
return frame.contentWindow
}
// ★ ONE FRAME MECHANISM, not a fourth copy. This was a local reimplementation of
// library/composables/printInPlace.js — same off-screen iframe, same doc.write,
// same autoprint script, differing only in an unused `title` argument. Four copies
// of one mechanism is how a fix to the blank-first-page behaviour reaches one
// caller and not the others. The shared helper takes (bodyHtml, opts), so the
// title is dropped here: it was never used, the document's own <title> carries it.
const openPrintWindow = (title, bodyHtml, opts) => openPrintFrame(bodyHtml, opts);
// Escape the handful of characters that break out of an HTML text node or a "..." attribute.
// Print-window markup is built by string concatenation (no template-literal/backtick rule for
@ -533,43 +514,35 @@ async function printList100(list) {
// pre-baked PDF pointer exists there, `prayer-card-{country}-{lang}.pdf`, not a per-PG
// generator). Styling below borrows the poster-wall's own vocabulary (tape header, thin
// card border, Material Light palette) instead of inventing a fourth visual language.
// ── CARD DECK: the SHARED action ────────────────────────────────────────────
// This function used to be a second, hand-maintained copy of the deck print —
// same renderer call, same stock, same language resolution — living beside the
// composable's. Two copies of one fact drift: a fix to either was invisible to
// the other, which is the whole reason the wall was being consolidated.
//
// It now delegates to library/composables/usePosterPrints.js, sharing THIS wall's
// exportState so the HUD keeps rendering one surface. The bundle still owns the
// part that cannot be shared — fetchListRecords knows the people-groups API, the
// selector evaluator and the pg_slugs special case — and hands it over as the
// `records` provider.
const prints = usePosterPrints({
state: exportState,
records: (list) => fetchListRecords(list),
lang: () => deckLang(),
stock: () => deckStock.value,
label: (list) => list?.label || list?.id || '',
})
async function printCardDeck(list) {
if (exportState.value) return
exportState.value = { label: list.label, kind: 'Card Deck', phase: 'fetch',
message: 'fetching people-group records', pct: 30 }
try {
const rows = await fetchListRecords(list)
// ★ THE PAGE IS THE CARD. This used to set @page{size:letter portrait} and give
// each card height:100%, so a "deck" printed as 95 mostly-empty 8.5x11 sheets
// with no photo. The Driver: "the print dialog that opens up needs to show all
// the cards not in a paper format but a CARD format, the aspect ratio that is
// used in the card generator."
//
// The pages now come from library/packet/card-render.js — one renderer, every
// caller — which sets @page to the card stock's own inches, so one card is
// exactly one page at 2.5x3.5in. Print on cardstock and cut, or send the PDF
// to a card printer.
const [{ createCardRenderer }, strings] = await Promise.all([
import('@map/packet/card-render.js'),
import('@map/scripts/posters/packet-strings.json').then((m) => m.default || m),
])
const R = createCardRenderer({ strings, lang: deckLang(), stock: deckStock.value })
const title = `Doxa UPG prayer cards — ${escapeHtml(list.label || list.id)}`
exportState.value = { ...exportState.value, phase: 'render',
message: `laying out ${rows.length} cards`, pct: 70 }
const w = openPrintWindow(title, R.buildDeck(list, rows), { autoprint: true })
if (!w) {
// See the note in the list path: an iframe cannot be pop-up blocked.
exportState.value = { label: list.label, kind: 'Card Deck', phase: 'error',
message: 'Could not open the print dialog in this view — try the Download button.', pct: 0 }
return
}
exportState.value = { ...exportState.value, phase: 'done', message: 'print dialog opened', pct: 100 }
setTimeout(() => { exportState.value = null }, 900)
} catch (e) {
exportState.value = { label: list.label, kind: 'Card Deck', phase: 'error',
message: String(e?.message || e).slice(0, 140) + (API_BASE ? '' :
' (no API configured in this preview — set window.MAP_APP_API_URL)'), pct: 0 }
await prints.printCardDeck(list)
// Keep the preview-specific hint the shared action cannot know about: in a
// dropped tree with no API configured the failure is a CONFIGURATION problem,
// not a broken button, and saying so is the difference between "this is broken"
// and "this needs a URL".
const st = exportState.value
if (st && st.phase === 'error' && !API_BASE && !/MAP_APP_API_URL/.test(st.message)) {
exportState.value = { ...st,
message: `${st.message} (no API configured in this preview — set window.MAP_APP_API_URL)` }
}
}

View file

@ -81,7 +81,7 @@ import { useI18n } from 'vue-i18n'
// The in-place print helper: a hidden same-page iframe, NOT window.open(). A popup
// is blockable and drops the user out of the map; the iframe opens the print dialog
// right here. Shared so the packet, the poster and the card deck all print the same way.
import { openPrintFrame } from '@map/composables/printInPlace.js'
import { usePosterPrints } from '@map/composables/usePosterPrints.js'
import { buildLegendNodes, leafZones } from './data/legend-tree.js'
import { resolveAllZones } from './data/zone-geometry.js'
// slice 09b-9 §3 (L18/L29 FIX): the per-zone color OVERRIDE map. zone-colors.json
@ -344,10 +344,10 @@ const API_BASE = (typeof window !== 'undefined' && window.MAP_APP_API_URL)
|| import.meta.env.VITE_API_BASE_URL
|| ''
// Prayer-packet printing (legend Export > Prayer packet). openPrintFrame is the
// SHARED in-place print helper — a hidden same-page iframe, so the dialog opens in
// this tab rather than a popup a browser may block. The packet's locale follows the
// app's, so a reader gets it in their own language.
// Prayer-packet printing (legend Export > Prayer packet). The ACTION lives in the
// shared usePosterPrints composable — it prints through a hidden same-page iframe,
// so the dialog opens in this tab rather than a popup a browser may block. The
// packet's locale follows the app's, so a reader gets it in their own language.
const { locale: packetLocale } = useI18n()
const DEAF_COUNT = 123
@ -1132,68 +1132,84 @@ async function onLegendExport(kind) {
// Build and print a zone's prayer packet without leaving the page.
// PAGE ORDER IS THE PRODUCT SPEC: map · people groups 20/page with photos ·
// 12 prayer points · prayer wheel.
let packetBusy = false;
async function printPrayerPacket(zoneId) {
if (packetBusy) return; // a second click must not open a second job
packetBusy = true;
try {
const zone = allLists().find((z) => z.id === zoneId);
if (!zone) throw new Error(`no list "${zoneId}"`);
status.value = 'Building the prayer packet…';
// ── THE PRAYER PACKET: the SHARED action ────────────────────────────────────
// This was a second hand-maintained copy of the packet print — its own renderer
// import, its own strings fetch, its own language resolution — beside the card
// deck's, which was consolidated first. Two copies of one fact drift.
//
// It now delegates to library/composables/usePosterPrints.js. What stays HERE is
// what genuinely cannot be shared: resolving which people groups are in a list
// (the people-groups API, the selector evaluator, and the pg_slugs special case
// that 12 of the 27 lists need), and where this bundle's posters are served from.
const packetPrints = usePosterPrints({
records: (zone) => packetRecords(zone),
lang: () => packetLang(),
label: (zone) => zone?.label || zone?.id || '',
});
if (!API_BASE) throw new Error('no API configured');
const fields = 'slug,name,country_code,population,religion,image_url';
const resp = await fetch(`${API_BASE}/api/people-groups/list?fields=${fields}&lang=${packetLang()}`,
{ cache: 'no-store' });
if (!resp.ok) throw new Error(`people-groups fetch failed (${resp.status})`);
const records = normalizeRecords(extractRecords(await resp.json()));
// ⚠ pg_slugs BYPASSES the shared evaluator — it intentionally THROWS on that
// type, and 12 of the 27 lists use it. Same special-case the map and the poster
// wall already apply, so all three agree about who is in a list.
let slugs;
if (zone.selector && zone.selector.type === 'pg_slugs') {
slugs = new Set(zone.selector.values || []);
} else {
const { evaluate } = await import('./data/selector-evaluator.js');
slugs = new Set(evaluate(zone.selector, records)); // evaluate returns a Set
}
const groups = records.filter((r) => slugs.has(r.slug))
.sort((a, b) => String(a.name).localeCompare(String(b.name), packetLang()));
if (!groups.length) throw new Error('that list resolved to no people groups');
// Photos stay as URLs here. The Node generator base64-inlines them so its file
// is self-contained offline; in a browser the print frame can fetch them, and
// inlining 95 images client-side would stall the tab for no gain.
const photos = new Map(groups.filter((g) => g.image_url).map((g) => [g.slug, g.image_url]));
const [{ createPacketRenderer }, strings] = await Promise.all([
import('@map/packet/packet-render.js'),
import('@map/scripts/posters/packet-strings.json').then((m) => m.default || m),
]);
const R = createPacketRenderer({ strings, lang: packetLang() });
// The map page takes the poster's <svg>. If it cannot be fetched the packet
// still prints — a cover without the map beats no packet at all.
let mapSvg = '';
try {
const base = resolveAssetsBase(profileConfig.value);
const html = await (await fetch(`${base}/posters/${zoneId}.html`, { cache: 'force-cache' })).text();
const svg = html.match(/<svg[\s\S]*?<\/svg>/);
if (svg) mapSvg = `<style>${R.mapCss(html)}</style>`
+ `<div style="position:absolute;left:0;top:250px;width:${R.W}px;`
+ `transform:scale(0.62);transform-origin:top center">${svg[0]}</div>`;
} catch { /* cover page without the map */ }
status.value = `Printing ${groups.length} people groups…`;
openPrintFrame(R.buildPacket(zone, groups, photos, mapSvg), { autoprint: true });
status.value = '';
} catch (err) {
status.value = `Packet failed: ${err && err.message ? err.message : err}`;
setTimeout(() => { status.value = ''; }, 4000);
} finally {
packetBusy = false;
// ⚠ BRIDGE THE PROGRESS BACK TO THE SURFACE THIS MAP ACTUALLY SHOWS.
// The composable reports through its own exportState; this profile has no HUD for
// that and displays `status` instead. Without this watcher the packet would print
// SILENTLY — no "building…", and a failure would vanish with nothing said — which
// is the mechanism working while the feedback does not.
watch(packetPrints.exportState, (st) => {
if (!st) { if (/packet/i.test(status.value)) status.value = ''; return; }
if (st.phase === 'error') {
status.value = `Packet failed: ${st.message}`;
setTimeout(() => { if (status.value.startsWith('Packet failed')) status.value = ''; }, 4000);
return;
}
status.value = st.phase === 'done' ? '' : `${st.message}…`;
});
// BUNDLE-SPECIFIC: who is in this list. ⚠ pg_slugs BYPASSES the shared evaluator —
// it intentionally THROWS on that type, and 12 of the 27 lists use it. Same
// special-case the map and the poster wall apply, so all three agree about
// membership.
async function packetRecords(zone) {
if (!API_BASE) throw new Error('no API configured');
const fields = 'slug,name,country_code,population,religion,image_url';
const resp = await fetch(`${API_BASE}/api/people-groups/list?fields=${fields}&lang=${packetLang()}`,
{ cache: 'no-store' });
if (!resp.ok) throw new Error(`people-groups fetch failed (${resp.status})`);
const records = normalizeRecords(extractRecords(await resp.json()));
let slugs;
if (zone.selector && zone.selector.type === 'pg_slugs') {
slugs = new Set(zone.selector.values || []);
} else {
const { evaluate } = await import('./data/selector-evaluator.js');
slugs = new Set(evaluate(zone.selector, records)); // evaluate returns a Set
}
return records.filter((r) => slugs.has(r.slug))
.sort((a, b) => String(a.name).localeCompare(String(b.name), packetLang()));
}
// BUNDLE-SPECIFIC: the map page's <svg>, lifted from this bundle's own poster.
// Absent is fine — the packet prints a cover without the map rather than failing.
async function packetMapSvg(zoneId, R) {
try {
const base = resolveAssetsBase(profileConfig.value);
const html = await (await fetch(`${base}/posters/${zoneId}.html`, { cache: 'force-cache' })).text();
const svg = html.match(/<svg[\s\S]*?<\/svg>/);
if (!svg) return '';
return `<style>${R.mapCss(html)}</style>`
+ `<div style="position:absolute;left:0;top:250px;width:${R.W}px;`
+ `transform:scale(0.62);transform-origin:top center">${svg[0]}</div>`;
} catch { return ''; }
}
async function printPrayerPacket(zoneId) {
const zone = allLists().find((z) => z.id === zoneId);
if (!zone) return;
// The map svg needs the renderer's own mapCss/W, so it is resolved here and
// handed in rather than fetched inside the shared action, which knows nothing
// about where this bundle serves its posters.
const [{ createPacketRenderer }, strings] = await Promise.all([
import('@map/packet/packet-render.js'),
import('@map/scripts/posters/packet-strings.json').then((m) => m.default || m),
]);
const R = createPacketRenderer({ strings, lang: packetLang() });
await packetPrints.printPacket(zone, { mapSvg: await packetMapSvg(zoneId, R) });
}
// Every list across all three cluster buckets, flattened.

View file

@ -609,9 +609,19 @@ useShadowStyles(
'.rd-head{ display:flex; flex-direction:column; gap:10px; text-align:center; }' +
'.rd-backlink{ margin:0; }' +
// their .light-link on a dark-on-light page: brand-light, underlined on hover
// THEIR back-link is an <a class="light-link">, so it inherits the UA underline plus their
// own `a` rule (_globals.scss:132-138): font-weight medium, text-decoration-thickness 2px,
// text-underline-offset 4px — and .light-link recolours it to --color-brand-secondary =
// $color-beige-300 = #cbc5b9. MEASURED on their live /regions/cameroon: rgb(203, 197, 185)
// with text-decoration-line underline.
// Ours is a <button> because this element has no router, and a button inherits NEITHER the
// underline nor any link colour — so it was rendering #4e594f with text-decoration:none, on
// BOTH the region and country pages. Neither vs-live diff measured the back-link at all,
// which is why it survived; _probe-country-head-vs-live.mjs now covers it.
'.rd-light-link{ appearance:none; background:none; border:0; padding:0; margin:0; cursor:pointer;' +
' font:inherit; font-size:19.5312px; color:#4e594f; text-decoration:none; }' +
'.rd-light-link:hover{ text-decoration:underline; }' +
' font:inherit; font-size:19.5312px; color:#cbc5b9; font-weight:500;' +
' text-decoration:underline; text-decoration-thickness:2px; text-underline-offset:4px; }' +
'.rd-light-link:hover{ color:#d1d4cd; }' +
'.rd-light-link:focus-visible{ outline:2px solid var(--dx-accent); outline-offset:2px; border-radius:4px; }' +
// h1: _globals.scss clamp(--font-size-3xl, 7vw, --font-size-5xl) = clamp(47.6837px,_,74.5058px),
// heading family, line-height 1. cqw not vw -- see tab 1 for why.
@ -951,6 +961,7 @@ useShadowStyles(
:country-name="selectedCountry.name"
:pray-base-url="prayBaseUrl"
:language-code="languageCode"
:images-base="assetsBase + '/images'"
/>
</template>
</main>

View file

@ -386,8 +386,18 @@ useShadowStyles(
'.region-card__title{ margin:0; font-size:clamp(30.5176px, 4cqw, 47.6837px); line-height:1;' +
' font-family:"Bebas Neue","Arial Narrow",BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,sans-serif;' +
' font-weight:400; letter-spacing:normal; }' +
// Their link is an <a class="region-card__link | with-icon">, so it carries their `a` rule's
// font-weight: var(--font-weight-medium) = 500 (_globals.scss:132). Ours is a <button>
// because this element has no router, and `font:inherit` gave it 400 — MEASURED against
// their live /regions. Same class of miss as the dashboard back-link.
// The icon spacing is theirs too: .with-icon is inline-flex with align-items:baseline and NO
// gap (composition/_icon.scss:12), and the 1rem separation comes from
// `.with-icon .icon.right { margin-inline-start: 1rem }` — 10px at their 10px root. We had
// the same 10px via `gap`, which looks identical but means their rule would not apply, so
// the mechanism is now theirs: margin on the icon, gap left alone.
'.region-card__link{ appearance:none; background:none; border:0; padding:0; margin:0; text-align:left;' +
' cursor:pointer; color:inherit; font:inherit; display:inline-flex; align-items:baseline; gap:10px; }' +
' cursor:pointer; color:inherit; font:inherit; font-weight:500;' +
' display:inline-flex; align-items:baseline; }' +
'.region-card__link:hover{ color:#92b195; }' +
'.region-card__link:focus-visible{ outline:2px solid #fff; outline-offset:2px; }' +
// .region-card__icon: DX-life's own <svg class="icon | rotate-90 right"><use href="arrow-
@ -395,7 +405,8 @@ useShadowStyles(
// not a text glyph. Ported verbatim (fill:currentColor tracks the surrounding text colour,
// same as their `.icon{ fill:currentColor }` utility) and rotated 90deg to point right, same
// as their `rotate-90` class. getComputedStyle measured it at 33.38px square on the live page.
'.region-card__icon{ width:0.7em; height:0.7em; flex:none; fill:currentColor; transform:rotate(90deg); }' +
'.region-card__icon{ width:0.7em; height:0.7em; flex:none; fill:currentColor; transform:rotate(90deg);' +
' margin-inline-start:1rem; }' +
// .region-card__summary: --font-size-md (19.5312px), 0.85 opacity, on the header band.
'.region-card__summary{ font-size:19.5312px; opacity:0.85; margin:0; }' +
// .region-card__body: padding --spacing-lg / clamp(...) / --spacing-xl -> 23.5264px / clamp / 31.2901px
@ -412,8 +423,12 @@ useShadowStyles(
// <NuxtLink> text does -- a flex row with align-items:baseline pinned the bullet to the first
// line only and stranded the (count) span beside the second line on wrap. font-weight:500
// matches getComputedStyle() on the live country links (theirs is medium, not regular).
// Their country entries are bare <NuxtLink>s inside .countries-grid li — no class of their
// own — so they take their `a` rule: color var(--color-brand-light) = $color-green-400 =
// #4e594f, font-weight medium. MEASURED on their live /regions: rgb(78, 89, 79). Ours used
// var(--dx-text), which resolves to rgb(42, 51, 42) — the body ink, not their link ink.
'.country-link{ appearance:none; background:none; border:0; padding:2px 0; margin:0;' +
' text-align:left; cursor:pointer; color:var(--dx-text); font:inherit; font-size:19.5312px;' +
' text-align:left; cursor:pointer; color:#4e594f; font:inherit; font-size:19.5312px;' +
' font-weight:500; width:100%; position:relative; }' +
'.country-link::before{ content:""; position:absolute; left:-16px; top:0.6em; width:6px; height:6px;' +
' border-radius:50%; background:#92b195; }' +

View file

@ -55,6 +55,10 @@ const props = defineProps({
// Their perPage / morePerPage defaults (UupgsList.vue props block).
perPage: { type: Number, default: 24 },
morePerPage: { type: Number, default: 0 },
// Where worldmap.svg lives. THEIRS is a bare `const imagesUrl = '/assets/images'`
// (UupgsList.vue:73) because their app is served from one origin; ours must take it from the
// caller, since a dropped bundle resolves its assets relative to the tree it sits in.
imagesBase: { type: String, default: './assets/images' },
})
// Their field list, verbatim (UupgsList.vue:388).
@ -252,13 +256,22 @@ function profileUrl(p) { return `${props.researchUrl}${p.slug || ''}` }
// NO BACKTICKS in this string, including comments (house style: one terminates the literal).
useShadowStyles(
':host{ display:block; }' +
// The static half of their watermark. The URL itself is inline (it needs imagesBase at
// runtime); everything that does not depend on the base lives here.
'.ul-root{ display:flex; flex-direction:column; gap:17.689px;' +
' background-repeat:no-repeat; background-size:60%; background-position:top; min-height:400px;' +
' --dx-text:#2a332a; --dx-muted:#6d766e; --dx-white:#fff; color:var(--dx-text);' +
' font:19.5312px/1.5 Poppins,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif; }' +
// .filters — a .stack--md column
'.filters{ display:flex; flex-direction:column; gap:17.689px; }' +
// .search-box + input[type=search]: 100% wide, pill, text indented past the icon
'.search-box{ position:relative; width:100%; max-width:480px; margin-inline:auto; }' +
// .search-box is theirs at width:100% (blocks/_form.scss:115-118); the cap comes from the
// .max-width-md utility they compose onto it, which is `max-width: 50ch`
// (utilities/_sizes.scss:11). This was a hardcoded 480px — the wrong value AND the wrong
// UNIT: ch scales with the input's own font, px does not, so the box stopped tracking the
// type at every other size. MEASURED: theirs renders ~600px inside the 1200px container
// and shows the whole placeholder; ours truncated it at 480px.
'.search-box{ position:relative; width:100%; max-width:50ch; margin-inline:auto; }' +
'.search-box input{ box-sizing:border-box; width:100%; border:1px solid #666; border-radius:100px;' +
' background:var(--dx-white); padding:10px 23.5264px; text-indent:1.5em; font:inherit;' +
' font-size:19.5312px; color:var(--dx-text); }' +
@ -305,6 +318,14 @@ useShadowStyles(
'.uupg__country-link:hover{ text-decoration:underline; }' +
// theirs is display:none — the location line is fetched and deliberately not shown
// blocks/_cards.scss:258 — brand primary ground, white ink.
// THEIR .sr-only, utilities/_visibility.scss:2-12, verbatim. We already used their CLASS
// NAME on the search label — which is the right instinct under RULE 1 — but the RULE was
// never ported, so the class did nothing and the label rendered as visible text above the
// input, duplicating its own placeholder. Caught by reading the screenshot; every computed
// check passed, because a class that matches no rule is invisible to a property diff.
// Borrowing a class name only works if its declarations travel with it.
'.sr-only{ position:absolute; width:1px; height:1px; padding:0; margin:-1px;' +
' overflow:hidden; clip:rect(0, 0, 0, 0); white-space:nowrap; border-width:0; }' +
'.search-highlight{ background-color:#92b195; color:#fff; }' +
'.uupg__match{ margin:0; font-size:15.625px; color:var(--dx-muted); }' +
'.uupg__content{ display:none; grid-area:content; }' +
@ -333,7 +354,19 @@ useShadowStyles(
</script>
<template>
<div class="ul-root" :dir="isRTL ? 'rtl' : 'ltr'">
<!-- THEIR watermark, UupgsList.vue:451-454: the list root carries worldmap.svg as a
background-image, inline, with background-size 60% / background-position top /
min-height 400px, over their .bg-image class (_globals.scss:93) which supplies
background-repeat:no-repeat. MEASURED on their live /regions/cameroon: computed
background-size 60%, background-position 50% 0%, background-repeat no-repeat,
min-height 400px — so the inline size and position override .bg-image's cover/center,
and only no-repeat survives from the class. Reproduced exactly, with the URL taken from
imagesBase because a dropped bundle cannot assume an absolute /assets path. -->
<div
class="ul-root"
:dir="isRTL ? 'rtl' : 'ltr'"
:style="`background-image: url(${imagesBase}/worldmap.svg);`"
>
<div class="filters">
<div class="search-box">
<svg class="search-icon" viewBox="0 0 24 24" aria-hidden="true">

File diff suppressed because one or more lines are too long

402
public/assets/images/worldmap.svg vendored Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 304 KiB

File diff suppressed because one or more lines are too long

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <all-people-groups> custom element. -->
<script src="../all-people-groups.js" integrity="sha384-cqk7oshuPW5FdnbZ/DyfBBXN2FObAI+V1jrbxmZR2xzNiBtWG65PETQ5/w5PCDB2" crossorigin="anonymous"></script>
<script src="../all-people-groups.js" integrity="sha384-xyaOMJJGpMsUFLHhSnQZrXPkFyPr+TKDt8jwjowVbozX2w9CZP437dyKFaH2AOB3" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 304 KiB

File diff suppressed because one or more lines are too long

View file

@ -37,7 +37,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <bp-big-picture> custom element. -->
<script src="../../big-picture.js" integrity="sha384-v0b+aZ7TBxmgUIBBLdKEm6HzwjY3jAGyOFNsKeKCKY4EIRpiWRTcNLavAitHRt8h" crossorigin="anonymous"></script>
<script src="../../big-picture.js" integrity="sha384-voYmtWeACTFBJOOeqcbf5cuBKSjyskA89cjvm5qcvrx9IUFTAhLuICyRXUM6fL+Y" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -37,7 +37,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <bp-big-picture> custom element. -->
<script src="../../big-picture.js" integrity="sha384-v0b+aZ7TBxmgUIBBLdKEm6HzwjY3jAGyOFNsKeKCKY4EIRpiWRTcNLavAitHRt8h" crossorigin="anonymous"></script>
<script src="../../big-picture.js" integrity="sha384-voYmtWeACTFBJOOeqcbf5cuBKSjyskA89cjvm5qcvrx9IUFTAhLuICyRXUM6fL+Y" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -37,7 +37,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <bp-big-picture> custom element. -->
<script src="../big-picture.js" integrity="sha384-v0b+aZ7TBxmgUIBBLdKEm6HzwjY3jAGyOFNsKeKCKY4EIRpiWRTcNLavAitHRt8h" crossorigin="anonymous"></script>
<script src="../big-picture.js" integrity="sha384-voYmtWeACTFBJOOeqcbf5cuBKSjyskA89cjvm5qcvrx9IUFTAhLuICyRXUM6fL+Y" 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

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <cities-internet-map> custom element. -->
<script src="../cities-internet.js" integrity="sha384-tNig8gXdCocWVKD5iXR6iRqiAr7msWFtcFKzYif0L0G5i/RM+HI+SO8oR5c6O+5R" crossorigin="anonymous"></script>
<script src="../cities-internet.js" integrity="sha384-yXvole+EYjOppLtZOqOW4pba/oWzbObcdkoSpYcnukHuARdg6R/qHzhOd5cpCJY0" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <cities-internet-map> custom element. -->
<script src="../cities-internet.js" integrity="sha384-tNig8gXdCocWVKD5iXR6iRqiAr7msWFtcFKzYif0L0G5i/RM+HI+SO8oR5c6O+5R" crossorigin="anonymous"></script>
<script src="../cities-internet.js" integrity="sha384-yXvole+EYjOppLtZOqOW4pba/oWzbObcdkoSpYcnukHuARdg6R/qHzhOd5cpCJY0" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <cities-internet-map> custom element. -->
<script src="../cities-internet.js" integrity="sha384-tNig8gXdCocWVKD5iXR6iRqiAr7msWFtcFKzYif0L0G5i/RM+HI+SO8oR5c6O+5R" crossorigin="anonymous"></script>
<script src="../cities-internet.js" integrity="sha384-yXvole+EYjOppLtZOqOW4pba/oWzbObcdkoSpYcnukHuARdg6R/qHzhOd5cpCJY0" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <country-posters-map> custom element. -->
<script src="../country-posters.js" integrity="sha384-qf7vNfeaN6eW3IlrtzWdAGvwTADFPwwyyvj0OmLg9yTcYLsl7EHMTvrOvW/qM8B3" crossorigin="anonymous"></script>
<script src="../country-posters.js" integrity="sha384-mk3L38FZ9gEiv/eRg89RXFkn0yzzOw3uSoxZ4NFr2UUEgVecyCe07hI0tgUQPMWY" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -26,7 +26,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-qf7vNfeaN6eW3IlrtzWdAGvwTADFPwwyyvj0OmLg9yTcYLsl7EHMTvrOvW/qM8B3" crossorigin="anonymous"></script>
<script src="../country-posters.js" integrity="sha384-mk3L38FZ9gEiv/eRg89RXFkn0yzzOw3uSoxZ4NFr2UUEgVecyCe07hI0tgUQPMWY" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -40,7 +40,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <country-posters-map> custom element. -->
<script src="../country-posters.js" integrity="sha384-qf7vNfeaN6eW3IlrtzWdAGvwTADFPwwyyvj0OmLg9yTcYLsl7EHMTvrOvW/qM8B3" crossorigin="anonymous"></script>
<script src="../country-posters.js" integrity="sha384-mk3L38FZ9gEiv/eRg89RXFkn0yzzOw3uSoxZ4NFr2UUEgVecyCe07hI0tgUQPMWY" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -40,7 +40,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <dashboard-plus-grid> custom element. -->
<script src="../../dashboard-plus-grid.js" integrity="sha384-YbJgljynZ4t3/Ro44oHQy9ihl9/5o7j4IKts8MNRfA73Cb5cyD7U52DklXjzpLpG" crossorigin="anonymous"></script>
<script src="../../dashboard-plus-grid.js" integrity="sha384-q5UVHN5QptVZvJHqrqIFgRpWCj2HRQGiTAO/JYxf5OHmg6XegLjaBMk1AZXWqHRG" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -40,7 +40,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <dashboard-plus-grid> custom element. -->
<script src="../dashboard-plus-grid.js" integrity="sha384-YbJgljynZ4t3/Ro44oHQy9ihl9/5o7j4IKts8MNRfA73Cb5cyD7U52DklXjzpLpG" crossorigin="anonymous"></script>
<script src="../dashboard-plus-grid.js" integrity="sha384-q5UVHN5QptVZvJHqrqIFgRpWCj2HRQGiTAO/JYxf5OHmg6XegLjaBMk1AZXWqHRG" 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

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <demo-map> custom element. -->
<script src="../demo-map.js" integrity="sha384-QiUJUgeFn27tiHKVhAYtJuIWo+1z5xsCUP1Nj4m1H4cFUV3vUA7ADTP58Ky3oVtQ" crossorigin="anonymous"></script>
<script src="../demo-map.js" integrity="sha384-bdvQUz/ahi3yvFWY4niHIt4hJ/2Thd5T/6KP/mobZrtEKchO1XclRQQcc35jt9Cd" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -27,7 +27,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <demo-map> custom element. -->
<script src="../../demo-map.js" integrity="sha384-QiUJUgeFn27tiHKVhAYtJuIWo+1z5xsCUP1Nj4m1H4cFUV3vUA7ADTP58Ky3oVtQ" crossorigin="anonymous"></script>
<script src="../../demo-map.js" integrity="sha384-bdvQUz/ahi3yvFWY4niHIt4hJ/2Thd5T/6KP/mobZrtEKchO1XclRQQcc35jt9Cd" 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

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

View file

@ -27,7 +27,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <doxa-research-map> custom element. -->
<script src="../../doxa-research-map.js" integrity="sha384-oecoezttPmpRe5GNG/Yko6IkEbtLjCD7PD7qghU1ZigprnfLKhbf0eBEiEbE24iR" crossorigin="anonymous"></script>
<script src="../../doxa-research-map.js" integrity="sha384-CTfwl1rhm6JTKoUkSjawyQfHWYf55RBcwSDBYmVyQQ6f64Ag3v2dn5eV18yQSKwD" 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

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <doxa-map> custom element. -->
<script src="../../doxa-simple-map.js" integrity="sha384-hzEui48BqpW8VhRthz3daMgAdw4w4M3gtBre4ce4sXuAmS+39pMRW9reNAvpFb+W" crossorigin="anonymous"></script>
<script src="../../doxa-simple-map.js" integrity="sha384-edWUmiU1eWxE8Ju7FFg5PDfmw21E2NLoVaYmCgM8gXlm8S/9rowTJ7045NvdeIQA" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <doxa-map> custom element. -->
<script src="../../doxa-simple-map.js" integrity="sha384-hzEui48BqpW8VhRthz3daMgAdw4w4M3gtBre4ce4sXuAmS+39pMRW9reNAvpFb+W" crossorigin="anonymous"></script>
<script src="../../doxa-simple-map.js" integrity="sha384-edWUmiU1eWxE8Ju7FFg5PDfmw21E2NLoVaYmCgM8gXlm8S/9rowTJ7045NvdeIQA" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <doxa-map> custom element. -->
<script src="../doxa-simple-map.js" integrity="sha384-hzEui48BqpW8VhRthz3daMgAdw4w4M3gtBre4ce4sXuAmS+39pMRW9reNAvpFb+W" crossorigin="anonymous"></script>
<script src="../doxa-simple-map.js" integrity="sha384-edWUmiU1eWxE8Ju7FFg5PDfmw21E2NLoVaYmCgM8gXlm8S/9rowTJ7045NvdeIQA" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <doxa-map> custom element. -->
<script src="../../doxa-simple-map.js" integrity="sha384-hzEui48BqpW8VhRthz3daMgAdw4w4M3gtBre4ce4sXuAmS+39pMRW9reNAvpFb+W" crossorigin="anonymous"></script>
<script src="../../doxa-simple-map.js" integrity="sha384-edWUmiU1eWxE8Ju7FFg5PDfmw21E2NLoVaYmCgM8gXlm8S/9rowTJ7045NvdeIQA" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-4pOAnuuOovcKXSQANV9jnLu1ExxiwQMuC4aU5MtAsd959tYmdUj05u4tT57Z/rKI" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-uljHGYhda+DqMVTe8uCnYCfMNupgLezn47K71zOn+2H6hPaGpILlh/LtNU4wlqrY" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-4pOAnuuOovcKXSQANV9jnLu1ExxiwQMuC4aU5MtAsd959tYmdUj05u4tT57Z/rKI" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-uljHGYhda+DqMVTe8uCnYCfMNupgLezn47K71zOn+2H6hPaGpILlh/LtNU4wlqrY" 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

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-4pOAnuuOovcKXSQANV9jnLu1ExxiwQMuC4aU5MtAsd959tYmdUj05u4tT57Z/rKI" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-uljHGYhda+DqMVTe8uCnYCfMNupgLezn47K71zOn+2H6hPaGpILlh/LtNU4wlqrY" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-4pOAnuuOovcKXSQANV9jnLu1ExxiwQMuC4aU5MtAsd959tYmdUj05u4tT57Z/rKI" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-uljHGYhda+DqMVTe8uCnYCfMNupgLezn47K71zOn+2H6hPaGpILlh/LtNU4wlqrY" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

224
public/doxa-maps/key-cities/key-cities.js generated Normal file

File diff suppressed because one or more lines are too long

View file

@ -9,7 +9,7 @@
"bundle": "all-people-groups",
"scriptUrl": "./all-people-groups/all-people-groups.js",
"output": "doxa-maps/all-people-groups/all-people-groups.js",
"integrity": "sha384-cqk7oshuPW5FdnbZ/DyfBBXN2FObAI+V1jrbxmZR2xzNiBtWG65PETQ5/w5PCDB2",
"integrity": "sha384-xyaOMJJGpMsUFLHhSnQZrXPkFyPr+TKDt8jwjowVbozX2w9CZP437dyKFaH2AOB3",
"elements": [
"all-people-groups"
],
@ -25,7 +25,7 @@
"scriptUrl": "./all-people-groups/all-people-groups.js",
"embed": {
"iframe": "<iframe src=\"./all-people-groups/all-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=\"./all-people-groups/all-people-groups.js\" integrity=\"sha384-cqk7oshuPW5FdnbZ/DyfBBXN2FObAI+V1jrbxmZR2xzNiBtWG65PETQ5/w5PCDB2\" crossorigin=\"anonymous\"></script>\n<all-people-groups profile-config='{\"profile\":\"all-people-groups\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></all-people-groups>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./all-people-groups/all-people-groups.js\" integrity=\"sha384-xyaOMJJGpMsUFLHhSnQZrXPkFyPr+TKDt8jwjowVbozX2w9CZP437dyKFaH2AOB3\" crossorigin=\"anonymous\"></script>\n<all-people-groups profile-config='{\"profile\":\"all-people-groups\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></all-people-groups>"
},
"bundle": "all-people-groups"
}
@ -35,7 +35,7 @@
"bundle": "big-picture",
"scriptUrl": "./big-picture/big-picture.js",
"output": "doxa-maps/big-picture/big-picture.js",
"integrity": "sha384-v0b+aZ7TBxmgUIBBLdKEm6HzwjY3jAGyOFNsKeKCKY4EIRpiWRTcNLavAitHRt8h",
"integrity": "sha384-voYmtWeACTFBJOOeqcbf5cuBKSjyskA89cjvm5qcvrx9IUFTAhLuICyRXUM6fL+Y",
"elements": [
"bp-big-picture",
"bp-research-header",
@ -57,7 +57,7 @@
"scriptUrl": "./big-picture/big-picture.js",
"embed": {
"iframe": "<iframe src=\"./big-picture/big-picture/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=\"./big-picture/big-picture.js\" integrity=\"sha384-v0b+aZ7TBxmgUIBBLdKEm6HzwjY3jAGyOFNsKeKCKY4EIRpiWRTcNLavAitHRt8h\" crossorigin=\"anonymous\"></script>\n<bp-big-picture profile-config='{\"profile\":\"big-picture\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></bp-big-picture>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./big-picture/big-picture.js\" integrity=\"sha384-voYmtWeACTFBJOOeqcbf5cuBKSjyskA89cjvm5qcvrx9IUFTAhLuICyRXUM6fL+Y\" crossorigin=\"anonymous\"></script>\n<bp-big-picture profile-config='{\"profile\":\"big-picture\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></bp-big-picture>"
},
"instances": [
{
@ -101,7 +101,7 @@
"bundle": "cities-internet",
"scriptUrl": "./cities-internet/cities-internet.js",
"output": "doxa-maps/cities-internet/cities-internet.js",
"integrity": "sha384-tNig8gXdCocWVKD5iXR6iRqiAr7msWFtcFKzYif0L0G5i/RM+HI+SO8oR5c6O+5R",
"integrity": "sha384-yXvole+EYjOppLtZOqOW4pba/oWzbObcdkoSpYcnukHuARdg6R/qHzhOd5cpCJY0",
"elements": [
"cities-internet-map"
],
@ -117,7 +117,7 @@
"scriptUrl": "./cities-internet/cities-internet.js",
"embed": {
"iframe": "<iframe src=\"./cities-internet/connectivity-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=\"./cities-internet/cities-internet.js\" integrity=\"sha384-tNig8gXdCocWVKD5iXR6iRqiAr7msWFtcFKzYif0L0G5i/RM+HI+SO8oR5c6O+5R\" crossorigin=\"anonymous\"></script>\n<cities-internet-map profile-config='{\"profile\":\"connectivity-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></cities-internet-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./cities-internet/cities-internet.js\" integrity=\"sha384-yXvole+EYjOppLtZOqOW4pba/oWzbObcdkoSpYcnukHuARdg6R/qHzhOd5cpCJY0\" crossorigin=\"anonymous\"></script>\n<cities-internet-map profile-config='{\"profile\":\"connectivity-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></cities-internet-map>"
}
},
{
@ -131,7 +131,7 @@
"scriptUrl": "./cities-internet/cities-internet.js",
"embed": {
"iframe": "<iframe src=\"./cities-internet/connectivity-map/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=\"./cities-internet/cities-internet.js\" integrity=\"sha384-tNig8gXdCocWVKD5iXR6iRqiAr7msWFtcFKzYif0L0G5i/RM+HI+SO8oR5c6O+5R\" crossorigin=\"anonymous\"></script>\n<cities-internet-map profile-config='{\"profile\":\"connectivity-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></cities-internet-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./cities-internet/cities-internet.js\" integrity=\"sha384-yXvole+EYjOppLtZOqOW4pba/oWzbObcdkoSpYcnukHuARdg6R/qHzhOd5cpCJY0\" crossorigin=\"anonymous\"></script>\n<cities-internet-map profile-config='{\"profile\":\"connectivity-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></cities-internet-map>"
}
},
{
@ -145,7 +145,7 @@
"scriptUrl": "./cities-internet/cities-internet.js",
"embed": {
"iframe": "<iframe src=\"./cities-internet/data-tables/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=\"./cities-internet/cities-internet.js\" integrity=\"sha384-tNig8gXdCocWVKD5iXR6iRqiAr7msWFtcFKzYif0L0G5i/RM+HI+SO8oR5c6O+5R\" crossorigin=\"anonymous\"></script>\n<cities-internet-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></cities-internet-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./cities-internet/cities-internet.js\" integrity=\"sha384-yXvole+EYjOppLtZOqOW4pba/oWzbObcdkoSpYcnukHuARdg6R/qHzhOd5cpCJY0\" crossorigin=\"anonymous\"></script>\n<cities-internet-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></cities-internet-map>"
}
}
]
@ -154,7 +154,7 @@
"bundle": "country-posters",
"scriptUrl": "./country-posters/country-posters.js",
"output": "doxa-maps/country-posters/country-posters.js",
"integrity": "sha384-qf7vNfeaN6eW3IlrtzWdAGvwTADFPwwyyvj0OmLg9yTcYLsl7EHMTvrOvW/qM8B3",
"integrity": "sha384-mk3L38FZ9gEiv/eRg89RXFkn0yzzOw3uSoxZ4NFr2UUEgVecyCe07hI0tgUQPMWY",
"elements": [
"country-posters-map"
],
@ -174,7 +174,7 @@
"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": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-qf7vNfeaN6eW3IlrtzWdAGvwTADFPwwyyvj0OmLg9yTcYLsl7EHMTvrOvW/qM8B3\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"countries-map\",\"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-mk3L38FZ9gEiv/eRg89RXFkn0yzzOw3uSoxZ4NFr2UUEgVecyCe07hI0tgUQPMWY\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"countries-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
},
{
@ -188,21 +188,21 @@
"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-qf7vNfeaN6eW3IlrtzWdAGvwTADFPwwyyvj0OmLg9yTcYLsl7EHMTvrOvW/qM8B3\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-poster-wall\",\"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-mk3L38FZ9gEiv/eRg89RXFkn0yzzOw3uSoxZ4NFr2UUEgVecyCe07hI0tgUQPMWY\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
},
{
"profile": "country-posters-mfe",
"file": "country-posters-mfe.vue",
"description": "",
"element": "country-posters-map",
"description": "Country Posters as ONE two-tab element — the countries map and the printable",
"element": "country-posters-mfe",
"type": "nested-elements-mfe",
"isMap": true,
"iframeUrl": "./country-posters/country-posters-mfe/index.html",
"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": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-qf7vNfeaN6eW3IlrtzWdAGvwTADFPwwyyvj0OmLg9yTcYLsl7EHMTvrOvW/qM8B3\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"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-mk3L38FZ9gEiv/eRg89RXFkn0yzzOw3uSoxZ4NFr2UUEgVecyCe07hI0tgUQPMWY\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
}
]
@ -211,7 +211,7 @@
"bundle": "dashboard-plus-grid",
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
"output": "doxa-maps/dashboard-plus-grid/dashboard-plus-grid.js",
"integrity": "sha384-YbJgljynZ4t3/Ro44oHQy9ihl9/5o7j4IKts8MNRfA73Cb5cyD7U52DklXjzpLpG",
"integrity": "sha384-q5UVHN5QptVZvJHqrqIFgRpWCj2HRQGiTAO/JYxf5OHmg6XegLjaBMk1AZXWqHRG",
"elements": [
"dashboard-plus-grid"
],
@ -231,7 +231,7 @@
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
"embed": {
"iframe": "<iframe src=\"./dashboard-plus-grid/dashboard-plus-grid/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=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-YbJgljynZ4t3/Ro44oHQy9ihl9/5o7j4IKts8MNRfA73Cb5cyD7U52DklXjzpLpG\" crossorigin=\"anonymous\"></script>\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-q5UVHN5QptVZvJHqrqIFgRpWCj2HRQGiTAO/JYxf5OHmg6XegLjaBMk1AZXWqHRG\" crossorigin=\"anonymous\"></script>\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>"
},
"instances": [
{
@ -255,7 +255,7 @@
"bundle": "demo-map",
"scriptUrl": "./demo-map/demo-map.js",
"output": "doxa-maps/demo-map/demo-map.js",
"integrity": "sha384-QiUJUgeFn27tiHKVhAYtJuIWo+1z5xsCUP1Nj4m1H4cFUV3vUA7ADTP58Ky3oVtQ",
"integrity": "sha384-bdvQUz/ahi3yvFWY4niHIt4hJ/2Thd5T/6KP/mobZrtEKchO1XclRQQcc35jt9Cd",
"elements": [
"demo-map"
],
@ -271,7 +271,7 @@
"scriptUrl": "./demo-map/demo-map.js",
"embed": {
"iframe": "<iframe src=\"./demo-map/demo-map/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=\"./demo-map/demo-map.js\" integrity=\"sha384-QiUJUgeFn27tiHKVhAYtJuIWo+1z5xsCUP1Nj4m1H4cFUV3vUA7ADTP58Ky3oVtQ\" crossorigin=\"anonymous\"></script>\n<demo-map profile-config='{\"profile\":\"demo-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></demo-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./demo-map/demo-map.js\" integrity=\"sha384-bdvQUz/ahi3yvFWY4niHIt4hJ/2Thd5T/6KP/mobZrtEKchO1XclRQQcc35jt9Cd\" crossorigin=\"anonymous\"></script>\n<demo-map profile-config='{\"profile\":\"demo-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></demo-map>"
},
"instances": [
{
@ -349,7 +349,7 @@
"bundle": "doxa-research-map",
"scriptUrl": "./doxa-research-map/doxa-research-map.js",
"output": "doxa-maps/doxa-research-map/doxa-research-map.js",
"integrity": "sha384-oecoezttPmpRe5GNG/Yko6IkEbtLjCD7PD7qghU1ZigprnfLKhbf0eBEiEbE24iR",
"integrity": "sha384-CTfwl1rhm6JTKoUkSjawyQfHWYf55RBcwSDBYmVyQQ6f64Ag3v2dn5eV18yQSKwD",
"elements": [
"doxa-research-map"
],
@ -365,7 +365,7 @@
"scriptUrl": "./doxa-research-map/doxa-research-map.js",
"embed": {
"iframe": "<iframe src=\"./doxa-research-map/research-map/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=\"./doxa-research-map/doxa-research-map.js\" integrity=\"sha384-oecoezttPmpRe5GNG/Yko6IkEbtLjCD7PD7qghU1ZigprnfLKhbf0eBEiEbE24iR\" crossorigin=\"anonymous\"></script>\n<doxa-research-map profile-config='{\"profile\":\"research-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-research-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-research-map/doxa-research-map.js\" integrity=\"sha384-CTfwl1rhm6JTKoUkSjawyQfHWYf55RBcwSDBYmVyQQ6f64Ag3v2dn5eV18yQSKwD\" crossorigin=\"anonymous\"></script>\n<doxa-research-map profile-config='{\"profile\":\"research-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-research-map>"
},
"instances": [
{
@ -391,7 +391,7 @@
"bundle": "doxa-simple-map",
"scriptUrl": "./doxa-simple-map/doxa-simple-map.js",
"output": "doxa-maps/doxa-simple-map/doxa-simple-map.js",
"integrity": "sha384-hzEui48BqpW8VhRthz3daMgAdw4w4M3gtBre4ce4sXuAmS+39pMRW9reNAvpFb+W",
"integrity": "sha384-edWUmiU1eWxE8Ju7FFg5PDfmw21E2NLoVaYmCgM8gXlm8S/9rowTJ7045NvdeIQA",
"elements": [
"doxa-map",
"doxa-simple-map"
@ -408,7 +408,7 @@
"scriptUrl": "./doxa-simple-map/doxa-simple-map.js",
"embed": {
"iframe": "<iframe src=\"./doxa-simple-map/doxa-simple-map/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=\"./doxa-simple-map/doxa-simple-map.js\" integrity=\"sha384-hzEui48BqpW8VhRthz3daMgAdw4w4M3gtBre4ce4sXuAmS+39pMRW9reNAvpFb+W\" crossorigin=\"anonymous\"></script>\n<doxa-map profile-config='{\"profile\":\"doxa-simple-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-simple-map/doxa-simple-map.js\" integrity=\"sha384-edWUmiU1eWxE8Ju7FFg5PDfmw21E2NLoVaYmCgM8gXlm8S/9rowTJ7045NvdeIQA\" crossorigin=\"anonymous\"></script>\n<doxa-map profile-config='{\"profile\":\"doxa-simple-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-map>"
},
"instances": [
{
@ -591,7 +591,7 @@
"bundle": "gospel-resources",
"scriptUrl": "./gospel-resources/gospel-resources.js",
"output": "doxa-maps/gospel-resources/gospel-resources.js",
"integrity": "sha384-4pOAnuuOovcKXSQANV9jnLu1ExxiwQMuC4aU5MtAsd959tYmdUj05u4tT57Z/rKI",
"integrity": "sha384-uljHGYhda+DqMVTe8uCnYCfMNupgLezn47K71zOn+2H6hPaGpILlh/LtNU4wlqrY",
"elements": [
"gospel-resources-map"
],
@ -607,7 +607,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/charts/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=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-4pOAnuuOovcKXSQANV9jnLu1ExxiwQMuC4aU5MtAsd959tYmdUj05u4tT57Z/rKI\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"charts\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-uljHGYhda+DqMVTe8uCnYCfMNupgLezn47K71zOn+2H6hPaGpILlh/LtNU4wlqrY\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"charts\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
},
{
@ -621,7 +621,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/data-tables/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=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-4pOAnuuOovcKXSQANV9jnLu1ExxiwQMuC4aU5MtAsd959tYmdUj05u4tT57Z/rKI\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-uljHGYhda+DqMVTe8uCnYCfMNupgLezn47K71zOn+2H6hPaGpILlh/LtNU4wlqrY\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
},
{
@ -635,7 +635,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/resources-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=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-4pOAnuuOovcKXSQANV9jnLu1ExxiwQMuC4aU5MtAsd959tYmdUj05u4tT57Z/rKI\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-uljHGYhda+DqMVTe8uCnYCfMNupgLezn47K71zOn+2H6hPaGpILlh/LtNU4wlqrY\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
},
{
@ -649,7 +649,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/resources-map/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=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-4pOAnuuOovcKXSQANV9jnLu1ExxiwQMuC4aU5MtAsd959tYmdUj05u4tT57Z/rKI\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-uljHGYhda+DqMVTe8uCnYCfMNupgLezn47K71zOn+2H6hPaGpILlh/LtNU4wlqrY\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
}
]
@ -658,7 +658,7 @@
"bundle": "my-upg-100-list",
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"output": "doxa-maps/my-upg-100-list/my-upg-100-list.js",
"integrity": "sha384-9MM9Wm9yP7JwtlWBL0+xuJ2yHwHD/trEHYrsk0kEKgR4pXXdTNguIE50TqRCUbK2",
"integrity": "sha384-/g1IZXqStjHu34i4B12LQdGpK965qFY0vSThdph2gKrVqmtl4NTFdzh5IvJptHHV",
"elements": [
"my-upg-100-list-map"
],
@ -678,7 +678,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-9MM9Wm9yP7JwtlWBL0+xuJ2yHwHD/trEHYrsk0kEKgR4pXXdTNguIE50TqRCUbK2\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-/g1IZXqStjHu34i4B12LQdGpK965qFY0vSThdph2gKrVqmtl4NTFdzh5IvJptHHV\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -692,7 +692,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/upg-100-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-9MM9Wm9yP7JwtlWBL0+xuJ2yHwHD/trEHYrsk0kEKgR4pXXdTNguIE50TqRCUbK2\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-/g1IZXqStjHu34i4B12LQdGpK965qFY0vSThdph2gKrVqmtl4NTFdzh5IvJptHHV\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -706,7 +706,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/upg-100-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-9MM9Wm9yP7JwtlWBL0+xuJ2yHwHD/trEHYrsk0kEKgR4pXXdTNguIE50TqRCUbK2\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-/g1IZXqStjHu34i4B12LQdGpK965qFY0vSThdph2gKrVqmtl4NTFdzh5IvJptHHV\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
}
]
@ -856,7 +856,7 @@
"bundle": "regions-dashboard",
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"output": "doxa-maps/regions-dashboard/regions-dashboard.js",
"integrity": "sha384-tj7QLhUCvAluRlp9Bp2ddjbXLcknRx2v1nMotvvY8XKImLplx6WkSdHh5MQC1Rix",
"integrity": "sha384-r0Xo6MLumWczZhDLa+U3zlxf4Wal/ZOW5zlgQiOC15aIH20NaY2RCYf1GyWKwRiG",
"elements": [
"regions-dashboard"
],
@ -876,7 +876,7 @@
"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": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-tj7QLhUCvAluRlp9Bp2ddjbXLcknRx2v1nMotvvY8XKImLplx6WkSdHh5MQC1Rix\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"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-r0Xo6MLumWczZhDLa+U3zlxf4Wal/ZOW5zlgQiOC15aIH20NaY2RCYf1GyWKwRiG\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
@ -890,7 +890,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-tj7QLhUCvAluRlp9Bp2ddjbXLcknRx2v1nMotvvY8XKImLplx6WkSdHh5MQC1Rix\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"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-r0Xo6MLumWczZhDLa+U3zlxf4Wal/ZOW5zlgQiOC15aIH20NaY2RCYf1GyWKwRiG\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
@ -904,7 +904,7 @@
"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": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-tj7QLhUCvAluRlp9Bp2ddjbXLcknRx2v1nMotvvY8XKImLplx6WkSdHh5MQC1Rix\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"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-r0Xo6MLumWczZhDLa+U3zlxf4Wal/ZOW5zlgQiOC15aIH20NaY2RCYf1GyWKwRiG\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
}
]
@ -913,7 +913,7 @@
"bundle": "research-dashboard",
"scriptUrl": "./research-dashboard/research-dashboard.js",
"output": "doxa-maps/research-dashboard/research-dashboard.js",
"integrity": "sha384-VvOYWBcDd7NtnB1eveECKX88ZHIpGnOf79tVdCUqGZzXLgoZPc+oTTPIC3ajaYsn",
"integrity": "sha384-cMZfw0g3/v0hHkyHQhHYiv9GeD7hvFaUD0qF/G3FowqUNjgDykvI+btwOIu/p6Qy",
"elements": [
"research-dashboard-map"
],
@ -929,7 +929,7 @@
"scriptUrl": "./research-dashboard/research-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./research-dashboard/research-dashboard/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=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-VvOYWBcDd7NtnB1eveECKX88ZHIpGnOf79tVdCUqGZzXLgoZPc+oTTPIC3ajaYsn\" crossorigin=\"anonymous\"></script>\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-cMZfw0g3/v0hHkyHQhHYiv9GeD7hvFaUD0qF/G3FowqUNjgDykvI+btwOIu/p6Qy\" crossorigin=\"anonymous\"></script>\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>"
},
"bundle": "research-dashboard"
}
@ -1027,7 +1027,7 @@
"bundle": "template-bundle",
"scriptUrl": "./template-bundle/template-bundle.js",
"output": "doxa-maps/template-bundle/template-bundle.js",
"integrity": "sha384-k+G5UlkZ99QmuecCCWUrjz998JBJnQT3hsDG0A+IVmiX9F3CNswmHXXzYhjnUTDX",
"integrity": "sha384-4YT4Amt8yc0KANs5xlODSxpkWKYgWWCWd9B0CNiHCZebzvGbXp4fS+wYtPbqJJx7",
"elements": [
"template-bundle"
],
@ -1043,7 +1043,7 @@
"scriptUrl": "./template-bundle/template-bundle.js",
"embed": {
"iframe": "<iframe src=\"./template-bundle/template-map-a/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=\"./template-bundle/template-bundle.js\" integrity=\"sha384-k+G5UlkZ99QmuecCCWUrjz998JBJnQT3hsDG0A+IVmiX9F3CNswmHXXzYhjnUTDX\" crossorigin=\"anonymous\"></script>\n<template-bundle profile-config='{\"profile\":\"template-map-a\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></template-bundle>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./template-bundle/template-bundle.js\" integrity=\"sha384-4YT4Amt8yc0KANs5xlODSxpkWKYgWWCWd9B0CNiHCZebzvGbXp4fS+wYtPbqJJx7\" crossorigin=\"anonymous\"></script>\n<template-bundle profile-config='{\"profile\":\"template-map-a\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></template-bundle>"
},
"bundle": "template-bundle"
},
@ -1058,7 +1058,7 @@
"scriptUrl": "./template-bundle/template-bundle.js",
"embed": {
"iframe": "<iframe src=\"./template-bundle/template-map-b/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=\"./template-bundle/template-bundle.js\" integrity=\"sha384-k+G5UlkZ99QmuecCCWUrjz998JBJnQT3hsDG0A+IVmiX9F3CNswmHXXzYhjnUTDX\" crossorigin=\"anonymous\"></script>\n<template-bundle profile-config='{\"profile\":\"template-map-b\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></template-bundle>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./template-bundle/template-bundle.js\" integrity=\"sha384-4YT4Amt8yc0KANs5xlODSxpkWKYgWWCWd9B0CNiHCZebzvGbXp4fS+wYtPbqJJx7\" crossorigin=\"anonymous\"></script>\n<template-bundle profile-config='{\"profile\":\"template-map-b\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></template-bundle>"
},
"bundle": "template-bundle"
}

File diff suppressed because one or more lines are too long

View file

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

View file

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

View file

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

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <regions-dashboard> custom element. -->
<script src="../regions-dashboard.js" integrity="sha384-tj7QLhUCvAluRlp9Bp2ddjbXLcknRx2v1nMotvvY8XKImLplx6WkSdHh5MQC1Rix" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-r0Xo6MLumWczZhDLa+U3zlxf4Wal/ZOW5zlgQiOC15aIH20NaY2RCYf1GyWKwRiG" 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

@ -29,7 +29,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-tj7QLhUCvAluRlp9Bp2ddjbXLcknRx2v1nMotvvY8XKImLplx6WkSdHh5MQC1Rix" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-r0Xo6MLumWczZhDLa+U3zlxf4Wal/ZOW5zlgQiOC15aIH20NaY2RCYf1GyWKwRiG" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -40,7 +40,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <regions-dashboard> custom element. -->
<script src="../regions-dashboard.js" integrity="sha384-tj7QLhUCvAluRlp9Bp2ddjbXLcknRx2v1nMotvvY8XKImLplx6WkSdHh5MQC1Rix" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-r0Xo6MLumWczZhDLa+U3zlxf4Wal/ZOW5zlgQiOC15aIH20NaY2RCYf1GyWKwRiG" 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

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <research-dashboard-map> custom element. -->
<script src="../research-dashboard.js" integrity="sha384-VvOYWBcDd7NtnB1eveECKX88ZHIpGnOf79tVdCUqGZzXLgoZPc+oTTPIC3ajaYsn" crossorigin="anonymous"></script>
<script src="../research-dashboard.js" integrity="sha384-cMZfw0g3/v0hHkyHQhHYiv9GeD7hvFaUD0qF/G3FowqUNjgDykvI+btwOIu/p6Qy" 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

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <template-bundle> custom element. -->
<script src="../template-bundle.js" integrity="sha384-k+G5UlkZ99QmuecCCWUrjz998JBJnQT3hsDG0A+IVmiX9F3CNswmHXXzYhjnUTDX" crossorigin="anonymous"></script>
<script src="../template-bundle.js" integrity="sha384-4YT4Amt8yc0KANs5xlODSxpkWKYgWWCWd9B0CNiHCZebzvGbXp4fS+wYtPbqJJx7" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <template-bundle> custom element. -->
<script src="../template-bundle.js" integrity="sha384-k+G5UlkZ99QmuecCCWUrjz998JBJnQT3hsDG0A+IVmiX9F3CNswmHXXzYhjnUTDX" crossorigin="anonymous"></script>
<script src="../template-bundle.js" integrity="sha384-4YT4Amt8yc0KANs5xlODSxpkWKYgWWCWd9B0CNiHCZebzvGbXp4fS+wYtPbqJJx7" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order: