Merge remote-tracking branch 'origin/main' into bundler-1/work

This commit is contained in:
Doxa Maps 2026-09-28 01:51:14 +00:00
commit 3f384aef50
20 changed files with 104 additions and 63 deletions

View file

@ -1,16 +1,41 @@
# Mapbox token used in dev. Production hosts pass the token via profile-config.tk
# on the host page; never bake into the IIFE bundle.
VITE_MAPBOX_TOKEN=pk.your_dev_token_here
# .env.example — every local setting, each shown with its DEFAULT.
# A fresh clone needs NONE of this: `bun run dev` works with no .env at all. To change something, copy
# this file to .env (or .env.local, which wins; both are gitignored) and edit only the lines you need.
# An empty value means "use the default".
# ── Maps ─────────────────────────────────────────────────────────────────────────────────────────
# A Mapbox public token (starts with pk.) for the map backgrounds. Empty = no Mapbox background; set
# "provider": "maplibre" on a plugin (or ?provider=maplibre on a page) to draw with MapLibre, no key.
# Production hosts pass the token through profile-config.tk; never bake it into a bundle.
VITE_MAPBOX_TOKEN=
# The data API the maps read when a plugin's profile does not name one (profile apiBaseUrl and a host
# page's window.MAP_APP_API_URL come first). This is the value the maps are built against.
VITE_API_BASE_URL=https://pray.doxa.life
# Follow a shared branch while `bun run dev` runs (internal/dev-sync-plugin.mjs): fetch every N seconds and
# fast-forward when this checkout is on that branch with no local edits; otherwise only report it at
# /api/dev-sync. DX_SYNC_REMOTE is a remote name (origin) or a repo URL; leave it unset to turn this off.
# DX_SYNC_REMOTE=origin
# DX_SYNC_BRANCH=main
# DX_SYNC_INTERVAL=5
# ── Hot reload from a shared branch (internal/dev-sync-plugin.mjs) ───────────────────────────────
# Empty = OFF: the dev server hot-reloads YOUR local edits only (the default).
# Set to a remote name (origin) or a repo URL (https://…/repo.git) and `bun run dev` fetches every few
# seconds and fast-forwards when this checkout is on that branch with no local edits or commits; otherwise
# it only reports "main is N commits ahead" (in the log and at /api/dev-sync). It never merges over your work.
DX_SYNC_REMOTE=
# The branch to follow. Empty = main.
DX_SYNC_BRANCH=
# Seconds between checks. Empty = 5 (minimum 2).
DX_SYNC_INTERVAL=
# PocketBase for plugins (internal/backend-dev-plugin.mjs): `bun run dev` downloads the pinned binary once
# and serves it at /api/pb, data in .pb/dev. DX_PB_URL uses a shared PocketBase instead of a local one.
# DX_PB_PORT=8090
# DX_PB_URL=
# ── PocketBase, the backend for plugins (internal/backend-dev-plugin.mjs) ────────────────────────
# Empty = a LOCAL PocketBase: `bun run dev` downloads the pinned binary once (checksum-verified) and
# serves it at /api/pb, admin UI /api/pb/_/, data in .pb/dev (gitignored). Nothing leaves this computer.
# Set to a PocketBase root (e.g. https://<your team's dev server>/pb) to use a shared team one instead.
DX_PB_URL=
# The local PocketBase's port. Empty = 8090 (change it only if the log says the port is in use).
DX_PB_PORT=
# ── Rudder, voice to text (backend/rudder-engine) ────────────────────────────────────────────────
# These are read from the SHELL ENVIRONMENT, not from this file (e.g. `RUDDER_PORT=6193 bun run dev`).
# Rudder runs when its engine is built: install Go 1.22+ and run `bash backend/rudder-engine/setup-runtime.sh`.
# RUDDER_ENGINE 0 = never start the engine here (default: start it if it is built)
# RUDDER_PORT the engine's port (default 5193)
# RUDDER_NEMO_PORT the speech server's port (default 5194)
# RUDDER_HOME where the runtime and model live (default ~/.local/share/rudder)
# RUDDER_LANG the default language (default en-US)

View file

@ -4,6 +4,8 @@ Made by Vibe Coders for Vibe Coders to prepare the way of the Lord and make His
**Isaiah 40:3 “...Prepare the way for the LORD in the wilderness; make a straight highway for our God in the desert."**
Built with love, with the prayer that these maps bless the nations.
# dx-maps — one build, maps that embed everywhere
**Write a map once in `plugin-designs/<your-map>/`, run one build, and drop it on any site** —
@ -646,13 +648,14 @@ a higher-capability plugin from them — that's how the Research Gallery was bui
You need **git**, **[Bun](https://bun.sh)** and **Node ≥ 18**, plus a free
**[Mapbox](https://account.mapbox.com) public token** (it starts with `pk.`) so the maps have a
background.
background. For Rudder's voice engine, also **[Go](https://go.dev/dl/) 1.22+**, then run
`bash backend/rudder-engine/setup-runtime.sh` once; without Go, everything except voice works.
```bash
git clone https://git.nuxtbase.app/doxa-open/doxa-maps.git
git clone --depth 1 https://git.nuxtbase.app/doxa-open/doxa-maps.git # latest code only: seconds, not hundreds of MB of history
cd doxa-maps
bun install --frozen-lockfile
cp .env.example .env # then paste your pk. token after VITE_MAPBOX_TOKEN=
cp .env.example .env # optional: paste your pk. token after VITE_MAPBOX_TOKEN=
bun run dev # → http://localhost:5173/ is the Plugin Studio
```
@ -705,8 +708,9 @@ The studio is a plugin like any other: `plugin-designs/plugin-studio/plugin-stud
their browser within seconds, with no rebuild. Add OIDC settings and it puts a "Sign in with *your
provider*" page in front of everything, open only to the groups you allow. Recipe and settings:
[deployment/cloud/](./deployment/cloud/README.md).
Working from your own laptop alongside the team (following the shared branch, the team's PocketBase):
[documentation/HOWTO-join-the-table.md](./documentation/HOWTO-join-the-table.md).
Working from your own laptop alongside the team (zero config, everything local by default):
[documentation/HOWTO-join-the-table.md](./documentation/HOWTO-join-the-table.md). When your agent runs on a
server instead: [documentation/CLOUD-DEVELOPMENT-ENVIRONMENT.md](./documentation/CLOUD-DEVELOPMENT-ENVIRONMENT.md).
---

View file

@ -24,6 +24,7 @@
"props": {
"profile": "board",
"view": "province",
"panel": "map",
"urlState": "query"
}
},

View file

@ -85,6 +85,9 @@ const back = M.buildQuery({ view: 'zero', filterSet: { band: ['yes', 'partial'],
ok(back.includes('lang=ar') && back.includes('list=700') && back.includes('band=yes%7Cpartial') && back.includes('view=zero'),
`query builds and keeps lang/list: ${back}`)
ok(M.parseQuery('?view=nonsense').view === 'board', 'an unknown view falls back to board')
// the tree is the default panel: a bare URL names no panel, only the map is written, both are read back
ok(M.parseQuery('').panel === '' && M.parseQuery('?panel=map').panel === 'map' && M.parseQuery('?panel=tree').panel === 'tree'
&& M.buildQuery({ panel: 'map' }) === 'panel=map' && M.buildQuery({ panel: 'tree' }) === '', 'the tree is the default panel; ?panel=map restores the map')
// embed-contract parity with Gospel Resources: ?groups= (peoples by slug) and ?codes= / ?code= (languages)
const pg = M.parseQuery('?groups=abai-sungai,hadrami-arabs&codes=abf,ayh')
ok(pg.groups.length === 2 && Array.isArray(pg.filters.language) && pg.filters.language.join('|') === 'abf|ayh', 'parses ?groups= (slugs) and ?codes= (languages), comma-separated as Gospel Resources writes them')

View file

@ -50,7 +50,7 @@ try {
const res = T('gospel-internet-resources.json')
const open = rows.find((r) => r.access_detail === 'none' && r.province) || rows[0]
async function render(lang) {
async function render(lang, extra = { legend: 'open' }) {
const app = createSSRApp({
setup() {
const b = useBoard()
@ -75,7 +75,7 @@ try {
const appI18n = i18n.createAppI18n()
app.use(appI18n)
appI18n.global.locale.value = lang
app.provide('profileConfig', ref({ profile: 'board', lang }))
app.provide('profileConfig', ref({ profile: 'board', lang, ...extra })) // legends start collapsed; the content checks open them
const errors = []
app.config.errorHandler = (e) => { errors.push(String(e && e.stack || e)) }
app.config.warnHandler = (m) => { if (/Unhandled error|Property .* was accessed during render but is not defined/.test(m)) errors.push(m) }
@ -84,6 +84,10 @@ try {
}
const en = await render('en')
// the Driver's default (2026-09-28): with no knob both legends start collapsed behind their "Legend" button
const shut = await render('en', {})
ok(!/data-tree-legend|class="gim-legend"/.test(shut.html) && /class="gtr-min"/.test(shut.html) && /class="gim-legend-min"/.test(shut.html),
'en: with no knob, the tree and map legends start collapsed')
ok(en.errors.length === 0, `en: every panel rendered with no error (${en.errors.length}${en.errors[0] ? ': ' + en.errors[0].slice(0, 160) : ''})`)
for (const [name, re] of [['GiFacetRail', /data-facet="access"/], ['GiGrid', /data-grid-total/], ['GiCharts', /data-region="charts"/],
['GiTree', /data-tree-legend[\s\S]*data-tree-poster/], ['GiResources', /data-resources-total/], ['GiMap', /data-region="map"/]]) ok(re.test(en.html), `en: ${name} rendered its region`)

View file

@ -103,9 +103,10 @@ useShadowStyles(
'.gic2{grid-area:combos;display:flex;align-items:center;gap:10px;padding:6px 14px;background:#fff;border-bottom:1px solid #d1d4cd;' +
'min-width:0;font:12.5px/1.3 Roboto,-apple-system,"Segoe UI",sans-serif;color:#3b463d}' +
'.gic2-h{flex:none;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:#6d766e}' +
// The selection side is BOUNDED and clips: its nowrap placeholder ran under "Try a combination" at 1280
// and 1440 (rega r82). It now ellipsizes; the full text stays in the title tooltip.
'.gic2-sel{display:flex;align-items:center;gap:6px;min-width:0;flex:0 1 auto;max-width:40%;overflow:hidden}' +
// The selection side is BOUNDED at 40% (rega r82: the placeholder ran under "Try a combination"), but only
// its chips and placeholder clip: they scroll or ellipsize. No overflow here and no min-width:0, so the
// flex:none label sets the minimum width and is never cut ('YOUR S…' at 390, the zh/ru/hi/ar labels at 1280).
'.gic2-sel{display:flex;align-items:center;gap:6px;flex:0 1 auto;max-width:40%}' +
'.gic2-none{color:#9aa19b;font-style:italic;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}' +
'.gic2-try{display:flex;align-items:center;gap:6px;min-width:0;flex:1 1 auto;overflow-x:auto;scrollbar-width:thin}' +
'.gic2-c{flex:none;display:inline-flex;align-items:center;gap:6px;border:1px solid #d1d4cd;background:#f3f3f1;color:#3b463d;border-radius:999px;' +

View file

@ -44,7 +44,8 @@ const ready = ref(false)
// Province shading: 'zero' = groups with nothing found in their own language (from the rows in scope),
// 'women' / 'men' = NFHS-5 ever used the internet (India only; China has no verified provincial source).
const provinceMode = ref('zero')
const legendOpen = ref(true)
// the Driver: legends start collapsed, one tap on "Legend" opens them; the embed knob legend:"open" opens them
const legendOpen = ref(board.profileConfig.value?.legend === 'open')
let unmounted = false
let adm1Table = null // { [shapeName]: { women, men } } India, NFHS-5
const nfhsAttribution = ref('')
@ -313,8 +314,6 @@ onMounted(async () => {
// resize the canvas too, or it stretches the old bitmap.
let ro = null
onMounted(() => {
// A phone opens on the map, not on its legend: at 390px the card covered most of the map (rega r75).
if (mapEl.value && mapEl.value.clientWidth && mapEl.value.clientWidth < 520) legendOpen.value = false
if (mapEl.value && typeof ResizeObserver !== 'undefined') {
ro = new ResizeObserver(() => { try { mapRef.value && mapRef.value.resize() } catch (_) {} })
ro.observe(mapEl.value)

View file

@ -43,7 +43,8 @@ const mapRef = shallowRef(null)
const err = ref('')
const ready = ref(false)
const hoverId = ref('')
const legendOpen = ref(true)
// the Driver: legends start collapsed, one tap on "Legend" opens them; the embed knob legend:"open" opens them
const legendOpen = ref(board.profileConfig.value?.legend === 'open')
let unmounted = false
let ro = null
@ -242,7 +243,6 @@ async function build() {
} catch (_) {}
}
onMounted(() => {
if (el.value && el.value.clientWidth && el.value.clientWidth < 520) legendOpen.value = false // a phone opens on the tree
if (el.value && typeof ResizeObserver !== 'undefined') {
// the engines only follow WINDOW resizes; a dragged rail or an un-hidden panel must resize the canvas
ro = new ResizeObserver(() => { try { mapRef.value && mapRef.value.resize() } catch (_) {} })

View file

@ -104,7 +104,8 @@ export function parseQuery(search) {
const codes = [...list('codes'), ...list('code')].filter((c) => /^[a-z]{3}$/.test(c))
if (codes.length && !filters.language) filters.language = codes.length === 1 ? codes[0] : codes
const groups = list('groups').filter((s) => /^[a-z0-9-]+$/.test(s))
const panel = q.get('panel') === 'tree' ? 'tree' : 'map'
// '' = not in the URL: the board opens on its default (the language tree, the Driver 2026-09-28)
const panel = ['tree', 'map'].includes(q.get('panel')) ? q.get('panel') : ''
const tree = /^[a-z0-9-]{3,40}$/.test(q.get('tree') || '') ? q.get('tree') : ''
// A tree node narrows by LANGUAGE (its ISO codes); the URL carries the node, not the code list.
if (tree) delete filters.language
@ -118,7 +119,7 @@ export function buildQuery({ view, filterSet, group, keep, panel, tree, filters
// delete nor write them, so the two writers never fight over one address bar
for (const name of [...(filters ? Object.keys(URL_KEYS) : []), 'view', 'group', 'panel', 'tree']) q.delete(name)
if (view && view !== 'board') q.set('view', view)
if (panel === 'tree') q.set('panel', 'tree')
if (panel === 'map') q.set('panel', 'map') // the tree is the default, so only the map is written
if (tree) q.set('tree', tree)
if (filters) for (const [name, key] of Object.entries(URL_KEYS)) {
if (tree && key === 'language') continue

View file

@ -37,7 +37,7 @@ export function useBoard() {
const sort = ref({ key: 'population', dir: -1 })
const openSlug = ref('') // the group in the detail drawer ('' = closed)
// ── the centre panel: the geographic map or the language tree (loaded on first use) ───────────────
const centre = ref('map')
const centre = ref('tree') // the Driver: people come for the language tree; the map is one tap away
const tree = shallowRef(null) // indexTree(doc) + { meta }
const resources = shallowRef(null) // { meta, rows } — gospel links for the board's languages
const treeNode = ref('') // the tree node the board is narrowed to ('' = none)
@ -180,7 +180,8 @@ export function useBoard() {
if (codes) bus.setFilter('language', codes)
const group = q.group || cfg().group || ''
if (group) pendingGroup = group
const panel = q.panel === 'tree' || cfg().panel === 'tree' ? 'tree' : 'map'
// the URL wins, then the embed knob (profile-config panel: 'map'), then the default: the tree
const panel = q.panel || (cfg().panel === 'map' ? 'map' : 'tree')
if (q.tree) pendingTree = q.tree
if (q.groups && q.groups.length) pendingSelection = q.groups
setCentre(panel)

View file

@ -604,7 +604,7 @@
"bundle": "gospel-internet",
"scriptUrl": "./gospel-internet/gospel-internet.js",
"output": "dx-maps/gospel-internet/gospel-internet.js",
"integrity": "sha384-1QKATO2zc5eFQVqHLIMkyHx2RcXSpvb2U/+1i2wyQFAy9WQPCR449qwFFu1+8S/Y",
"integrity": "sha384-y/ti76gIc9CO7C0Q74z8teaxCKsB5xbb5sk+aDVBgZLecERoSaFhc+brdokaOTIb",
"elements": [
"gospel-internet-board"
],
@ -623,7 +623,7 @@
"scriptUrl": "./gospel-internet/gospel-internet.js",
"embed": {
"iframe": "<iframe src=\"./gospel-internet/board/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-1QKATO2zc5eFQVqHLIMkyHx2RcXSpvb2U/+1i2wyQFAy9WQPCR449qwFFu1+8S/Y\" crossorigin=\"anonymous\"></script>\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-y/ti76gIc9CO7C0Q74z8teaxCKsB5xbb5sk+aDVBgZLecERoSaFhc+brdokaOTIb\" crossorigin=\"anonymous\"></script>\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
},
"instances": [
{
@ -662,6 +662,7 @@
"props": {
"profile": "board",
"view": "province",
"panel": "map",
"urlState": "query"
},
"element": "gospel-internet-board",

View file

@ -36,7 +36,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-1QKATO2zc5eFQVqHLIMkyHx2RcXSpvb2U/+1i2wyQFAy9WQPCR449qwFFu1+8S/Y" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-y/ti76gIc9CO7C0Q74z8teaxCKsB5xbb5sk+aDVBgZLecERoSaFhc+brdokaOTIb" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -36,7 +36,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../gospel-internet.js" integrity="sha384-1QKATO2zc5eFQVqHLIMkyHx2RcXSpvb2U/+1i2wyQFAy9WQPCR449qwFFu1+8S/Y" crossorigin="anonymous"></script>
<script src="../gospel-internet.js" integrity="sha384-y/ti76gIc9CO7C0Q74z8teaxCKsB5xbb5sk+aDVBgZLecERoSaFhc+brdokaOTIb" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -36,7 +36,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-1QKATO2zc5eFQVqHLIMkyHx2RcXSpvb2U/+1i2wyQFAy9WQPCR449qwFFu1+8S/Y" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-y/ti76gIc9CO7C0Q74z8teaxCKsB5xbb5sk+aDVBgZLecERoSaFhc+brdokaOTIb" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -52,7 +52,7 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"board","view":"province","urlState":"query"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"board","view":"province","panel":"map","urlState":"query"};
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -36,7 +36,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-1QKATO2zc5eFQVqHLIMkyHx2RcXSpvb2U/+1i2wyQFAy9WQPCR449qwFFu1+8S/Y" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-y/ti76gIc9CO7C0Q74z8teaxCKsB5xbb5sk+aDVBgZLecERoSaFhc+brdokaOTIb" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -36,7 +36,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-1QKATO2zc5eFQVqHLIMkyHx2RcXSpvb2U/+1i2wyQFAy9WQPCR449qwFFu1+8S/Y" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-y/ti76gIc9CO7C0Q74z8teaxCKsB5xbb5sk+aDVBgZLecERoSaFhc+brdokaOTIb" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -36,7 +36,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-1QKATO2zc5eFQVqHLIMkyHx2RcXSpvb2U/+1i2wyQFAy9WQPCR449qwFFu1+8S/Y" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-y/ti76gIc9CO7C0Q74z8teaxCKsB5xbb5sk+aDVBgZLecERoSaFhc+brdokaOTIb" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -36,7 +36,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-1QKATO2zc5eFQVqHLIMkyHx2RcXSpvb2U/+1i2wyQFAy9WQPCR449qwFFu1+8S/Y" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-y/ti76gIc9CO7C0Q74z8teaxCKsB5xbb5sk+aDVBgZLecERoSaFhc+brdokaOTIb" 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

@ -604,7 +604,7 @@
"bundle": "gospel-internet",
"scriptUrl": "./gospel-internet/gospel-internet.js",
"output": "dx-maps/gospel-internet/gospel-internet.js",
"integrity": "sha384-1QKATO2zc5eFQVqHLIMkyHx2RcXSpvb2U/+1i2wyQFAy9WQPCR449qwFFu1+8S/Y",
"integrity": "sha384-y/ti76gIc9CO7C0Q74z8teaxCKsB5xbb5sk+aDVBgZLecERoSaFhc+brdokaOTIb",
"elements": [
"gospel-internet-board"
],
@ -623,7 +623,7 @@
"scriptUrl": "./gospel-internet/gospel-internet.js",
"embed": {
"iframe": "<iframe src=\"./gospel-internet/board/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-1QKATO2zc5eFQVqHLIMkyHx2RcXSpvb2U/+1i2wyQFAy9WQPCR449qwFFu1+8S/Y\" crossorigin=\"anonymous\"></script>\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-y/ti76gIc9CO7C0Q74z8teaxCKsB5xbb5sk+aDVBgZLecERoSaFhc+brdokaOTIb\" crossorigin=\"anonymous\"></script>\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
},
"instances": [
{
@ -662,6 +662,7 @@
"props": {
"profile": "board",
"view": "province",
"panel": "map",
"urlState": "query"
},
"element": "gospel-internet-board",