Merge branch 'main' of https://git.nuxtbase.app/doxa-life/doxa-maps into bundler-3/work
Some checks are pending
build-gate / build (push) Waiting to run
Some checks are pending
build-gate / build (push) Waiting to run
# Conflicts: # public/doxa-maps/gospel-resources/charts/index.html # public/doxa-maps/gospel-resources/data-tables/index.html # public/doxa-maps/gospel-resources/gospel-dashboard/index.html # public/doxa-maps/gospel-resources/gospel-resources.js # public/doxa-maps/gospel-resources/resources-list/index.html # public/doxa-maps/gospel-resources/resources-map/index.html # public/doxa-maps/index.html # public/doxa-maps/manifest.json
This commit is contained in:
commit
795b357ab8
98 changed files with 1881 additions and 964 deletions
|
|
@ -49,7 +49,7 @@ The scripts these commands are grounded in (from this branch's `package.json`):
|
|||
"build": "bash internal/build-lock.sh",
|
||||
"build:unlocked": "bun run gates:pre && bun run library-index && bun run check:library-index && bun run clean && bun run token && bun run build:bundles && bun run tree && bun run gates:post && bun run gallery",
|
||||
"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 check:i18n-parity check:tabs-localized check:packets-all check:packet-strings-parity check:zone-census check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:done-evidence check:script-flags check:backlog-status check:capability-exemplars check:packet-fixture check:packet-browser check:provider-switch check:locale-reachable check:url-resolver check:manifest-covers check:one-palette check:legend-source check:backlog-refs",
|
||||
"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:packets-all check:packet-strings-parity check:zone-census check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:done-evidence check:script-flags check:backlog-status check:capability-exemplars check:packet-fixture check:packet-browser check:provider-switch check:locale-reachable check:url-resolver check:manifest-covers check:one-palette check:legend-source check:backlog-refs check:composite-embed-knobs",
|
||||
"build:bundles": "node internal/run-parallel.mjs --bundles", // the 22 vite builds, 4 at a time
|
||||
"preview": "bun x vite preview",
|
||||
"serve": "node internal/serve-strict.mjs", // 404s a directory, like production
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ Generated from 22 bundle(s).
|
|||
| `doxa-simple-map` | `doxa-simple-map` | `parameterized` |
|
||||
| `doxa-vision-card` | `doxa-vision-card` | `parameterized` |
|
||||
| `people-groups-grid` | `people-groups-grid` | `parameterized` |
|
||||
| `upg-neighbor` | `upg-neighbor` | `parameterized` |
|
||||
|
||||
## Capability 3 — multi-view-element (monolithic)
|
||||
|
||||
|
|
@ -71,6 +70,7 @@ Generated from 22 bundle(s).
|
|||
|---|---|---|
|
||||
| `doxa-research-map` | `research-map` | `monolithic` |
|
||||
| `research-dashboard` | `research-dashboard` | `monolithic` |
|
||||
| `upg-neighbor` | `upg-neighbor` | `monolithic` |
|
||||
|
||||
## Capability 4 — composite-element (nested-element SPA)
|
||||
|
||||
|
|
|
|||
229
internal/check-composite-embed-knobs.mjs
Normal file
229
internal/check-composite-embed-knobs.mjs
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* check-composite-embed-knobs.mjs — a composite must pass the host's TOKEN and PROVIDER down to the
|
||||
* map it nests, on somebody else's page.
|
||||
*
|
||||
* THE DEFECT THIS EXISTS FOR, MEASURED 2026-09-24. Two shipped composites declared NO PROPS at all,
|
||||
* so the `profile-config` a partner writes was read by nobody:
|
||||
*
|
||||
* <research-map-plus-grid profile-config='{"tk":"pk...."}'> -> "No Mapbox access token
|
||||
* <dashboard-plus-grid profile-config='{"tk":"pk...."}'> provided", 0 tiles, no canvas
|
||||
*
|
||||
* and after the token was threaded, the SAME hole was still open one knob over:
|
||||
*
|
||||
* <research-map-plus-grid profile-config='{"provider":"maplibre"}'> -> child still on mapbox,
|
||||
* so it demanded a token
|
||||
*
|
||||
* Every existing gate missed all of it, and not by accident: they load a composite on its OWN
|
||||
* generated leaf, and that leaf BAKES a token and assigns window.MAP_TOKEN, which the shared-token
|
||||
* bridge hands to the nested map. The leaf supplies the very thing under test. The failure exists
|
||||
* only where there is no leaf — which is exactly the partner page the published embed snippet is
|
||||
* written for, and exactly the case nobody was testing.
|
||||
*
|
||||
* WHY THESE TWO KNOBS AND NOT A LONGER LIST. They are the two the snippet documents and the two the
|
||||
* product promises: `tk` is how a partner supplies their own key, and `provider` is the one prop that
|
||||
* is supposed to swap the engine. A keyless MapLibre embed is the whole reason MapLibre support was
|
||||
* built — partners at volume who do not want a Mapbox key — so a composite that drops `provider`
|
||||
* does not degrade the feature, it cancels it, and reports the loss as a token error.
|
||||
*
|
||||
* HOW. Serves the built tree from a FREE port (ACAO:* via serve-strict, production parity) and the
|
||||
* partner page from `localhost` — a genuinely different origin, so CORS is exercised rather than
|
||||
* assumed. Free ports asked of the OS, never fixed ones: a stray server on a fixed port answers in
|
||||
* place of the tree under test and the gate then passes a build it never loaded.
|
||||
*
|
||||
* ASSERTIONS, per composite that nests a map:
|
||||
* tk — given ONLY {"tk": <the token the tree bakes>}, a canvas appears and at least one
|
||||
* api.mapbox.com style/tile request succeeds. No token error in the console.
|
||||
* provider — given ONLY {"provider":"maplibre"} and NO token, a canvas appears and there are
|
||||
* ZERO requests to api.mapbox.com. Zero is the assertion: "it rendered" would pass on
|
||||
* a build that quietly fell back to mapbox with a baked key.
|
||||
*
|
||||
* NEGATIVE-TESTED: reverting either fix in research-map-plus-grid.vue makes the matching case FAIL
|
||||
* naming the composite and the knob; both restored, both pass. Removing the zero-request assertion
|
||||
* from the provider case makes it pass on a build that ignores the prop, which is what it is for.
|
||||
*
|
||||
* Exit: 0 pass or SKIP (no built tree, no browser, no baked token to test with) · 1 fail.
|
||||
*/
|
||||
import { createServer } from 'node:http'
|
||||
import { spawn } from 'node:child_process'
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import { resolve, dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
||||
const MANIFEST = join(ROOT, 'public', 'doxa-maps', 'manifest.json')
|
||||
|
||||
if (!existsSync(MANIFEST)) {
|
||||
console.log('COMPOSITE-EMBED-KNOBS: SKIP — no built manifest (run `bun run tree` first).')
|
||||
process.exit(0)
|
||||
}
|
||||
let chromium
|
||||
try { ({ chromium } = await import('playwright')) } catch {
|
||||
console.log('COMPOSITE-EMBED-KNOBS: SKIP — playwright is not installed.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
const manifest = JSON.parse(readFileSync(MANIFEST, 'utf8'))
|
||||
|
||||
// Which bundles nest a MAP? A composite declares `composes`; a bundle is a map if any of its
|
||||
// profiles is isMap. Asking the manifest keeps this list correct when a composite is added.
|
||||
const mapBundles = new Set()
|
||||
for (const b of manifest.bundles || []) {
|
||||
if ((b.profiles || []).some((p) => p.isMap)) mapBundles.add(b.bundle)
|
||||
}
|
||||
const targets = []
|
||||
for (const b of manifest.bundles || []) {
|
||||
// TWO WAYS A COMPOSITE DECLARES ITSELF, and taking only the first under-covered this gate.
|
||||
// `composes` is written when a composite mounts children BY TAG; a composite that BAKES its
|
||||
// children in (an imported .vue) lists nothing there, and country-posters-mfe — one of the three
|
||||
// composites this defect was measured on — was silently not a target. The profile TYPE says so in
|
||||
// both cases, so ask for either.
|
||||
const composes = b.composes || []
|
||||
const byCompose = composes.some((c) => mapBundles.has(c))
|
||||
const profile = (b.profiles || []).find((p) => p.element && (byCompose || p.type === 'nested-elements-mfe'))
|
||||
if (!profile || !b.scriptUrl) continue
|
||||
targets.push({ bundle: b.bundle, element: profile.element, script: `${b.bundle}/${b.bundle}.js` })
|
||||
}
|
||||
if (!targets.length) {
|
||||
console.log('COMPOSITE-EMBED-KNOBS: SKIP — the manifest declares no composite that nests a map.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// The token to hand the partner page is the one the tree already bakes into its own leaves: this
|
||||
// gate must not invent a key, and a token that is not this tree's would 401 and look like our bug.
|
||||
const bakedToken = (() => {
|
||||
for (const b of manifest.bundles || []) {
|
||||
for (const p of b.profiles || []) {
|
||||
if (!p.isMap || !p.iframeUrl) continue
|
||||
const leaf = join(ROOT, 'public', 'doxa-maps', String(p.iframeUrl).replace(/^\.\//, ''))
|
||||
if (!existsSync(leaf)) continue
|
||||
const m = readFileSync(leaf, 'utf8').match(/BAKED_TOKEN\s*=\s*"(pk\.[^"]+)"/)
|
||||
if (m) return m[1]
|
||||
}
|
||||
}
|
||||
return ''
|
||||
})()
|
||||
|
||||
const freePort = () => new Promise((ok) => {
|
||||
const s = createServer().listen(0, '127.0.0.1', () => { const p = s.address().port; s.close(() => ok(p)) })
|
||||
})
|
||||
const TREE_PORT = await freePort()
|
||||
const HOST_PORT = await freePort()
|
||||
const TREE = `http://127.0.0.1:${TREE_PORT}/doxa-maps`
|
||||
|
||||
let pageHtml = '<!doctype html><html><body>nothing yet</body></html>'
|
||||
const tree = spawn(process.execPath, ['internal/serve-strict.mjs', '--port', String(TREE_PORT)], { cwd: ROOT, stdio: 'ignore' })
|
||||
const host = createServer((_, r) => { r.writeHead(200, { 'content-type': 'text/html' }); r.end(pageHtml) }).listen(HOST_PORT, 'localhost')
|
||||
const cleanup = () => { try { tree.kill() } catch { /* already gone */ } try { host.close() } catch { /* already closed */ } }
|
||||
await new Promise((r) => setTimeout(r, 900))
|
||||
|
||||
const reachable = await fetch(`${TREE}/manifest.json`, { signal: AbortSignal.timeout(4000) }).then((r) => r.ok).catch(() => false)
|
||||
if (!reachable) {
|
||||
cleanup()
|
||||
console.log('COMPOSITE-EMBED-KNOBS: SKIP — could not serve the built tree locally.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
const CASES = [
|
||||
{ knob: 'tk', config: (tok) => ({ tk: tok }), needsToken: true },
|
||||
{ knob: 'provider', config: () => ({ provider: 'maplibre' }), needsToken: false },
|
||||
]
|
||||
|
||||
const browser = await chromium.launch({ args: ['--enable-unsafe-swiftshader', '--use-gl=angle', '--use-angle=swiftshader'] })
|
||||
const fails = []
|
||||
const lines = []
|
||||
// Elements whose tk case actually drew a map — the only ones whose provider case can mean anything.
|
||||
const renders = new Set()
|
||||
try {
|
||||
for (const t of targets) {
|
||||
for (const c of CASES) {
|
||||
// Do not pay for a page load we already know cannot mean anything: if this element's tk case
|
||||
// drew no map, its provider case has nothing to compare against. Short-circuiting here is what
|
||||
// keeps the whole gate near two minutes instead of five on a nine-composite tree.
|
||||
if (c.knob === 'provider' && !renders.has(t.element)) {
|
||||
lines.push(` · ${t.element} [provider] UNMEASURED — its tk case never drew a map, so there is nothing to compare against.`)
|
||||
continue
|
||||
}
|
||||
if (c.needsToken && !bakedToken) {
|
||||
lines.push(` · ${t.element} [${c.knob}] SKIPPED — no baked token in this tree to hand the host`)
|
||||
continue
|
||||
}
|
||||
const cfg = JSON.stringify(c.config(bakedToken)).replace(/'/g, ''')
|
||||
pageHtml = `<!doctype html><html><head><meta charset=utf-8><title>partner</title></head><body style="margin:0">
|
||||
<header style="height:48px;background:#eee">HOST HEADER</header>
|
||||
<script>window.MAP_APP_API_URL="https://pray.doxa.life";</script>
|
||||
<script src="${TREE}/${t.script}" crossorigin="anonymous"></script>
|
||||
<${t.element} profile-config='${cfg}'></${t.element}>
|
||||
</body></html>`
|
||||
const page = await browser.newPage({ viewport: { width: 1280, height: 900 } })
|
||||
let mapboxOk = 0, mapboxBad = 0
|
||||
const errs = []
|
||||
page.on('response', (r) => {
|
||||
if (!/api\.mapbox\.com|tiles\.mapbox\.com/.test(r.url())) return
|
||||
if (r.status() >= 400) mapboxBad++; else mapboxOk++
|
||||
})
|
||||
page.on('console', (m) => { if (m.type() === 'error') errs.push(m.text().slice(0, 120)) })
|
||||
await page.goto(`http://localhost:${HOST_PORT}/`, { waitUntil: 'load' }).catch(() => {})
|
||||
// WAIT FOR THE THING, NOT FOR A CLOCK. A flat 14s per case made this gate cost four minutes
|
||||
// of wall time on a nine-composite tree, most of it spent watching a map that had already
|
||||
// drawn. Poll for a canvas instead, then settle briefly so late tile requests are counted —
|
||||
// the provider case asserts ZERO requests to api.mapbox.com, so it must not stop measuring
|
||||
// the moment something paints. An element that never draws still costs the full budget, which
|
||||
// is correct: that is the case whose absence is the finding.
|
||||
const CANVAS_BUDGET_MS = 16000
|
||||
const deadline = Date.now() + CANVAS_BUDGET_MS
|
||||
let canvas = 0
|
||||
const countCanvas = `(() => {
|
||||
let n = 0
|
||||
const visit = (r) => { n += r.querySelectorAll('canvas').length; for (const el of r.querySelectorAll('*')) if (el.shadowRoot) visit(el.shadowRoot) }
|
||||
visit(document)
|
||||
return n
|
||||
})()`
|
||||
while (Date.now() < deadline) {
|
||||
canvas = await page.evaluate(countCanvas).catch(() => 0)
|
||||
if (canvas) break
|
||||
await page.waitForTimeout(500)
|
||||
}
|
||||
await page.waitForTimeout(2500)
|
||||
canvas = await page.evaluate(countCanvas).catch(() => canvas)
|
||||
const tokenErr = errs.find((e) => /access token/i.test(e))
|
||||
const label = `${t.element} [${c.knob}]`
|
||||
const mapboxAll = mapboxOk + mapboxBad
|
||||
|
||||
// ★ FAIL ONLY WHERE THE EVIDENCE POINTS AT THE KNOB. An element that draws no map under a
|
||||
// MINIMAL config is not thereby broken: several composites need a `profile` to select which
|
||||
// of their profiles to show, and this gate deliberately passes only the knob under test. The
|
||||
// first draft failed nine of them for that, which would have red-gated other people's plugins
|
||||
// over a claim it had not measured. The distinguishing evidence is the console: a token WAS
|
||||
// supplied, so "No Mapbox access token provided" means the knob did not cross the boundary —
|
||||
// that is this defect. No canvas and no such complaint is simply not measurable here, and is
|
||||
// reported as UNMEASURED rather than dressed up as a finding.
|
||||
if (c.knob === 'tk') {
|
||||
if (canvas && mapboxOk > 0) { renders.add(t.element); lines.push(` ok ${label} — canvas ${canvas}, api.mapbox.com requests ${mapboxAll}`) }
|
||||
else if (canvas && mapboxOk === 0) fails.push(`${label}: canvas drew but NOTHING loaded from api.mapbox.com — the host's token never reached the map`)
|
||||
else if (tokenErr) fails.push(`${label}: a token was supplied and the element still says "${tokenErr}" — it never read the host's profile-config`)
|
||||
else lines.push(` · ${label} UNMEASURED — no map canvas under a minimal config, and no token complaint. This element likely needs a \`profile\` to show its map; not a knob failure.`)
|
||||
} else {
|
||||
if (canvas && mapboxAll === 0) lines.push(` ok ${label} — canvas ${canvas}, api.mapbox.com requests 0 (keyless, as asked)`)
|
||||
else if (mapboxAll > 0) fails.push(`${label}: asked for maplibre and still made ${mapboxAll} request(s) to api.mapbox.com — the prop did not cross the composite boundary`)
|
||||
else fails.push(`${label}: asked for maplibre with no token and drew nothing${tokenErr ? ` — ${tokenErr}` : ''}`)
|
||||
}
|
||||
await page.close()
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
await browser.close()
|
||||
cleanup()
|
||||
}
|
||||
|
||||
console.log(`COMPOSITE-EMBED-KNOBS: ${targets.length} composite(s) that nest a map, on a foreign origin`)
|
||||
for (const l of lines) console.log(l)
|
||||
if (fails.length) {
|
||||
console.error(`\nCOMPOSITE-EMBED-KNOBS: FAIL — ${fails.length} case(s)`)
|
||||
for (const f of fails) console.error(' - ' + f)
|
||||
console.error('\n A composite reads the host\'s profile-config and hands `tk` and `provider` to the map it')
|
||||
console.error(' nests. Our own leaves bake a token and assign window.MAP_TOKEN, so this only ever breaks')
|
||||
console.error(' on a partner page — the case the published embed snippet is written for.')
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(`\nCOMPOSITE-EMBED-KNOBS: PASS — the host's token and provider reach every nested map.`)
|
||||
|
|
@ -55,6 +55,7 @@ async function measure(width) {
|
|||
const cards = all.filter((e) => (e.className||'').toString().split(' ').includes('card')).filter(vis)
|
||||
const boxes = cards.map((c) => ({ c, b: c.getBoundingClientRect() }))
|
||||
let intrusions = 0, overflowing = 0, worst = 0, coveringPreview = 0, worstY = 0
|
||||
let previewsPainted = 0, previewsBroken = 0, noPreview = 0
|
||||
for (const { c, b } of boxes) {
|
||||
const row = c.querySelector('.pfs')
|
||||
if (!row) continue
|
||||
|
|
@ -68,7 +69,24 @@ async function measure(width) {
|
|||
// 35px -> 78px, and because it sits at bottom:-14px the extra height pushed its TOP from
|
||||
// 216px up to 173px in a 238px card: over the preview image and the card's outline.
|
||||
// Horizontal clean, card visibly broken, gate green.
|
||||
// COUNT THE PREVIEW, do not merely guard on it. An if-guard protects this loop from a
|
||||
// placeholder card — and also means a card with NO preview passes the over-preview assertion
|
||||
// perfectly. The driver reported BOTH a missing-previews symptom AND the overlap;
|
||||
// measuring only the overlap leaves the first unasserted.
|
||||
// NOTE: no backticks in this block — it lives inside a JS template literal.
|
||||
const img = c.querySelector('img')
|
||||
// ONLY JUDGE WHAT IS IN VIEW. Every preview carries loading=lazy, so a card below the fold
|
||||
// legitimately has naturalWidth 0 — measured at 390px: 8 of 27 painted, the first unpainted
|
||||
// one 3926px down an 844px viewport, and ZERO failing HTTP responses. A first version of this
|
||||
// assertion called that 18 broken images. Deferred is not broken; only an in-viewport image
|
||||
// that never painted is.
|
||||
if (!img) noPreview++
|
||||
else {
|
||||
const ib2 = img.getBoundingClientRect()
|
||||
const inView = ib2.top < window.innerHeight && ib2.bottom > 0
|
||||
if (img.complete && img.naturalWidth > 0) previewsPainted++
|
||||
else if (inView) previewsBroken++
|
||||
}
|
||||
if (img) {
|
||||
const ib = img.getBoundingClientRect()
|
||||
if (ib.height > 2 && rb.top < ib.bottom - 1) {
|
||||
|
|
@ -87,6 +105,7 @@ async function measure(width) {
|
|||
const tiny = ctrls.filter((e) => { const b = e.getBoundingClientRect(); return b.width < 18 || b.height < 10 })
|
||||
return { cards: cards.length, rows: cards.filter((c) => c.querySelector('.pfs')).length,
|
||||
overflowing, worst, intrusions, coveringPreview, worstY,
|
||||
previewsPainted, previewsBroken, noPreview,
|
||||
controls: ctrls.length, tiny: tiny.length }
|
||||
})()`)
|
||||
await page.close()
|
||||
|
|
@ -107,6 +126,8 @@ for (const r of results) {
|
|||
+ ` · overflow ${r.overflowing}${r.worst ? ` (${r.worst}px)` : ''}`
|
||||
+ ` · neighbour ${r.intrusions}`
|
||||
+ ` · over-preview ${r.coveringPreview}${r.worstY ? ` (${r.worstY}px)` : ''}`
|
||||
+ ` · previews ${r.previewsPainted} painted`
|
||||
+ `${r.previewsBroken ? `/${r.previewsBroken} BROKEN` : ''}${r.noPreview ? `/${r.noPreview} none` : ''}`
|
||||
+ ` · ${r.controls} control(s), ${r.tiny} too small`)
|
||||
}
|
||||
|
||||
|
|
@ -125,6 +146,27 @@ for (const r of results) {
|
|||
}
|
||||
// The row belongs BELOW the preview. Driver-reported 2026-09-24: "the download print options are
|
||||
// not showing up under the blue outline, they are overlapping where the blue outline would be".
|
||||
// THE PREVIEW MUST ACTUALLY BE THERE. A card with no image passes every geometry assertion
|
||||
// above trivially — nothing can overlap what does not render. Driver 2026-09-24: "it is supposed
|
||||
// to show the previews".
|
||||
if (r.previewsBroken) {
|
||||
fails.push(`${at}: ${r.previewsBroken} preview image(s) failed to load (naturalWidth 0) — `
|
||||
+ 'a broken preview is not something the geometry checks can see')
|
||||
}
|
||||
// EVERY card falling back to the placeholder means the previews are gone. MEASURED by aborting
|
||||
// every previews/** request: the product degrades WELL — all 27 cards swap to a .ph placeholder
|
||||
// reading "poster not generated yet", with no broken-image icons and no <img> left at all. That
|
||||
// is correct behaviour and exactly why it is invisible to an image-health check: previewsBroken
|
||||
// stays 0 because there is nothing left to be broken. Assert the FALLBACK instead.
|
||||
if (r.cards && r.noPreview === r.cards) {
|
||||
fails.push(`${at}: all ${r.cards} card(s) fell back to the "poster not generated yet" `
|
||||
+ 'placeholder — no preview rendered anywhere, and the geometry assertions above are vacuous '
|
||||
+ 'without one (they cannot overlap an image that is not there)')
|
||||
}
|
||||
if (r.previewsPainted === 0 && r.cards && r.noPreview !== r.cards) {
|
||||
fails.push(`${at}: NOT ONE preview image painted across ${r.cards} card(s) — the geometry `
|
||||
+ 'assertions above are vacuous without them')
|
||||
}
|
||||
if (r.coveringPreview) {
|
||||
fails.push(`${at}: ${r.coveringPreview} print row(s) COVER the preview image `
|
||||
+ `(top sits ${r.worstY}px above the image's bottom edge) — growing the row taller to fit it `
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
* party tile/glyph hiccups are reported, not failed — they are not this repo's to fix).
|
||||
*
|
||||
* PRECONDITION: a built tree in public/doxa-maps (this starts its own servers; no dev server).
|
||||
* Usage: node internal/check-research-gallery-embed.mjs [--mode js|iframe] [--only id,id]
|
||||
* Usage: node internal/check-research-gallery-embed.mjs [--mode js|iframe] [--only id,id] [--provider maplibre]
|
||||
* Exit: 0 pass · 1 fail · 2 SKIP (no built tree / no browser)
|
||||
*/
|
||||
import { createServer } from 'node:http'
|
||||
|
|
@ -42,6 +42,26 @@ const argv = process.argv.slice(2)
|
|||
const argOf = (k, d) => { const i = argv.indexOf(k); return i >= 0 && argv[i + 1] ? argv[i + 1] : d }
|
||||
const MODES = argOf('--mode', '') ? [argOf('--mode', '')] : ['js', 'iframe']
|
||||
const ONLY = argOf('--only', '') ? argOf('--only', '').split(',') : null
|
||||
// --provider maplibre: the KEYLESS embed. The host asks for maplibre (attribute in js mode, ?provider=
|
||||
// in iframe mode) and every tab must still paint — with ZERO requests to api.mapbox.com. That is the
|
||||
// promise a keyless partner embed depends on, and the shell once broke it by not forwarding the engine.
|
||||
const PROVIDER = argOf('--provider', '')
|
||||
// KNOWN, ROUTED exemptions from the zero-Mapbox rule — each names its owner. Printed on every run so
|
||||
// it cannot become invisible; DELETE the entry when the owner lands the fix (the gate then enforces it).
|
||||
const MAPBOX_KNOWN = {
|
||||
// EMPTY ON PURPOSE. The one entry here — my-upg-100-list/upg-100-list.vue:1464 pinning
|
||||
// mapbox-gl.css v3.3.0 regardless of engine — was fixed and the exemption deleted in the SAME
|
||||
// COMMIT as the fix, so main never had a window where the gate red-flagged its own known bug and
|
||||
// never had a window where a stale exemption hid a live one. Proven before deletion: this gate
|
||||
// reported "provider=maplibre made 0 request(s) to api.mapbox.com" in BOTH js and iframe modes,
|
||||
// with no KNOWN line printed at all.
|
||||
//
|
||||
// ⚠ NOT COVERED BY THIS MAP, and deliberately so: the generated leaf HEAD still preloads
|
||||
// mapbox-gl.css v3.24.0 and mapbox-gl-geocoder v5.0.0. Different versions, different owner —
|
||||
// that is generate-tree (bundler-1's lane), tracked as
|
||||
// BUG-LEAF-PAGES-PRELOAD-MAPBOX-EVEN-UNDER-MAPLIBRE. This gate embeds the GALLERY, which does not
|
||||
// load those leaves, which is why it reads zero today.
|
||||
}
|
||||
// ★ FREE PORTS, ASKED OF THE OS — never fixed ones. A stray server left on a fixed port by an
|
||||
// earlier crashed run answered in place of the tree under test, and this gate PASSED a known-broken
|
||||
// tree (caught by its own negative control, 2026-09-24): spawn failed with EADDRINUSE silently and
|
||||
|
|
@ -63,8 +83,8 @@ try { ({ chromium } = await import('playwright')) } catch {
|
|||
let mode = 'js'
|
||||
const hostPage = () => {
|
||||
const embed = mode === 'iframe'
|
||||
? `<iframe src="${TREE}/doxa-maps-spa/doxa-maps-spa/index.html" style="width:100%;height:760px;border:0"></iframe>`
|
||||
: `<script src="${TREE}/doxa-maps-spa/doxa-maps-spa.js"></script><doxa-maps-spa></doxa-maps-spa>`
|
||||
? `<iframe src="${TREE}/doxa-maps-spa/doxa-maps-spa/index.html${PROVIDER ? '?provider=' + PROVIDER : ''}" style="width:100%;height:760px;border:0"></iframe>`
|
||||
: `<script src="${TREE}/doxa-maps-spa/doxa-maps-spa.js"></script><doxa-maps-spa${PROVIDER ? ` provider="${PROVIDER}"` : ''}></doxa-maps-spa>`
|
||||
return `<!doctype html><html><head><meta charset=utf-8><title>host</title>
|
||||
<style>body{margin:0} header,footer{height:60px;background:#eee}</style></head>
|
||||
<body><header id=hdr>HOST HEADER</header><main style="max-width:1200px;margin:0 auto">${embed}</main><footer>HOST FOOTER</footer></body></html>`
|
||||
|
|
@ -80,7 +100,14 @@ const checked = {} // mode -> tabs actually driven; printed, and 0 is a FAIL (
|
|||
try {
|
||||
for (mode of MODES) {
|
||||
const page = await browser.newPage({ viewport: { width: 1400, height: 900 } })
|
||||
const own = new Set(), foreign = new Set()
|
||||
const own = new Set(), foreign = new Set(), mapbox = new Set()
|
||||
let current = '(page load)'
|
||||
const mapboxBy = {} // tab id (the one open when the request fired) -> distinct mapbox URLs
|
||||
page.on('request', q => {
|
||||
if (!/^https:\/\/api\.mapbox\.com\//.test(q.url())) return
|
||||
const u = q.url().split('?')[0]
|
||||
mapbox.add(u); (mapboxBy[current] = mapboxBy[current] || new Set()).add(u)
|
||||
})
|
||||
const note = (url, why) => (url.startsWith(`http://127.0.0.1:${TREE_PORT}/`) ? own : foreign).add(why + ' ' + url.split('?')[0])
|
||||
page.on('response', r => { if (r.status() >= 400) note(r.url(), String(r.status())) })
|
||||
page.on('requestfailed', q => { const e = (q.failure() && q.failure().errorText) || ''; if (!/ABORTED/.test(e)) note(q.url(), e) })
|
||||
|
|
@ -102,6 +129,7 @@ try {
|
|||
const tabs = await frame.evaluate(() => document.querySelector('doxa-maps-spa')._instance.proxy.tabs.map(t => ({ id: t.id, discovered: !!t.discovered })))
|
||||
for (const { id, discovered } of tabs) {
|
||||
if (ONLY && !ONLY.includes(id)) continue
|
||||
current = id
|
||||
await frame.evaluate(id => document.querySelector('doxa-maps-spa')._instance.proxy.onSelect(id), id)
|
||||
let v
|
||||
for (let k = 0; k < 50; k++) {
|
||||
|
|
@ -125,6 +153,17 @@ try {
|
|||
if (!ok) fails.push(`[${mode}] ${id}: ${why}`)
|
||||
}
|
||||
for (const f of own) { console.log(`FAIL [${mode}] tree request failed: ${f}`); fails.push(`[${mode}] ${f}`) }
|
||||
if (PROVIDER === 'maplibre') {
|
||||
for (const u of [...mapbox]) if (MAPBOX_KNOWN[u]) { console.log(`KNOWN [${mode}] ${u} — owner: ${MAPBOX_KNOWN[u]}`); mapbox.delete(u); for (const k in mapboxBy) { mapboxBy[k].delete(u); if (!mapboxBy[k].size) delete mapboxBy[k] } }
|
||||
const ok = mapbox.size === 0
|
||||
console.log(`${ok ? 'PASS' : 'FAIL'} [${mode}] provider=maplibre made ${mapbox.size} request(s) to api.mapbox.com`)
|
||||
if (!ok) {
|
||||
for (const [tab, urls] of Object.entries(mapboxBy)) {
|
||||
console.log(` while ${tab} was open: ${urls.size} — ${[...urls].slice(0, 3).join(' , ')}`)
|
||||
fails.push(`[${mode}] provider=maplibre: ${tab} hit api.mapbox.com (${urls.size} distinct URL(s))`)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const f of foreign) console.log(`note [${mode}] third-party request failed (not gated): ${f}`)
|
||||
await page.close()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,32 @@
|
|||
/**
|
||||
* WAGF region color strategy — colors pins by the region they belong to.
|
||||
*
|
||||
* ★ THE VALUES ARE THE RESEARCH MAP'S, ON THE DRIVER'S INSTRUCTION (2026-09-24). He compared the
|
||||
* two surfaces himself: "when i look on teh color ffor th regiosn tab of the simpel research map i
|
||||
* don tsee the you using htes colors on the reigosn dashbarod hwen you shoudl". Two surfaces
|
||||
* disagreeing about what Africa's colour means is a product defect whichever palette is prettier,
|
||||
* and he chose which one wins. Source of truth:
|
||||
* plugin-designs/doxa-research-map/src/colors/doxa-region.js, which the research dashboard and
|
||||
* three other consumers already paint from.
|
||||
*
|
||||
* WHAT THE CHANGE COST, measured rather than glossed (dataviz validate_palette.js, light mode,
|
||||
* surface #fcfcfb — the same tool and surface the previous palette was stepped against):
|
||||
* Lightness band FAIL #1ee05f 0.793 · #FFEB3B 0.928 · #00e0bd 0.810 sit above the 0.43–0.77 band
|
||||
* Chroma floor PASS all 7 >= 0.1
|
||||
* CVD separation PASS worst adjacent #FFEB3B<->#1ee05f dE 8.7 protan (>= 8), tritan 14.7
|
||||
* Normal vision PASS worst adjacent dE 21.0
|
||||
* Contrast WARN under 3:1 vs the surface: #1ee05f 1.72 · #FFEB3B 1.19 · #00e0bd 1.65 · #ff7f11 2.47
|
||||
* The palette this replaced passed all five. So the trade is real and it is recorded here rather
|
||||
* than in a commit message nobody will read next year.
|
||||
*
|
||||
* WHY THE CONTRAST WARN IS SURVIVABLE HERE, and it is a reason, not a dismissal: that check
|
||||
* obligates relief through a secondary encoding, and both surfaces already carry one — the chooser
|
||||
* renders a LEGEND of labelled chips in these exact colours, and the dashboard renders the same
|
||||
* seven regions as a TABLE with names and figures. Identity never rests on hue alone on either.
|
||||
* The LIGHTNESS FAIL is the part with no relief: three of these read faintly as PINS on a light
|
||||
* basemap. Darkening those three by ~10% L would enter the band while keeping the hue
|
||||
* recognisable, and that is the Driver's call to make, not mine to make quietly — asked, not done.
|
||||
*
|
||||
* WHY THIS EXISTS. The regions element's no-selection state is a CHOOSER: the Driver's brief was
|
||||
* "some type of map that would show the regions and countries and let you select one". For the
|
||||
* seven regions to read AS regions the moment the map loads, the pins have to be colored by
|
||||
|
|
@ -37,7 +63,13 @@
|
|||
|
||||
export const PROPERTY_KEY = 'region'
|
||||
|
||||
const DEFAULT_COLOR = '#6d766e' // DX-life --color-brand-lighter: an unknown region reads as chrome
|
||||
// DX-life --color-brand-lighter: an unknown region reads as chrome, not as an eighth region.
|
||||
// ★ DELIBERATELY NOT THEIRS. doxa-region.js uses '#0098FF' for null/undefined and keys
|
||||
// 'No WAGF Region/Bloc' to '#1a1a2e'. Neither is a REGION colour — they are what an absent value
|
||||
// looks like — and the Driver's instruction was about the seven regions. A bright blue for
|
||||
// "unknown" would also read as a region on a map whose every other pin is a region. Every row in
|
||||
// this feed carries a wagf_region, so this value is almost never painted; it is chrome on purpose.
|
||||
const DEFAULT_COLOR = '#6d766e'
|
||||
|
||||
/** Region value → display label, as the prayer API labels them. Used by the legend. */
|
||||
export const WAGF_REGIONS = {
|
||||
|
|
@ -50,15 +82,22 @@ export const WAGF_REGIONS = {
|
|||
'oceania': 'Oceania',
|
||||
}
|
||||
|
||||
/** Region value → color, in the validated order. Do not reorder without re-running the validator. */
|
||||
/**
|
||||
* Region value → color. THE RESEARCH MAP'S VALUES, so the two surfaces agree — see the header.
|
||||
* Mapped from its label-keyed table: Africa #ff2e2e, Asia #1a8cff, Europe #1ee05f,
|
||||
* Latin America & Caribbean #FFEB3B, Middle East #a83dff,
|
||||
* North America & Non-Spanish Caribbean #00e0bd, Oceania #ff7f11.
|
||||
* The order is still the fixed alphabetical one (colour follows the entity, never its rank), which
|
||||
* is also the order the adjacent-pair CVD result in the header was measured in.
|
||||
*/
|
||||
export const PALETTE = {
|
||||
'africa': '#2563eb',
|
||||
'asia': '#d97706',
|
||||
'europe': '#7c3aed',
|
||||
'latin_america_&_caribbean': '#15803d',
|
||||
'middle_east': '#dc2626',
|
||||
'north_america_&_non-spanish_caribbean': '#0891b2',
|
||||
'oceania': '#be185d',
|
||||
'africa': '#ff2e2e',
|
||||
'asia': '#1a8cff',
|
||||
'europe': '#1ee05f',
|
||||
'latin_america_&_caribbean': '#FFEB3B',
|
||||
'middle_east': '#a83dff',
|
||||
'north_america_&_non-spanish_caribbean': '#00e0bd',
|
||||
'oceania': '#ff7f11',
|
||||
}
|
||||
|
||||
/** The fixed render order — the same order the palette was validated in. */
|
||||
|
|
|
|||
|
|
@ -61,7 +61,13 @@ const visible = ref(false)
|
|||
const hintEl = ref(null)
|
||||
let watchTimer = null
|
||||
let movedTo = null // the element we re-parented into, so we can put ourselves back
|
||||
let attribRO = null // observes the attribution control (it resizes on its own, see below)
|
||||
let attribRO = null
|
||||
// The root this pill was mounted in, kept so a later clamp can look for obstacles (the phone
|
||||
// legend sheet) that did not exist at mount time.
|
||||
let hintRoot = null
|
||||
let sheetRO = null
|
||||
let sheetWatched = null
|
||||
let settleTimers = [] // observes the attribution control (it resizes on its own, see below)
|
||||
let hostRO = null // observes the pill's layout parent, so a LATE layout re-runs the clamp
|
||||
let attribEl = null
|
||||
|
||||
|
|
@ -122,6 +128,45 @@ function findMapBox(canvas, root) {
|
|||
* clipped, and leaves a correctly-placed pill untouched — so every surface that already worked is
|
||||
* byte-identical in behaviour.
|
||||
*/
|
||||
/**
|
||||
* The phone legend sheet is an obstacle too, not just the fold.
|
||||
*
|
||||
* MEASURED 2026-09-24 at 390x844 on doxa-research-map: the pill sat at y=700 and the open sheet
|
||||
* began at y=603, so "Tap a coloured dot — someone still needs prayer" printed straight across the
|
||||
* Progress rows — 1,418 Needs Prayer and the Full Prayer Coverage line were unreadable underneath
|
||||
* it. It is the phone screenshot the README showcases. Nothing was clipped, so the existing
|
||||
* below-the-fold clamp had nothing to say: the pill was fully visible and fully in the way.
|
||||
*
|
||||
* Same lever as the attribution strip, which this component already treats as a floor rather than
|
||||
* something to cover: find the sheet, and if the pill would cross its top edge, lift by exactly the
|
||||
* overlap. Only when the two actually intersect horizontally — a sheet that does not sit under the
|
||||
* pill is not an obstacle — and only ever upward, so every surface with no sheet is unchanged.
|
||||
*/
|
||||
function sheetFloor(pill) {
|
||||
const sheet = hintRoot?.querySelector?.('.legend-mobile-sheet')
|
||||
if (!sheet) return Infinity
|
||||
// ★ ATTACH THE OBSERVER HERE, NOT AT MOUNT. Measured: the sheet does not exist yet when the pill
|
||||
// mounts — LegendMobile renders after the map's first canvas — so a mount-time querySelector
|
||||
// found nothing, no observer was attached, and the clamp never ran again. The pill stayed exactly
|
||||
// where it was and the "fix" moved it by 0px. Binding lazily, the first clamp that SEES a sheet
|
||||
// is the one that starts watching it.
|
||||
if (sheetRO && sheetWatched !== sheet) { try { sheetRO.disconnect() } catch (_) {} sheetRO = null }
|
||||
if (!sheetRO && typeof ResizeObserver !== 'undefined') {
|
||||
try {
|
||||
sheetRO = new ResizeObserver(() => clampIntoView())
|
||||
sheetRO.observe(sheet)
|
||||
sheetWatched = sheet
|
||||
} catch (_) { sheetRO = null }
|
||||
}
|
||||
try {
|
||||
const sr = sheet.getBoundingClientRect()
|
||||
// A collapsed sheet is a thin strip; still an obstacle, but only if it is really there.
|
||||
if (!(sr.height > 16) || !(sr.width > 16)) return Infinity
|
||||
const apart = pill.right <= sr.left || sr.right <= pill.left
|
||||
return apart ? Infinity : sr.top
|
||||
} catch (_) { return Infinity }
|
||||
}
|
||||
|
||||
function clampIntoView() {
|
||||
const el = hintEl.value
|
||||
if (!el) return
|
||||
|
|
@ -138,7 +183,10 @@ function clampIntoView() {
|
|||
el.style.removeProperty('--pin-hint-lift')
|
||||
const r = el.getBoundingClientRect()
|
||||
if (!r.height) return
|
||||
const overflow = Math.round(r.bottom - window.innerHeight)
|
||||
// The lowest thing the pill may touch: the fold, or the top of the phone legend sheet when one
|
||||
// is open beneath it. Whichever is higher wins.
|
||||
const floor = Math.min(window.innerHeight, sheetFloor(r))
|
||||
const overflow = Math.round(r.bottom - floor)
|
||||
if (overflow > 0) el.style.setProperty('--pin-hint-lift', (overflow + 8) + 'px')
|
||||
} catch (_) { /* detached — nothing to clamp */ }
|
||||
}
|
||||
|
|
@ -196,6 +244,7 @@ onMounted(() => {
|
|||
const inst = getCurrentInstance()
|
||||
const root = inst?.proxy?.$el?.getRootNode?.()
|
||||
if (!root || typeof root.querySelector !== 'function') return
|
||||
hintRoot = root
|
||||
let tries = 0
|
||||
watchTimer = setInterval(() => {
|
||||
tries++
|
||||
|
|
@ -215,6 +264,11 @@ onMounted(() => {
|
|||
// The attribution ResizeObserver only fires when THAT control resizes, which need not
|
||||
// coincide with the host settling. Watch the pill's own offsetParent as well, so a late
|
||||
// layout (a composite sizing its nested child after mount) triggers a re-measure.
|
||||
// RE-CLAMP AS THE PAGE SETTLES. The phone legend sheet mounts AFTER the map's first canvas,
|
||||
// so the clamp above runs while the only floor is the fold. These three re-measures catch
|
||||
// the sheet arriving; once one of them sees it, sheetFloor() binds a ResizeObserver and the
|
||||
// sheet's own drags and collapses keep the pill clear from then on.
|
||||
settleTimers.push(setTimeout(clampIntoView, 1200), setTimeout(clampIntoView, 3000), setTimeout(clampIntoView, 6000))
|
||||
try {
|
||||
const watch = (hintEl.value && hintEl.value.offsetParent) || null
|
||||
if (watch && typeof ResizeObserver !== 'undefined') {
|
||||
|
|
@ -233,6 +287,10 @@ onBeforeUnmount(() => {
|
|||
if (watchTimer) clearInterval(watchTimer)
|
||||
if (attribRO) { try { attribRO.disconnect() } catch (_) {} attribRO = null } attribEl = null
|
||||
if (hostRO) { try { hostRO.disconnect() } catch (_) {} hostRO = null }
|
||||
if (sheetRO) { try { sheetRO.disconnect() } catch (_) {} sheetRO = null } sheetWatched = null
|
||||
for (const t of settleTimers) clearTimeout(t)
|
||||
settleTimers = []
|
||||
hintRoot = null
|
||||
// We appended our own element into a node Vue does not own. Vue removes the element
|
||||
// it created, but only from where IT thinks it is — so detach explicitly to be certain
|
||||
// no orphan pill is left behind in the map container on profile teardown.
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ import { useI18n } from 'vue-i18n'
|
|||
// (contain:layout on .vtl-content). Measured 1024x793 @ (256,107) at 1280x900 — rail clickable
|
||||
// behind the "modal". See library/utils/viewportScrim.js for the measurements and rejected fixes.
|
||||
import { useViewportScrim } from '@map/utils/viewportScrim.js'
|
||||
import { bundleTreeRoot } from '@map/utils/embedBase.js'
|
||||
|
||||
const props = defineProps({
|
||||
items: { type: Array, required: true },
|
||||
|
|
@ -149,7 +150,29 @@ const props = defineProps({
|
|||
|
||||
const plural = computed(() => props.itemNounPlural || `${props.itemNoun}s`)
|
||||
const base = computed(() => String(props.assetsBase || './assets').replace(/\/+$/, ''))
|
||||
const previewUrl = (id) => `${base.value}/previews/${id}.webp`
|
||||
|
||||
// ★ A SECOND PLACE TO LOOK, because "poster not generated yet" was being shown for posters that
|
||||
// ARE generated. The DRIVER reported it on Ethiopia, whose country-eth.webp exists (174 of the 175
|
||||
// records have their .webp; India is the one that legitimately does not and carries its own
|
||||
// reason). MEASURED here — static build AND dev server, every request 200, zero cards in that
|
||||
// branch — so the file is not missing; a HOST LAYOUT is. resolveAssetsBase points at
|
||||
// <treeRoot>/../assets, the shared pool, which is correct for the layout generate-tree documents
|
||||
// and wrong on a host that publishes only the tree folder. generate-tree ALSO stages a
|
||||
// self-contained copy INSIDE the tree ("staged 421 runtime asset(s) → doxa-maps/assets"), and
|
||||
// that copy is reachable on both layouts. So: try the pool, and if the bytes do not arrive, try
|
||||
// the copy before telling the user anything.
|
||||
const fallbackBase = computed(() => {
|
||||
const root = String(bundleTreeRoot() || '').replace(/\/+$/, '')
|
||||
return root ? `${root}/assets` : ''
|
||||
})
|
||||
// 0/absent = first attempt, 1 = the fallback is being tried.
|
||||
const attempt = ref({})
|
||||
const previewUrl = (id) => `${attempt.value[id] ? fallbackBase.value : base.value}/previews/${id}.webp`
|
||||
function onPreviewError(id) {
|
||||
const fb = fallbackBase.value
|
||||
if (!attempt.value[id] && fb && fb !== base.value) { attempt.value = { ...attempt.value, [id]: 1 }; return }
|
||||
missing.value = { ...missing.value, [id]: true }
|
||||
}
|
||||
|
||||
// Sections ordered by TOTAL count (largest first), items within a section by their
|
||||
// own count — the densest prayer need leads at BOTH levels.
|
||||
|
|
@ -630,11 +653,18 @@ useShadowStyles(
|
|||
@click="previewIsControl && exportPoster(item)"
|
||||
@keydown.enter.prevent="previewIsControl && exportPoster(item)"
|
||||
@keydown.space.prevent="previewIsControl && exportPoster(item)"
|
||||
@error="missing[item.id] = true" />
|
||||
@error="onPreviewError(item.id)" />
|
||||
<div v-else class="ph">
|
||||
<div class="ph-label">{{ item.label }}</div>
|
||||
<div v-if="item.count" class="ph-count">{{ item.count.toLocaleString() }} people groups</div>
|
||||
<div class="ph-note">poster not generated yet</div>
|
||||
<!-- NOT "not generated yet": reaching this branch means the preview IMAGE did
|
||||
not arrive after both bases were tried, which says nothing about whether a
|
||||
poster exists. A record with genuinely no poster carries its own
|
||||
unsupportedReason and renders the branch above. Saying "not generated" of a
|
||||
poster that is sitting on disk is how the Driver came to report this.
|
||||
i18n DEBT: this literal predates t() here and is still untranslated, like
|
||||
the two beside it. -->
|
||||
<div class="ph-note">preview unavailable</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@
|
|||
"WAGF Block": "كتلة WAGF",
|
||||
"WAGF Region": "منطقة WAGF",
|
||||
"people groups adopted": "الشعوب المنتمية",
|
||||
"people groups engaged": "مجموعات بشرية مُنخرِطة"
|
||||
"people groups engaged": "مجموعات بشرية مُنخرِطة",
|
||||
"Outside this region": "خارج هذه المنطقة",
|
||||
"Pray": "صلّي",
|
||||
"Loading region dashboards…": "جارٍ تحميل لوحات المناطق…",
|
||||
"No regions found.": "لم يتم العثور على مناطق."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@
|
|||
"WAGF Block": "WAGF-Block",
|
||||
"WAGF Region": "WAGF-Region",
|
||||
"people groups adopted": "adoptierte Volksgruppen",
|
||||
"people groups engaged": "engagierte Volksgruppen"
|
||||
"people groups engaged": "engagierte Volksgruppen",
|
||||
"Outside this region": "Außerhalb dieser Region",
|
||||
"Pray": "Ich bete",
|
||||
"Loading region dashboards…": "Regions-Dashboards werden geladen…",
|
||||
"No regions found.": "Keine Regionen gefunden."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@
|
|||
"WAGF Block": "WAGF Block",
|
||||
"WAGF Region": "WAGF Region",
|
||||
"people groups adopted": "people groups adopted",
|
||||
"people groups engaged": "people groups engaged"
|
||||
"people groups engaged": "people groups engaged",
|
||||
"Outside this region": "Outside this region",
|
||||
"Pray": "Pray",
|
||||
"Loading region dashboards…": "Loading region dashboards…",
|
||||
"No regions found.": "No regions found."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@
|
|||
"WAGF Block": "Bloque WAGF",
|
||||
"WAGF Region": "Región de la WAGF",
|
||||
"people groups adopted": "grupos de personas adoptados",
|
||||
"people groups engaged": "grupos étnicos comprometidos"
|
||||
"people groups engaged": "grupos étnicos comprometidos",
|
||||
"Outside this region": "Fuera de esta región",
|
||||
"Pray": "Oración",
|
||||
"Loading region dashboards…": "Cargando los paneles de regiones…",
|
||||
"No regions found.": "No se encontraron regiones."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@
|
|||
"WAGF Block": "Bloc WAGF",
|
||||
"WAGF Region": "Région WAGF",
|
||||
"people groups adopted": "peuples adoptés",
|
||||
"people groups engaged": "peuples engagés"
|
||||
"people groups engaged": "peuples engagés",
|
||||
"Outside this region": "Hors de cette région",
|
||||
"Pray": "Prier",
|
||||
"Loading region dashboards…": "Chargement des tableaux de bord des régions…",
|
||||
"No regions found.": "Aucune région trouvée."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@
|
|||
"WAGF Block": "WAGF ब्लॉक",
|
||||
"WAGF Region": "डब्ल्यूएजीएफ क्षेत्र",
|
||||
"people groups adopted": "लोगों के समूहों ने अपनाया",
|
||||
"people groups engaged": "प्रवेशित लोगों के समूह"
|
||||
"people groups engaged": "प्रवेशित लोगों के समूह",
|
||||
"Outside this region": "इस क्षेत्र के बाहर",
|
||||
"Pray": "प्रार्थना करें",
|
||||
"Loading region dashboards…": "क्षेत्र डैशबोर्ड लोड हो रहे हैं…",
|
||||
"No regions found.": "कोई क्षेत्र नहीं मिला।"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@
|
|||
"WAGF Block": "Blocco WAGF",
|
||||
"WAGF Region": "Regione WAGF",
|
||||
"people groups adopted": "popoli adottati",
|
||||
"people groups engaged": "popoli coinvolti"
|
||||
"people groups engaged": "popoli coinvolti",
|
||||
"Outside this region": "Fuori da questa regione",
|
||||
"Pray": "Prega",
|
||||
"Loading region dashboards…": "Caricamento delle dashboard delle regioni…",
|
||||
"No regions found.": "Nessuna regione trovata."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@
|
|||
"WAGF Block": "Bloco WAGF",
|
||||
"WAGF Region": "Região da WAGF",
|
||||
"people groups adopted": "grupos étnicos adotados",
|
||||
"people groups engaged": "grupos étnicos engajados"
|
||||
"people groups engaged": "grupos étnicos engajados",
|
||||
"Outside this region": "Fora desta região",
|
||||
"Pray": "Ore",
|
||||
"Loading region dashboards…": "Carregando os painéis das regiões…",
|
||||
"No regions found.": "Nenhuma região encontrada."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@
|
|||
"WAGF Block": "Bloc WAGF",
|
||||
"WAGF Region": "Regiune WAGF",
|
||||
"people groups adopted": "popoare adoptate",
|
||||
"people groups engaged": "popoare implicate"
|
||||
"people groups engaged": "popoare implicate",
|
||||
"Outside this region": "În afara acestei regiuni",
|
||||
"Pray": "Roagă-te",
|
||||
"Loading region dashboards…": "Se încarcă panourile regiunilor…",
|
||||
"No regions found.": "Nu au fost găsite regiuni."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@
|
|||
"WAGF Block": "Блок WAGF",
|
||||
"WAGF Region": "Регион WAGF",
|
||||
"people groups adopted": "принятые группы людей",
|
||||
"people groups engaged": "вовлечённые группы людей"
|
||||
"people groups engaged": "вовлечённые группы людей",
|
||||
"Outside this region": "За пределами этого региона",
|
||||
"Pray": "Молиться",
|
||||
"Loading region dashboards…": "Загрузка панелей по регионам…",
|
||||
"No regions found.": "Регионы не найдены."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@
|
|||
"WAGF Block": "WAGF 板块",
|
||||
"WAGF Region": "WAGF 区域",
|
||||
"people groups adopted": "已认领的民族",
|
||||
"people groups engaged": "已参与的民族"
|
||||
"people groups engaged": "已参与的民族",
|
||||
"Outside this region": "在此区域之外",
|
||||
"Pray": "祷告",
|
||||
"Loading region dashboards…": "正在加载区域面板…",
|
||||
"No regions found.": "未找到区域。"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@
|
|||
selects : the `key` of the canonical row this one stands for. An ALIAS row has its own unique
|
||||
`key` (for v-for) but clicking it selects `selects`, it highlights whenever that key is
|
||||
active, and it is skipped by keyboard nav so arrow keys visit each canonical row once.
|
||||
branch : an id that makes this row FOLDABLE — a chevron beside it shows/hides the rows below.
|
||||
Closed by default; picking the row also opens it.
|
||||
ancestors : the `branch` ids above this row; it shows only while ALL of them are open.
|
||||
Selection is controlled via v-model:active (the active item's `key`). The host owns pane content
|
||||
and mount logic — this component only paints the SHELL (top bar + rail + a content frame) and
|
||||
exposes slots so each app keeps its unique chrome + its own mount machinery:
|
||||
|
|
@ -161,14 +164,24 @@
|
|||
</div>
|
||||
|
||||
<div class="vtl-rows" v-show="!grp.folder || !isFolderClosed(grp)">
|
||||
<div class="vtl-rowwrap" role="presentation" v-for="row in grp.rows" :key="row.key"
|
||||
v-show="rowShown(row)">
|
||||
<!-- BRANCH toggle: folds this row's sub-rows (see `branch` / `ancestors`). A sibling of the
|
||||
tab, never inside it — a button may not contain a button. -->
|
||||
<button v-if="row.branch" type="button" class="vtl-twisty"
|
||||
:aria-expanded="String(isBranchOpen(row.branch))"
|
||||
:aria-label="(isBranchOpen(row.branch) ? 'Hide' : 'Show') + ' what ' + row.label + ' is made of'"
|
||||
@click="toggleBranch(row.branch)">
|
||||
<span class="vtl-chev" :class="{ open: isBranchOpen(row.branch) }" aria-hidden="true" v-html="iconSvg('chevron')"></span>
|
||||
</button>
|
||||
<button
|
||||
v-for="row in grp.rows" :key="row.key" type="button" role="tab"
|
||||
class="vtl-tab" :class="{ active: target(row) === active, alias: !!row.selects }"
|
||||
type="button" role="tab"
|
||||
class="vtl-tab" :class="{ active: target(row) === active, alias: !!row.selects, 'has-branch': !!row.branch }"
|
||||
:data-depth="row.depth || null" :style="row.depth ? { '--vtl-depth': row.depth } : null"
|
||||
:aria-selected="String(target(row) === active)"
|
||||
:tabindex="!row.selects && row.key === active ? 0 : -1"
|
||||
:ref="el => { if (!row.selects) registerTab(row.key, el) }"
|
||||
@click="pick(target(row))" @keydown="onKey($event)">
|
||||
@click="pick(target(row), row)" @keydown="onKey($event)">
|
||||
<span class="vtl-tab-ic" aria-hidden="true" v-if="row.icon" v-html="iconSvg(row.icon)"></span>
|
||||
<span class="vtl-tab-emoji" aria-hidden="true" v-else-if="row.emoji">{{ row.emoji }}</span>
|
||||
<!-- Slim-rail fallback (desktop collapsed only): a row with NEITHER icon NOR emoji would
|
||||
|
|
@ -180,6 +193,7 @@
|
|||
<span class="vtl-tab-sub" v-if="row.sub"><span v-html="row.sub"></span></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -368,6 +382,11 @@ const VTL_SHADOW_CSS = `
|
|||
.vtl-tab { display:flex; align-items:center; gap:11px; width:100%; min-height:48px; text-align:left; border:0; background:none; color:var(--vtl-muted); padding:8px 12px; cursor:pointer; border-radius:var(--vtl-radius,8px); font:inherit; margin:0; transition:background .13s ease,color .13s ease; }
|
||||
.vtl-tab[data-depth] { padding-left:calc(12px + var(--vtl-depth) * 16px); }
|
||||
.vtl-tab[data-depth]::before { content:''; flex:0 0 auto; align-self:stretch; width:0; margin-right:-3px; border-left:2px solid var(--vtl-accent); opacity:.45; }
|
||||
.vtl-rowwrap { position:relative; }
|
||||
.vtl-twisty { position:absolute; z-index:1; right:4px; top:50%; transform:translateY(-50%); width:28px; height:28px; display:inline-flex; align-items:center; justify-content:center; padding:0; border:0; border-radius:8px; background:none; color:var(--vtl-muted); cursor:pointer; }
|
||||
.vtl-twisty:hover { background:var(--vtl-accented); color:#3b463d; }
|
||||
.vtl-twisty:focus-visible { outline:2px solid var(--vtl-accent); outline-offset:-2px; }
|
||||
.vtl-tab.has-branch { padding-right:36px; }
|
||||
.vtl-tab:hover { background:var(--vtl-accented); color:#3b463d; }
|
||||
.vtl-tab:focus-visible { outline:2px solid var(--vtl-accent); outline-offset:-2px; }
|
||||
.vtl-tab.active { background:var(--vtl-accented); color:#3b463d; font-weight:500; }
|
||||
|
|
@ -463,6 +482,7 @@ const VTL_SHADOW_CSS = `
|
|||
.vtl.rail-collapsed .vtl-tab-emoji { font-size:19px; }
|
||||
.vtl.rail-collapsed .vtl-tab-fallback { display:inline-flex; }
|
||||
.vtl.rail-collapsed .vtl-tab[data-depth]::before { display:none; }
|
||||
.vtl.rail-collapsed .vtl-twisty { display:none; }
|
||||
.vtl.rail-collapsed .vtl-tier { padding-left:196px; }
|
||||
.vtl.rail-collapsed .vtl-tl, .vtl.rail-collapsed .vtl-td, .vtl.rail-collapsed .vtl-cap, .vtl.rail-collapsed .vtl-chev { display:none; }
|
||||
.vtl.rail-collapsed .vtl-grp + .vtl-grp { margin-top:6px; padding-top:6px; }
|
||||
|
|
@ -489,6 +509,7 @@ const VTL_SHADOW_CSS = `
|
|||
.vtl.rail-collapsed .vtl-tab { padding-left:10px; gap:11px; }
|
||||
.vtl.rail-collapsed .vtl-tab[data-depth] { padding-left:calc(12px + var(--vtl-depth) * 16px); }
|
||||
.vtl.rail-collapsed .vtl-tab[data-depth]::before { display:block; }
|
||||
.vtl.rail-collapsed .vtl-twisty { display:inline-flex; }
|
||||
.vtl.rail-collapsed .vtl-tab-text { display:flex; }
|
||||
.vtl.rail-collapsed .vtl-tab-fallback { display:none; }
|
||||
.vtl.rail-collapsed .vtl-tier { padding-left:8px; }
|
||||
|
|
@ -529,7 +550,7 @@ export default defineComponent({
|
|||
// tab (so their pane is rendered + element mounted); hostState/hostError track each pane's load.
|
||||
// A row not in activatedKeys is never rendered — the lazy contract (no visit → no cost).
|
||||
return {
|
||||
navOpen: this.initialNavOpen, railCollapsed: this.initialRailCollapsed, _tabEls: {}, folderOverride: {},
|
||||
navOpen: this.initialNavOpen, railCollapsed: this.initialRailCollapsed, _tabEls: {}, folderOverride: {}, branchOpen: {},
|
||||
// `narrow` mirrors the (max-width:760px) media query as REACTIVE state, kept current by a resize
|
||||
// listener. It lets us reconcile the two boolean state machines (navOpen = mobile drawer,
|
||||
// railCollapsed = desktop slim rail) at the breakpoint and drive rail visibility correctly.
|
||||
|
|
@ -690,7 +711,15 @@ export default defineComponent({
|
|||
},
|
||||
// The key a row selects: its own, or — for an ALIAS row — the canonical row it points at.
|
||||
target(row) { return row.selects || row.key },
|
||||
pick(key) {
|
||||
// BRANCHES — a row with `branch` folds the rows whose `ancestors` include it. Closed by default,
|
||||
// so a deep composition tree costs one line until someone asks to see inside it.
|
||||
isBranchOpen(id) { return !!this.branchOpen[id] },
|
||||
toggleBranch(id) { this.branchOpen = { ...this.branchOpen, [id]: !this.branchOpen[id] } },
|
||||
rowShown(row) { return !row.ancestors || row.ancestors.every(id => this.branchOpen[id]) },
|
||||
pick(key, row) {
|
||||
// Choosing a row that owns a branch also OPENS it (never closes it): you asked for that plugin,
|
||||
// so show what it is made of. Only the chevron closes a branch.
|
||||
if (row && row.branch && !this.branchOpen[row.branch]) this.toggleBranch(row.branch)
|
||||
this.$emit('update:active', key)
|
||||
// On mobile, picking a tab closes the off-canvas drawer. On desktop navOpen must stay true (it gates
|
||||
// the desktop rail's visibility via railShown), so we only touch it when narrow.
|
||||
|
|
@ -820,6 +849,11 @@ export default defineComponent({
|
|||
.vtl-tab { display:flex; align-items:center; gap:11px; width:100%; min-height:48px; text-align:left; border:0; background:none; color:var(--vtl-muted); padding:8px 12px; cursor:pointer; border-radius:var(--vtl-radius,8px); font:inherit; margin:0; transition:background .13s ease,color .13s ease; }
|
||||
.vtl-tab[data-depth] { padding-left:calc(12px + var(--vtl-depth) * 16px); }
|
||||
.vtl-tab[data-depth]::before { content:''; flex:0 0 auto; align-self:stretch; width:0; margin-right:-3px; border-left:2px solid var(--vtl-accent); opacity:.45; }
|
||||
.vtl-rowwrap { position:relative; }
|
||||
.vtl-twisty { position:absolute; z-index:1; right:4px; top:50%; transform:translateY(-50%); width:28px; height:28px; display:inline-flex; align-items:center; justify-content:center; padding:0; border:0; border-radius:8px; background:none; color:var(--vtl-muted); cursor:pointer; }
|
||||
.vtl-twisty:hover { background:var(--vtl-accented); color:#3b463d; }
|
||||
.vtl-twisty:focus-visible { outline:2px solid var(--vtl-accent); outline-offset:-2px; }
|
||||
.vtl-tab.has-branch { padding-right:36px; }
|
||||
.vtl-tab:hover { background:var(--vtl-accented); color:#3b463d; }
|
||||
.vtl-tab:focus-visible { outline:2px solid var(--vtl-accent); outline-offset:-2px; }
|
||||
.vtl-tab.active { background:var(--vtl-accented); color:#3b463d; font-weight:500; }
|
||||
|
|
@ -915,6 +949,7 @@ export default defineComponent({
|
|||
.vtl.rail-collapsed .vtl-tab-emoji { font-size:19px; }
|
||||
.vtl.rail-collapsed .vtl-tab-fallback { display:inline-flex; }
|
||||
.vtl.rail-collapsed .vtl-tab[data-depth]::before { display:none; }
|
||||
.vtl.rail-collapsed .vtl-twisty { display:none; }
|
||||
.vtl.rail-collapsed .vtl-tier { padding-left:196px; }
|
||||
.vtl.rail-collapsed .vtl-tl, .vtl.rail-collapsed .vtl-td, .vtl.rail-collapsed .vtl-cap, .vtl.rail-collapsed .vtl-chev { display:none; }
|
||||
.vtl.rail-collapsed .vtl-grp + .vtl-grp { margin-top:6px; padding-top:6px; }
|
||||
|
|
@ -941,6 +976,7 @@ export default defineComponent({
|
|||
.vtl.rail-collapsed .vtl-tab { padding-left:10px; gap:11px; }
|
||||
.vtl.rail-collapsed .vtl-tab[data-depth] { padding-left:calc(12px + var(--vtl-depth) * 16px); }
|
||||
.vtl.rail-collapsed .vtl-tab[data-depth]::before { display:block; }
|
||||
.vtl.rail-collapsed .vtl-twisty { display:inline-flex; }
|
||||
.vtl.rail-collapsed .vtl-tab-text { display:flex; }
|
||||
.vtl.rail-collapsed .vtl-tab-fallback { display:none; }
|
||||
.vtl.rail-collapsed .vtl-tier { padding-left:8px; }
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@
|
|||
"check:gallery-embed": "node internal/check-research-gallery-embed.mjs # the cap-5 Research Gallery must embed on a FOREIGN ORIGIN (a stand-in host page on localhost, the built tree on 127.0.0.1) in BOTH modes, bare <script>+<doxa-maps-spa> and <iframe>, with the layout inside the host box and every curated tab painting a map. The summary line prints the tab count PER MODE, and a mode that checked zero tabs is a FAIL. One mode only: check:gallery-embed:js or check:gallery-embed:iframe. Starts its own servers on OS-assigned ports; needs only a built tree. Exit 2 = SKIP (no built tree / no playwright).",
|
||||
"check:gallery-embed:js": "node internal/check-research-gallery-embed.mjs --mode js",
|
||||
"check:gallery-embed:iframe": "node internal/check-research-gallery-embed.mjs --mode iframe",
|
||||
"check:gallery-embed:maplibre": "node internal/check-research-gallery-embed.mjs --provider maplibre",
|
||||
"check:spa-tab-order": "node internal/check-spa-tab-order.mjs # the cap-5 SPA must open on Big Picture and keep the Driver's order (Big Picture, UPG-100, Prayer Progress, Gospel Resources) — asserted as PRESENCE + tab-1 + RELATIVE order on the RENDERED rail, because the rail gained three sections and now renders 12 rows with others between them. ⚠ NOT WAVE-WIRED: it FAILS rather than skips when the SPA is unreachable, deliberately (\"a gate that cannot reach its subject has not passed, it has not run\") — correct standalone, but gates:post runs on checkouts with no server. Needs `bun run serve` on 4173.",
|
||||
"check:backlog-status": "node internal/check-backlog-status-enum.mjs",
|
||||
"check:backlog-refs": "node internal/check-backlog-refs.mjs # a card may not depend on a card that does not exist. A dangling depends_on can never be done, so the card can never become ready and nothing says so — it reads as ordinary blocked work forever. FAILS only for depends_on on an OPEN card; a dangling parent or a stale link on a done card is REPORTED, because failing on filing debt teaches people to delete the reference rather than restore the card. Reads all three phase backlogs — references legitimately cross phases. SKIPs when _qa-cycle is absent.",
|
||||
|
|
@ -167,8 +168,9 @@
|
|||
"check:doc-scripts:self-test": "node internal/check-doc-quotes-scripts.mjs --self-test",
|
||||
"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 check:i18n-parity check:tabs-localized check:packets-all check:packet-strings-parity check:zone-census check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:done-evidence check:script-flags check:backlog-status check:capability-exemplars check:packet-fixture check:packet-browser check:provider-switch check:locale-reachable check:url-resolver check:manifest-covers check:one-palette check:legend-source check:backlog-refs",
|
||||
"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:packets-all check:packet-strings-parity check:zone-census check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:done-evidence check:script-flags check:backlog-status check:capability-exemplars check:packet-fixture check:packet-browser check:provider-switch check:locale-reachable check:url-resolver check:manifest-covers check:one-palette check:legend-source check:backlog-refs check:composite-embed-knobs",
|
||||
"build:bundles": "node internal/run-parallel.mjs --bundles",
|
||||
"check:composite-embed-knobs": "node internal/check-composite-embed-knobs.mjs # a composite must pass the HOST's tk and provider down to the map it nests, proven on a genuinely foreign origin (tree served on one port, partner page on another). Our own leaves bake a token and assign window.MAP_TOKEN, so this only ever breaks where there is no leaf - the partner page the embed snippet is written for, and the case nothing else tested. Keyless maplibre asserts ZERO requests to api.mapbox.com, because 'it rendered' would pass on a build that quietly fell back with a baked key.",
|
||||
"check:maplibre-drops": "node internal/check-maplibre-layer-drops.mjs",
|
||||
"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.",
|
||||
"check:packets-all": "node internal/check-packets-all.mjs # runs check:packet-render over EVERY generated packet, not one hand-named file. The single-file gate SKIPs with no argument, so it was in package.json, passing in all 11 locales, and in neither gates:pre nor gates:post — it only ran when someone typed a filename. SKIPs when no packets are generated.",
|
||||
|
|
|
|||
|
|
@ -13,8 +13,9 @@
|
|||
* Same "import the REAL components, no fork" discipline as big-picture: the grid is the exact
|
||||
* people-groups-grid component; the dashboard is the exact research-dashboard component.
|
||||
*/
|
||||
import { reactive, provide, ref } from 'vue'
|
||||
import { reactive, provide, ref, computed } from 'vue'
|
||||
import { resolveEmbedBase } from '@map/utils/embedBase.js'
|
||||
import { useSharedMapToken, publishMapToken } from '@map/composables/useSharedMapToken.js'
|
||||
import StackLayout from '@map/layouts/StackLayout.vue'
|
||||
import ResearchDashboard from '../research-dashboard/research-dashboard.vue'
|
||||
import PeopleGroupsGrid from '../people-groups-grid/people-groups-grid.vue'
|
||||
|
|
@ -217,13 +218,58 @@ function onDashboardFilter({ filterSet = {}, searchTerm = '' } = {}) {
|
|||
// Note this is exactly the two-host defect class: research-dashboard standalone PASSES the same
|
||||
// gate (1/1, verified this tick), and the identical component inside this composite FAILED. Only a
|
||||
// gate that drives BOTH hosts can tell those apart, which is why the composite is now a target.
|
||||
// ★ THE HOST'S OWN profile-config, WHICH THIS COMPOSITE USED TO THROW AWAY.
|
||||
// It declared no props, so a partner's <dashboard-plus-grid profile-config='{"tk":"..."}'> lost its
|
||||
// token entirely. MEASURED on a third-party origin before this: 'No Mapbox access token provided',
|
||||
// 0 style and 0 tile requests to api.mapbox.com, no canvas — the JS embed, one of the two shipped
|
||||
// embed methods, mounted a dashboard whose map could not draw. Our own leaf hides it, because that
|
||||
// page carries a BAKED token; the failure exists only where there is no leaf, which is exactly the
|
||||
// partner case. Same defect and same shape as research-map-plus-grid.
|
||||
const props = defineProps({
|
||||
/** The host's JSON config, exactly as the embed snippet writes it. */
|
||||
profileConfig: { type: [String, Object], default: null },
|
||||
})
|
||||
const hostConfig = computed(() => {
|
||||
const raw = props.profileConfig
|
||||
if (!raw) return {}
|
||||
if (typeof raw === 'object') return raw
|
||||
// A malformed attribute must not take the element down with it.
|
||||
try { return JSON.parse(raw) } catch { return {} }
|
||||
})
|
||||
const hostToken = computed(() => {
|
||||
const tk = hostConfig.value?.tk
|
||||
return typeof tk === 'string' && tk ? tk : ''
|
||||
})
|
||||
if (hostToken.value) publishMapToken(hostToken.value)
|
||||
|
||||
// The provider is a host knob as well: resolveMapProvider reads profile-config.provider, and the
|
||||
// config the child sees is the one provided below. Dropping it left a host that asked for maplibre
|
||||
// on mapbox — demanding a token for the one configuration that exists to need none.
|
||||
const hostProvider = computed(() => {
|
||||
const p = hostConfig.value?.provider
|
||||
return p === 'maplibre' || p === 'mapbox' ? p : ''
|
||||
})
|
||||
|
||||
// ★ AND PROVIDE IT THE WAY ProfileLoader WOULD. This composite bakes its children in rather than
|
||||
// mounting them through ProfileLoader, and ProfileLoader is the ONLY provider of 'mapboxToken' in
|
||||
// the repo — so DashboardMapPanel's inject('mapboxToken', ref('')) fell through to its empty
|
||||
// default here. The shared page token keeps a late-arriving token working (the leaf FETCHES one),
|
||||
// which is what the composable exists for; the host's own tk still wins.
|
||||
const sharedToken = useSharedMapToken()
|
||||
const mapboxToken = computed(() => hostToken.value || sharedToken.value || '')
|
||||
provide('mapboxToken', mapboxToken)
|
||||
|
||||
const SHARE_LEAF = 'dashboard-plus-grid/dashboard-plus-grid/index.html'
|
||||
const shareBase = resolveEmbedBase(null)
|
||||
provide('profileConfig', ref({
|
||||
provide('profileConfig', computed(() => ({
|
||||
profile: 'research-dashboard',
|
||||
layout: 'page-scroll',
|
||||
shareUrl: (shareBase ? shareBase.replace(/\/+$/, '') + '/' : '') + SHARE_LEAF,
|
||||
}))
|
||||
// Spread last so a host that supplies none leaves the key absent, and never overwrite the two
|
||||
// settings above — those are this composite's own layout and share decisions, not the host's.
|
||||
...(hostToken.value ? { tk: hostToken.value } : {}),
|
||||
...(hostProvider.value ? { provider: hostProvider.value } : {}),
|
||||
})))
|
||||
|
||||
const sections = [
|
||||
// The research-dashboard leaf SELF-TITLES (its own DashboardTopBar renders a "Research Dashboard"
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ Add `?tab=<id>` to the `src` to open a specific map.
|
|||
| `tab` | device default (Big Picture on desktop, Simple Research on phones) | Tab id to open first. Changing it later switches tabs. `?tab=` on the page URL works too. |
|
||||
| `language` | parent page / saved choice | UI language pushed to every tab (`en`, `es`, `fr`, …). |
|
||||
| `api-base-url` | manifest `runtime.apiBaseUrl` | Data API. Only applied when the page has not already set `window.MAP_APP_API_URL`. |
|
||||
| `provider` | each map's own default (Mapbox) | Map engine for every nested map: `maplibre` needs no token and makes no Mapbox requests; `mapbox`. Forwarded to each map and, when the page has not set `window.MAP_PROVIDER`, set there too so maps nested inside composites follow. In the iframe embed use `?provider=maplibre`. |
|
||||
| `tk` | manifest `runtime.token` | Mapbox public token. Only fills `window.MAP_TOKEN` when the page has not set one. |
|
||||
| `token-url` | none | Token endpoint forwarded to each map. |
|
||||
| `tree-base` | derived from the script URL | Pin the tree root explicitly (needed only when the script is re-hosted apart from its tree). |
|
||||
|
|
@ -74,5 +75,6 @@ Both headers are **required** on a host other than the one serving the tree:
|
|||
## Prove it
|
||||
|
||||
```sh
|
||||
bun run check:gallery-embed # serves the built tree + a foreign host page, drives every tab in both modes
|
||||
bun run check:gallery-embed # serves the built tree + a foreign host page, drives every tab in both modes
|
||||
bun run check:gallery-embed:maplibre # same, keyless: provider=maplibre must make zero api.mapbox.com requests
|
||||
```
|
||||
|
|
|
|||
|
|
@ -737,6 +737,9 @@ export default defineComponent({
|
|||
// the tree's own manifest.json (its `runtime` block), so a bare two-line embed needs no config.
|
||||
// See EMBED.md beside this file.
|
||||
apiBaseUrl: { type: String, default: '' },
|
||||
// The map engine for every nested map: 'maplibre' (keyless) or 'mapbox'. Also accepted as
|
||||
// profile-config.provider. Unset = each map's own ladder (?provider= → window.MAP_PROVIDER → mapbox).
|
||||
provider: { type: String, default: '' },
|
||||
// Which tab opens first, by tab id (e.g. "upg-100", "gospel-resources"). Lets a host page deep-
|
||||
// link into one map of the gallery. Falls back to ?tab= on the page URL, then the device default.
|
||||
tab: { type: String, default: '' }
|
||||
|
|
@ -905,6 +908,11 @@ export default defineComponent({
|
|||
const fromProp = (this.language || this.cfg.language || this.cfg.locale || this.cfg.lang || '').trim()
|
||||
return (fromProp || this.locale || '').split('-')[0].toLowerCase()
|
||||
},
|
||||
// The engine a HOST asked for ('' = none; each map keeps its own ladder).
|
||||
effectiveProvider() {
|
||||
const p = String(this.provider || this.cfg.provider || '').trim().toLowerCase()
|
||||
return (p === 'maplibre' || p === 'mapbox') ? p : ''
|
||||
},
|
||||
activeKey() {
|
||||
const t = this.tabs[this.activeIndex]
|
||||
return t ? t.id : ''
|
||||
|
|
@ -1239,6 +1247,11 @@ export default defineComponent({
|
|||
const tk = this.tk || this.cfg.tk || this.runtime.token
|
||||
if (tk) pc.tk = tk
|
||||
if (this.tokenUrl || this.cfg.tokenUrl) pc.tokenUrl = this.tokenUrl || this.cfg.tokenUrl
|
||||
// ★ AND THE ENGINE. resolveMapProvider's ladder starts at profile-config.provider, and a child
|
||||
// reads only the config written HERE — so a gallery asked for maplibre mounted children that
|
||||
// resolved mapbox (bundler-2 measured 19 api.mapbox.com requests for a maplibre request on the
|
||||
// studio, the same hole). Validated to the two known engines so a typo cannot pick a third.
|
||||
if (this.effectiveProvider) pc.provider = this.effectiveProvider
|
||||
// PASS THE TREE BASE DOWN — a nested cap-5 shell (or any element that fetches the manifest)
|
||||
// cannot guess it, and guessing is what produced the original 404 class.
|
||||
if (this.base) pc.treeBase = this.base
|
||||
|
|
@ -1259,6 +1272,14 @@ export default defineComponent({
|
|||
if (api && !window.MAP_APP_API_URL) window.MAP_APP_API_URL = api.replace(/\/+$/, '')
|
||||
const tk = this.tk || this.cfg.tk || this.runtime.token
|
||||
if (tk && !window.MAP_TOKEN) window.MAP_TOKEN = tk
|
||||
// window.MAP_PROVIDER — the engine, when a host explicitly asked this gallery for one.
|
||||
// childConfig forwards it as profile-config.provider, which the simple map elements honour,
|
||||
// but a COMPOSITE mounts its inner maps without passing its own config's provider on.
|
||||
// Measured 2026-09-24 with provider="maplibre", one tab per clean page: Prayer Progress and
|
||||
// All People Groups made 0 api.mapbox.com requests, while Big Picture (19), Regions (17),
|
||||
// UPG-100 (15) and Simple Research (14) loaded mapbox-gl and Mapbox styles. The page global
|
||||
// is rung 3 of every map's resolveMapProvider ladder, so it reaches maps nested at any depth.
|
||||
if (this.effectiveProvider && !window.MAP_PROVIDER) window.MAP_PROVIDER = this.effectiveProvider
|
||||
},
|
||||
// Mount a tab's REAL custom element: inject the bundle's script once, wait for the tag to be
|
||||
// registered, then create it in the pane's empty slot. This is the ONE path for every tab.
|
||||
|
|
|
|||
|
|
@ -1458,8 +1458,14 @@ onMounted(async () => {
|
|||
// custom MapToolbar buttons never needed mapbox ctrl CSS, so this profile
|
||||
// skipped it until the shared GeocoderComponent (a real mapbox ctrl) arrived.
|
||||
// Mirrors src/composables/useMapInstance.js ensureMapboxCSS (idempotent).
|
||||
// ⚠ MAPBOX ONLY. This ran unconditionally, so a keyless maplibre embed still pulled a
|
||||
// stylesheet from api.mapbox.com — token-free and harmless to render, but wrong-engine
|
||||
// leakage on a page whose whole point is having no Mapbox dependency. It was the last
|
||||
// mapbox-under-maplibre reference in this profile, carried as a named exemption in the
|
||||
// maplibre-embed gate; guarding it lets that exemption be deleted and enforced instead.
|
||||
// MapLibre ships its own ctrl CSS via ensureEngineScript, so nothing is lost.
|
||||
try {
|
||||
const shadow = mapEl.value && mapEl.value.getRootNode()
|
||||
const shadow = !isMaplibre && mapEl.value && mapEl.value.getRootNode()
|
||||
if (shadow instanceof ShadowRoot) {
|
||||
const MAPBOX_CSS = 'https://api.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.css'
|
||||
if (!shadow.querySelector(`link[href="${MAPBOX_CSS}"]`)) {
|
||||
|
|
|
|||
|
|
@ -292,6 +292,12 @@ const HEAVY_ELEMENTS = new Set([
|
|||
// doxa-maps-spa's NOT_EXPERIMENTAL already hides big-picture for the same reason.
|
||||
const STUDIO_HIDDEN = new Set(['big-picture'])
|
||||
|
||||
// DISPLAY NAMES — what a row is CALLED, keyed by "<bundle>/<profile>". Display only: the row key, the
|
||||
// URL hash, the stored last-tab and the <tag> under the name are all unchanged, so links and memory
|
||||
// keep working. The Driver's name for the cap-5 shell is "Research Gallery" (its meta.json label);
|
||||
// the manifest does not publish meta labels, so the studio carries the one it needs here.
|
||||
const DISPLAY_NAME = { 'doxa-maps-spa/doxa-maps-spa': 'Research Gallery' }
|
||||
|
||||
// Load a bundle exactly once per URL; resolves after its define() has run.
|
||||
//
|
||||
// ★ A CLASSIC SCRIPT FIRES onload AND THEN FAILS, for a dev-server bundle. Measured 2026-09-22:
|
||||
|
|
@ -340,6 +346,10 @@ export default defineComponent({
|
|||
props: {
|
||||
treeBase: { type: String, default: '' },
|
||||
profileConfig: { type: [String, Object], default: '' },
|
||||
// The map engine, as an attribute as well as a profile-config key — the studio previews map
|
||||
// plugins, so a host showing it to partners wants to flip both at once. Forwarded to every pane
|
||||
// below; an unrecognised value is ignored there rather than passed on.
|
||||
provider: { type: String, default: '' },
|
||||
// NOT `title` — that name collides with the NATIVE HTMLElement.title property.
|
||||
// defineCustomElement maps every prop to an attribute, and `title` already exists on every
|
||||
// element (the tooltip), so Vue warned on EVERY mount:
|
||||
|
|
@ -418,17 +428,32 @@ export default defineComponent({
|
|||
navGroups() {
|
||||
const esc = (s) => String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||
const treeOf = new Map(this.compositionTrees.map(t => [t.nodes[0].selects, t]))
|
||||
// ★ FOLDED BY DEFAULT (Driver, 2026-09-24: "it needs to be collapsible, otherwise it is too
|
||||
// hard to know how to navigate so many nested plugins"). Every node with parts is a BRANCH with
|
||||
// its own chevron, closed until opened — so the rail first reads as a plain list of plugins, and
|
||||
// you drill into one composite, then one level of it, at a time. Picking a composite opens it.
|
||||
// Branch ids are namespaced by the composite's row key: the same child (dashboard-plus-grid)
|
||||
// folds independently under doxa-maps-spa and in its own CAP 4 entry.
|
||||
const parts = (n) => n + (n === 1 ? ' part' : ' parts')
|
||||
const rowsFor = (r) => {
|
||||
const out = [{ key: r.key, label: r.label, icon: r.icon, sub: '<code><' + esc(r.tag) + '></code>' }]
|
||||
const t = treeOf.get(r.key)
|
||||
const bid = (id) => 'b:' + r.key + ':' + id
|
||||
const out = [{
|
||||
key: r.key, label: r.label, icon: r.icon,
|
||||
branch: t ? bid(0) : undefined,
|
||||
sub: '<code><' + esc(r.tag) + '></code>' + (t ? ' · ' + parts(t.nodes[0].kids) : '')
|
||||
}]
|
||||
if (t) {
|
||||
t.nodes.slice(1).forEach((n, i) => out.push({
|
||||
key: 'tree-' + r.key + '-' + i,
|
||||
t.nodes.slice(1).forEach((n) => out.push({
|
||||
key: 'tree-' + r.key + '-' + n.id,
|
||||
selects: n.selects || ('none:' + r.key),
|
||||
depth: n.depth,
|
||||
label: n.label,
|
||||
badge: n.part ? 'part' : '',
|
||||
sub: n.part ? 'no standalone page' : 'CAP ' + n.cap + ' · <code><' + esc(n.tag) + '></code>'
|
||||
branch: n.kids ? bid(n.id) : undefined,
|
||||
ancestors: n.ancestors.map(bid),
|
||||
sub: n.part ? 'no standalone page'
|
||||
: 'CAP ' + n.cap + ' · <code><' + esc(n.tag) + '></code>' + (n.kids ? ' · ' + parts(n.kids) : '')
|
||||
}))
|
||||
}
|
||||
return out
|
||||
|
|
@ -460,7 +485,9 @@ export default defineComponent({
|
|||
// own page because it has none, so it opens the composite it lives in.
|
||||
compositionTrees() {
|
||||
const out = []
|
||||
const walk = (row, depth, path, nodes) => {
|
||||
// Every node records `ancestors` (the ids of the nodes above it) and, if anything was nested
|
||||
// under it, `kids` — which is what lets the rail fold each level independently.
|
||||
const walk = (row, depth, path, nodes, ancestors) => {
|
||||
const b = this.manifestBundles.find(x => x.bundle === row.bundle)
|
||||
const refs = (row.cap >= 4 && b && b.composes) || []
|
||||
const kids = []
|
||||
|
|
@ -475,12 +502,15 @@ export default defineComponent({
|
|||
}
|
||||
kids.sort((a, b2) => b2.cap - a.cap || a.label.localeCompare(b2.label))
|
||||
for (const k of kids) {
|
||||
nodes.push({ label: k.label, tag: k.tag, cap: k.cap, selects: k.key, depth: depth + 1 })
|
||||
if (!path.has(k.key)) walk(k, depth + 1, new Set([...path, k.key]), nodes)
|
||||
const node = { id: nodes.length, label: k.label, tag: k.tag, cap: k.cap, selects: k.key, depth: depth + 1, ancestors, kids: 0 }
|
||||
nodes.push(node)
|
||||
const before = nodes.length
|
||||
if (!path.has(k.key)) walk(k, depth + 1, new Set([...path, k.key]), nodes, [...ancestors, node.id])
|
||||
node.kids = nodes.filter((n, i) => i >= before && n.depth === depth + 2).length
|
||||
}
|
||||
// Unpublished parts have no tier, so they sort LAST — below every capability — and open the
|
||||
// composite they live in.
|
||||
for (const ref of parts) nodes.push({ label: ref, part: true, selects: row.key, depth: depth + 1 })
|
||||
for (const ref of parts) nodes.push({ id: nodes.length, label: ref, part: true, selects: row.key, depth: depth + 1, ancestors, kids: 0 })
|
||||
}
|
||||
for (const b of this.manifestBundles) {
|
||||
if (!b.composes || !b.composes.length || STUDIO_HIDDEN.has(b.bundle)) continue
|
||||
|
|
@ -489,8 +519,9 @@ export default defineComponent({
|
|||
// this rail already IS its composition.
|
||||
const own = this.rows.find(r => r.bundle === b.bundle)
|
||||
if (!own) continue
|
||||
const nodes = [{ label: own.label, tag: own.tag, cap: own.cap, selects: own.key, depth: 0 }]
|
||||
walk(own, 0, new Set([own.key]), nodes)
|
||||
const nodes = [{ id: 0, label: own.label, tag: own.tag, cap: own.cap, selects: own.key, depth: 0, ancestors: [] }]
|
||||
walk(own, 0, new Set([own.key]), nodes, [0])
|
||||
nodes[0].kids = nodes.filter(n => n.depth === 1).length
|
||||
if (nodes.length > 1) out.push({ bundle: b.bundle, nodes })
|
||||
}
|
||||
return out
|
||||
|
|
@ -536,7 +567,7 @@ export default defineComponent({
|
|||
const slot = this._slots && this._slots[this.activeKey]
|
||||
const el = slot && slot.firstElementChild
|
||||
if (el && el.setAttribute && row) {
|
||||
const pc = { profile: row.label, instanceId: 'ps-' + this.activeKey.replace(/\//g, '-'), locale: code }
|
||||
const pc = { profile: row.profile, instanceId: 'ps-' + this.activeKey.replace(/\//g, '-'), locale: code }
|
||||
if (this.tk || this.cfg.tk) pc.tk = this.tk || this.cfg.tk
|
||||
el.setAttribute('profile-config', JSON.stringify(pc))
|
||||
}
|
||||
|
|
@ -596,7 +627,10 @@ export default defineComponent({
|
|||
out.push({
|
||||
key: b.bundle + '/' + p.profile,
|
||||
bundle: b.bundle,
|
||||
label: p.profile,
|
||||
label: DISPLAY_NAME[b.bundle + '/' + p.profile] || p.profile,
|
||||
// The REAL profile id, handed to the element in profile-config. Never the label: a display
|
||||
// name would mount <doxa-maps-spa> with profile "Research Gallery", which it does not have.
|
||||
profile: p.profile,
|
||||
tag,
|
||||
cap,
|
||||
icon: CAP_ICON[cap] || 'embed',
|
||||
|
|
@ -715,9 +749,16 @@ export default defineComponent({
|
|||
// renders in the studio's active language (ProfileLoader reads profile-config.locale).
|
||||
// tk/tokenUrl ride along here now that map rows mount directly — this is the token ladder
|
||||
// the removed iframe src used to carry as a query param.
|
||||
const pc = { profile: row.label, instanceId: 'ps-' + row.key.replace(/\//g, '-'), locale: this.locale }
|
||||
const pc = { profile: row.profile, instanceId: 'ps-' + row.key.replace(/\//g, '-'), locale: this.locale }
|
||||
if (this.tk || this.cfg.tk) pc.tk = this.tk || this.cfg.tk
|
||||
if (this.tokenUrl || this.cfg.tokenUrl) pc.tokenUrl = this.tokenUrl || this.cfg.tokenUrl
|
||||
// ★ AND THE ENGINE, for the same reason tk rides along. resolveMapProvider's ladder starts
|
||||
// at profile-config.provider, and a pane reads the config THIS file writes — so a studio
|
||||
// embedded with provider=maplibre showed mapbox panes and, on a keyless host, panes that
|
||||
// asked for a token. MEASURED on a foreign origin: 19 requests to api.mapbox.com for a
|
||||
// maplibre request. Validated to the two known engines so a typo cannot select a third.
|
||||
const wantProvider = this.provider || this.cfg.provider
|
||||
if (wantProvider === 'maplibre' || wantProvider === 'mapbox') pc.provider = wantProvider
|
||||
// PASS THE TREE BASE DOWN — a nested cap-5 shell cannot guess it.
|
||||
// doxa-maps-spa carries its OWN hardcoded, TREE-RELATIVE tab list (doxa-maps-spa.vue:265-312,
|
||||
// e.g. 'doxa-research-map/research-map/index.html') and resolves it against ITS treeBase,
|
||||
|
|
|
|||
|
|
@ -20,10 +20,19 @@
|
|||
// rem values would resolve against the host's root (16px by default) and every space would be
|
||||
// 1.6x too large. That is exactly why these were resolved to px in the first place.
|
||||
//
|
||||
// THE VALUES ARE OURS AS THEY ALREADY WERE, not re-derived from live. Live carries more precision
|
||||
// (2.352637rem = 23.52637px vs our 23.5264px). Naming the numbers and changing the numbers are two
|
||||
// different changes; this one only names them, which is what lets a full computed-style
|
||||
// fingerprint prove it altered nothing. Re-deriving would be a separate, separately measured step.
|
||||
// THE VALUES ARE NOW LIVE'S FULL PRECISION. They started as the rounded numbers this file was
|
||||
// created to name (23.5264px for --spacing-lg, where live is 2.352637rem = 23.52637px), and the
|
||||
// header said re-deriving them would be "a separate, separately measured step". THIS IS THAT STEP,
|
||||
// and a measurement forced it: their country-list bullet is sized in em, 1.5em of --font-size-md,
|
||||
// and against live it came out 29.2812px where theirs is 29.2969px. 0.0157px, which is nothing to
|
||||
// look at — but it is the ROUNDING of --font-size-md (19.5312 for their 19.53125) multiplied by
|
||||
// 1.5, and every other em- or percentage-derived length on the page inherits the same error. The
|
||||
// scales are exact powers of their two ratios (type 1.25, spacing 1.33) on a 10px root, so full
|
||||
// precision is available for free and there is no reason to ship a rounded clone.
|
||||
// type: 10px * 1.25^n -> 15.625 / 19.53125 / 24.4140625 / 30.517578125 / ...
|
||||
// spacing: 10px * 1.33^n -> 13.3 / 17.689 / 23.52637 / 31.2900721 / ...
|
||||
// The vs-live diffs compare with a +/-0.5px tolerance, so this cannot be what turns one green; the
|
||||
// bullet's exact-equality compare is what it is for.
|
||||
//
|
||||
// Mapping verified against live's own custom properties, not arithmetic:
|
||||
// spacing 3xs .5653230821rem · 2xs .7518796992 · md 1.7689 · lg 2.352637 · xl 3.12900721
|
||||
|
|
@ -36,10 +45,10 @@
|
|||
// a magic number because it reads as deliberate.
|
||||
export const DXLIFE_TOKENS =
|
||||
':host{' +
|
||||
' --spacing-3xs:5.6532px; --spacing-2xs:7.5188px; --spacing-md:17.689px;' +
|
||||
' --spacing-lg:23.5264px; --spacing-xl:31.2901px; --spacing-2xl:41.6158px;' +
|
||||
' --spacing-3xl:55.349px; --spacing-4xl:73.6142px;' +
|
||||
' --font-size-sm:15.625px; --font-size-md:19.5312px; --font-size-lg:24.4141px;' +
|
||||
' --font-size-xl:30.5176px; --font-size-2xl:38.147px; --font-size-3xl:47.6837px;' +
|
||||
' --font-size-4xl:59.6046px; --font-size-5xl:74.5058px;' +
|
||||
' --spacing-3xs:5.653230821px; --spacing-2xs:7.518796992px; --spacing-md:17.689px;' +
|
||||
' --spacing-lg:23.52637px; --spacing-xl:31.2900721px; --spacing-2xl:41.615795893px;' +
|
||||
' --spacing-3xl:55.349008538px; --spacing-4xl:73.614181355px;' +
|
||||
' --font-size-sm:15.625px; --font-size-md:19.53125px; --font-size-lg:24.4140625px;' +
|
||||
' --font-size-xl:30.517578125px; --font-size-2xl:38.146972656px; --font-size-3xl:47.68371582px;' +
|
||||
' --font-size-4xl:59.604644775px; --font-size-5xl:74.505805969px;' +
|
||||
'}'
|
||||
|
|
|
|||
|
|
@ -69,6 +69,10 @@ const cfg = computed(() => {
|
|||
try { return JSON.parse(props.profileConfig) || {} } catch { return {} }
|
||||
})
|
||||
const prayBaseUrl = computed(() => props.prayBaseUrl || cfg.value.prayBaseUrl || 'https://pray.doxa.life')
|
||||
// Their popup's second button. RegionDetail passes CountryMap `:research-url="localePath('/research') + '/'"`;
|
||||
// we have no router, so it comes from profile-config with their public site as the default —
|
||||
// the same ladder and the same default UupgsList.vue:74 already uses.
|
||||
const researchUrl = computed(() => cfg.value.researchUrl || 'https://doxa.life/research/')
|
||||
// The prayer API localises its LABELS from ?lang= — country names, region names, religion
|
||||
// names. MEASURED: with locale=ar the UI translated but every country in the table stayed
|
||||
// English, because this read only cfg.languageCode while the locale arrives as
|
||||
|
|
@ -131,7 +135,13 @@ const sel = ref({
|
|||
// identically -- the extra fields are read by the map, never by addToStats().
|
||||
// Their PEOPLE_GROUP_LIST_FIELDS plus the two this tab's map needs (name, slug) — derived
|
||||
// from the shared list so the two can never drift apart.
|
||||
const FIELDS = 'name,slug,' + PEOPLE_GROUP_LIST_FIELDS
|
||||
// ★ PLUS THEIR FIVE POPUP FIELDS. CountryMap.vue:89 fetches
|
||||
// name,slug,country_code,rop1,religion,population,location_description,image_url,has_photo,
|
||||
// latitude,longitude,people_committed
|
||||
// and their pin popup renders every one of them. Ours fetched neither rop1, religion,
|
||||
// location_description nor the photo, so the popup COULD NOT have been a clone however it was
|
||||
// written — the data was not on the page. Same one request, five more columns.
|
||||
const FIELDS = 'name,slug,rop1,religion,location_description,image_url,has_photo,' + PEOPLE_GROUP_LIST_FIELDS
|
||||
|
||||
function formatNumber(n) {
|
||||
// THEIRS, RegionDetail.vue:16: `n.toLocaleString(`${locale.value}-u-nu-latn`)` — locale
|
||||
|
|
@ -594,6 +604,12 @@ async function loadRegions() {
|
|||
region: p.wagf_region?.value || '',
|
||||
lng: parseFloat(p.longitude), lat: parseFloat(p.latitude),
|
||||
committed: toNumber(p.people_committed), population: toNumber(p.population),
|
||||
// Their popup's fields, mapped exactly as CountryMap.vue:107-115 maps them — including the
|
||||
// has_photo GATE on the image, which is theirs: a row can carry an image_url that is a
|
||||
// placeholder, and they only show it when the flag says there is a real photo.
|
||||
rop1: p.rop1?.label || '', religion: p.religion?.label || '',
|
||||
description: p.location_description || '',
|
||||
imageUrl: (p.has_photo && p.image_url) ? p.image_url : '',
|
||||
})).filter((p) => Number.isFinite(p.lng) && Number.isFinite(p.lat))
|
||||
} catch (error) {
|
||||
console.error('[region-dashboards] fetch error:', error)
|
||||
|
|
@ -651,7 +667,13 @@ useShadowStyles(
|
|||
' --dx-surface:#f3f3f1; --dx-elevated:#fff; --dx-text:#2a332a; --dx-header-bg:#3b463d;' +
|
||||
' --dx-header-text:#fff; --dx-muted:#6d766e; --dx-line:#d1d4cd; --dx-accent:#92b195;' +
|
||||
' --dx-dark:#2a332a; --dx-on-dark:#f3f3f1; --dx-track:#4e594f; --dx-partial:#f0c64a;' +
|
||||
' --dx-radius:35px;' +
|
||||
' --dx-radius:35px; --dx-radius-lg:25px;' +
|
||||
// base/_globals.scss:99-105 + :205-207 style EVERY table on their site: --table-border-color
|
||||
// is $color-gray-500 (#666) and --border-radius-lg is 2.5rem at their 10px root = 25px.
|
||||
' --dx-table-border:#666;' +
|
||||
// base/_globals.scss:132-141 styles EVERY anchor: --color-brand-light on hover to
|
||||
// --color-brand-lighter. $color-green-400 / $color-green-300.
|
||||
' --dx-link:#4e594f; --dx-link-hover:#6d766e;' +
|
||||
' background:var(--dx-surface); color:var(--dx-text);' +
|
||||
' font:var(--font-size-md)/1.5 Poppins,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif; }' +
|
||||
// Same responsive context + same 1200px cap as tab 1 (regions-list.vue). DX-life applies its
|
||||
|
|
@ -669,15 +691,24 @@ useShadowStyles(
|
|||
// We cannot set this on the host document from inside a shadow root, and should not;
|
||||
// this element's own scroller is the box every child measures against.
|
||||
'.rd-scroll{ flex:1 1 auto; min-height:0; overflow-y:auto; scrollbar-gutter:stable; -webkit-overflow-scrolling:touch;' +
|
||||
' padding:var(--spacing-3xl) 0 var(--spacing-4xl); display:flex; flex-direction:column; gap:var(--spacing-3xl);' +
|
||||
' padding:var(--spacing-3xl) 0 var(--spacing-4xl); display:flex; flex-direction:column;' +
|
||||
' container-type:inline-size; }' +
|
||||
'.rd-scroll > * + *{ margin-top:var(--spacing-3xl); }' + // .stack .stack--3xl
|
||||
'.rd-scroll > *{ box-sizing:border-box; width:calc(90% + 16px); max-width:1200px;' +
|
||||
' margin-left:auto; margin-right:auto; }' +
|
||||
'.rd-status{ padding:28px; text-align:center; color:var(--dx-muted); font-size:var(--font-size-md); }' +
|
||||
'.rd-status.rd-failed{ font-weight:600; }' +
|
||||
|
||||
// ── head: RegionDetail.vue:47-51, a .stack--xs (7.5px) block, centred ──
|
||||
'.rd-head{ display:flex; flex-direction:column; gap:10px; text-align:center; }' +
|
||||
// ★ EVERY .stack HERE IS NOW THEIR MECHANISM, not `gap`. The goal card proved the two are not
|
||||
// interchangeable (a child's margin-top:auto can override a margin and cannot override a gap),
|
||||
// and the extended live diff then caught the residue: their .stack rowGap computes to `normal`
|
||||
// because the spacing is margin, while ours read 17.689px. Same pixels, different code — and the
|
||||
// DRIVER asked for the code to match, not just the screenshot. Converted, so the next
|
||||
// margin-overriding child anywhere on this page behaves as it does on their page.
|
||||
// .stack .stack--xs — --spacing-xs is 1rem at their 10px root.
|
||||
'.rd-head{ display:flex; flex-direction:column; text-align:center; }' +
|
||||
'.rd-head > * + *{ margin-top:10px; }' +
|
||||
'.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
|
||||
|
|
@ -734,7 +765,9 @@ useShadowStyles(
|
|||
// clone below is untouched by it.
|
||||
'.rd-chooser{ display:flex; flex-wrap:wrap; gap:13.3px; align-items:flex-end;' +
|
||||
' justify-content:center; }' +
|
||||
'.rd-mapblock{ display:flex; flex-direction:column; gap:13.3px; }' +
|
||||
// .stack .stack--sm — --spacing-sm, 1.33rem.
|
||||
'.rd-mapblock{ display:flex; flex-direction:column; }' +
|
||||
'.rd-mapblock > * + *{ margin-top:13.3px; }' +
|
||||
'.rd-mapnote{ margin:0; text-align:center; color:#92b195; font-weight:700; font-size:var(--font-size-md); }' +
|
||||
// .rounded-xlg on their <CountryMap>; the child takes border-radius:inherit from here.
|
||||
'.rd-mapframe{ border-radius:var(--dx-radius); overflow:hidden; }' +
|
||||
|
|
@ -776,7 +809,16 @@ useShadowStyles(
|
|||
// heading keeps the full clamp -- it has 1200px and no such constraint.
|
||||
// .stack--lg (var(--spacing-lg)) inside each card, centred; .region-goal pins to the bottom
|
||||
// (margin-top:auto) so three cards of different heights still align their goal lines.
|
||||
'.rd-goal-card{ display:flex; flex-direction:column; gap:var(--spacing-lg); text-align:center; }' +
|
||||
// ★ THEIR .stack IS margin-top, AND THAT IS LOAD-BEARING — not a stylistic detail.
|
||||
// composition/_stack.scss: `.stack > * + * { margin-top: var(--stack-spacing) }`, with
|
||||
// `.stack--lg` setting that to --spacing-lg. RegionDetail.vue's scoped
|
||||
// `.region-goal { margin-top: auto }` then OVERRIDES the same property on the last child,
|
||||
// so the goal line is pushed to the bottom and the 23.526px stack gap above it is GONE.
|
||||
// This was ported as `gap`, which margin cannot override: gap AND the auto both applied,
|
||||
// so every goal card carried ~23.5px of space their cards do not have. The DRIVER saw it
|
||||
// ('spcing is nto ths ame', naming these three cards). Ported as their mechanism.
|
||||
'.rd-goal-card{ display:flex; flex-direction:column; text-align:center; }' +
|
||||
'.rd-goal-card > * + *{ margin-top:var(--spacing-lg); }' +
|
||||
// h2: _globals.scss clamp(--font-size-2xl, 6vw, --font-size-4xl) = clamp(var(--font-size-2xl),_,var(--font-size-4xl))
|
||||
'.rd-h2{ margin:0; font-size:clamp(var(--font-size-2xl), 6cqw, var(--font-size-4xl)); line-height:1;' +
|
||||
' font-family:"Bebas Neue","Arial Narrow",BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,sans-serif;' +
|
||||
|
|
@ -791,8 +833,16 @@ useShadowStyles(
|
|||
'.rd-big{ margin:0; font-size:var(--font-size-4xl); font-weight:500; line-height:1.1; }' +
|
||||
'.rd-goal-card .rd-big{ white-space:nowrap; }' +
|
||||
'.rd-big-label{ margin:0; font-size:var(--font-size-lg); }' +
|
||||
'.rd-stack-xs{ display:flex; flex-direction:column; gap:10px; }' +
|
||||
'.rd-goal{ margin:auto 0 0; font-size:var(--font-size-sm); }' +
|
||||
// .stack .stack--xs, inside the Prayer Coverage card.
|
||||
'.rd-stack-xs{ display:flex; flex-direction:column; }' +
|
||||
'.rd-stack-xs > * + *{ margin-top:10px; }' +
|
||||
// .region-goal — margin-top:auto, spelled at higher specificity than the stack rule above
|
||||
// so the override is unambiguous rather than depending on source order.
|
||||
'.rd-goal{ margin:0; font-size:var(--font-size-sm); }' +
|
||||
// base/_globals.scss:200-202 — <strong> is --font-weight-medium (500) on their site, not the
|
||||
// UA's bold. The 'Goal:' label in all three cards is a <strong>, so ours was rendering 700.
|
||||
'.rd-root strong{ font-weight:500; }' +
|
||||
'.rd-goal-card > .rd-goal{ margin-top:auto; }' +
|
||||
|
||||
// ── .progress-bar: blocks/_progress-bar.scss. The HEIGHT comes from padding-top, not height
|
||||
// -- clamp(15px, 6%, 25px) at [data-size="md"] -- so the track scales with its own width.
|
||||
|
|
@ -817,16 +867,45 @@ useShadowStyles(
|
|||
// ── the breakdown table: RegionDetail.vue's scoped block. min-width 560px inside an
|
||||
// overflow-x:auto wrapper is how they keep five columns readable on a phone instead of
|
||||
// crushing them -- the table scrolls sideways, the page does not.
|
||||
'.rd-section{ display:flex; flex-direction:column; gap:var(--spacing-md); }' +
|
||||
// ★ base/_globals.scss:19-23 — their countries block is a <section>, and EVERY <section> on
|
||||
// their site carries padding-top clamp(--spacing-2xl, 6vw, --spacing-4xl) and padding-bottom
|
||||
// --spacing-4xl. At 1440 that is 73.614px above and below, ON TOP of the --spacing-3xl the
|
||||
// page stack already puts between blocks: 128.96px of air above the heading, where ours had
|
||||
// 55.35px and nothing below. Another global rule, another thing reading RegionDetail.vue
|
||||
// alone could not tell me. Same clamp, in container units for the embedded case.
|
||||
'.rd-section{ display:flex; flex-direction:column;' +
|
||||
' padding-top:clamp(var(--spacing-2xl), 6cqw, var(--spacing-4xl));' +
|
||||
' padding-bottom:var(--spacing-4xl); }' +
|
||||
'.rd-section > * + *{ margin-top:var(--spacing-md); }' + // .stack .stack--md
|
||||
|
||||
'.rd-table-scroll{ overflow-x:auto; }' +
|
||||
'.rd-table{ width:100%; min-width:560px; border-collapse:collapse; font-size:var(--font-size-md); }' +
|
||||
// ★ base/_globals.scss:99-105 — the part of their table that is NOT in RegionDetail's
|
||||
// scoped block and was therefore missed: every <table> on their site is a rounded,
|
||||
// ring-outlined WHITE card, and every <td> carries a 1px gridline (:205-207). Ours was a
|
||||
// bare borderless table on the page background. That is what the DRIVER meant by 'the
|
||||
// tbabel compoent is not the same' — the rule lived in a global stylesheet, not next to
|
||||
// the markup, so reading RegionDetail.vue alone could not show it.
|
||||
// overflow:hidden is what makes border-radius clip the header's own background.
|
||||
'.rd-table{ width:100%; min-width:560px; border-collapse:collapse; font-size:var(--font-size-md);' +
|
||||
' border-radius:var(--dx-radius-lg); overflow:hidden; background:#fff;' +
|
||||
' box-shadow:0 0 0 1px var(--dx-table-border); }' +
|
||||
// td ONLY — their th has no border of its own, it has the header fill.
|
||||
'.rd-table td{ border:1px solid var(--dx-table-border); }' +
|
||||
'.rd-table th, .rd-table td{ padding:var(--spacing-2xs) 13.3px; text-align:start; }' +
|
||||
'.rd-table th:not(:first-child), .rd-table td:not(:first-child){ text-align:end; }' +
|
||||
'.rd-table th{ background:var(--dx-muted); color:var(--dx-on-dark); font-weight:500; }' +
|
||||
'.rd-tr--selected{ background:#e8ece7; font-weight:600; }' +
|
||||
// ★ Their country cell is a <NuxtLink>, i.e. an <a>, which picks up base/_globals.scss:132-141:
|
||||
// --color-brand-light, --font-weight-medium, the UA underline at 2px thickness / 4px offset,
|
||||
// hovering to --color-brand-lighter. Ours is a <button> (it selects a subject in place
|
||||
// rather than navigating, which is the one thing this element does differently) and a
|
||||
// button inherits NONE of that — it read as plain body text, unweighted and unlined.
|
||||
// So the anchor rule is spelled out here: same element role, same appearance.
|
||||
'.rd-row-link{ appearance:none; background:none; border:0; padding:0; margin:0; cursor:pointer;' +
|
||||
' font:inherit; color:var(--dx-text); text-align:start; }' +
|
||||
'.rd-row-link:hover{ text-decoration:underline; }' +
|
||||
' font:inherit; font-weight:500; color:var(--dx-link); text-align:start;' +
|
||||
' text-decoration:underline; text-decoration-thickness:2px; text-underline-offset:4px;' +
|
||||
' text-decoration-skip-ink:auto; transition:color .3s ease; }' +
|
||||
'.rd-row-link:hover{ color:var(--dx-link-hover); }' +
|
||||
'.rd-row-link:focus-visible{ outline:2px solid var(--dx-accent); outline-offset:2px; border-radius:4px; }',
|
||||
'region-dashboards'
|
||||
)
|
||||
|
|
@ -837,7 +916,7 @@ useShadowStyles(
|
|||
<!-- a landmark, so a screen reader can jump to the dashboard body; the app probe
|
||||
measured none on the page and it costs nothing to name the region. -->
|
||||
<main class="rd-scroll" :aria-label="t('Region dashboard')">
|
||||
<div v-if="loading" class="rd-status">Loading region dashboards…</div>
|
||||
<div v-if="loading" class="rd-status">{{ t('Loading region dashboards…') }}</div>
|
||||
<div v-else-if="loadFailed" class="rd-status rd-failed" role="status">
|
||||
Region data could not be loaded. This is a connection problem, not a filter.
|
||||
</div>
|
||||
|
|
@ -928,6 +1007,8 @@ useShadowStyles(
|
|||
:color-mode="mapColorMode"
|
||||
:highlight-region="hoveredRegion"
|
||||
:select-on-pin-click="isAll"
|
||||
:pray-base-url="prayBaseUrl"
|
||||
:research-url="researchUrl"
|
||||
@pick-country="onPickFromMap"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -413,8 +413,18 @@ 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.
|
||||
// ★ 1rem WAS THE ONE UNIT IN THIS PORT THAT INHERITS THE HOST PAGE'S ROOT, and it was wrong on
|
||||
// our own leaf, not only in an embed. `rem` resolves against the DOCUMENT root wherever the
|
||||
// element lives — which is the whole reason dxlife-tokens.js resolves their scale to px — and
|
||||
// their root is 10px (html{font-size: var(--font-size-base)}, $font-size-base: 10px). Ours
|
||||
// inherits whatever the host sets: 16px by default, so this gap rendered 16px against their
|
||||
// 10px, and on a host with the common html{font-size:62.5%} reset it would render 10px by
|
||||
// accident. Pinned to the value their root produces, like every other token here.
|
||||
// No diff caught it: the list diff's `link` spec reads colour, decoration, weight, display and
|
||||
// alignItems — no margin — so the icon's own spacing was never a measured property. It is now.
|
||||
// (Credit where due: the class of bug came to me as a flock relay from another agent's sweep.)
|
||||
'.region-card__icon{ width:0.7em; height:0.7em; flex:none; fill:currentColor; transform:rotate(90deg);' +
|
||||
' margin-inline-start:1rem; }' +
|
||||
' margin-inline-start:10px; }' +
|
||||
// .region-card__summary: --font-size-md (var(--font-size-md)), 0.85 opacity, on the header band.
|
||||
'.region-card__summary{ font-size:var(--font-size-md); opacity:0.85; margin:0; }' +
|
||||
// .region-card__body: padding --spacing-lg / clamp(...) / --spacing-xl -> var(--spacing-lg) / clamp / var(--spacing-xl)
|
||||
|
|
@ -425,7 +435,9 @@ useShadowStyles(
|
|||
// one list-item's worth even though DX-life's countries-grid a rule doesn't set it directly.
|
||||
// Reproduced with list-style:none + the same 35.16px indent kept explicitly so a real list
|
||||
// bullet has somewhere to sit without stealing width from the text column.
|
||||
'.countries-grid{ list-style:none; margin:0; padding:0 0 0 35.2px; display:grid;' +
|
||||
// padding-INLINE-start, as theirs is (1.8em). The physical `padding-left:35.2px` it replaces
|
||||
// put the indent on the wrong side in Arabic, where the bullets hang off the right edge.
|
||||
'.countries-grid{ list-style:none; margin:0; padding-inline-start:1.8em; display:grid;' +
|
||||
' grid-template-columns:repeat(auto-fill, minmax(220px, 1fr)); gap:10px var(--spacing-xl); }' +
|
||||
// Plain inline text (not a flex row) so multi-line country names wrap the same way DX-life's
|
||||
// <NuxtLink> text does -- a flex row with align-items:baseline pinned the bullet to the first
|
||||
|
|
@ -441,8 +453,22 @@ useShadowStyles(
|
|||
// inset-inline-start, NOT left: the bullet hangs off the text's starting edge, which is the
|
||||
// RIGHT edge in Arabic. With `left:-16px` it stayed on the physical left in RTL — measured
|
||||
// at locale=ar, computed right was 256.938px instead of the -16px near-edge overhang.
|
||||
'.country-link::before{ content:""; position:absolute; inset-inline-start:-16px; top:0.6em; width:6px; height:6px;' +
|
||||
' border-radius:50%; background:#92b195; }' +
|
||||
// ★ THEIR BULLET, COPIED — not a dot of my own. base/_globals.scss:117-131 paints the list
|
||||
// marker with a 16x16 data-URI SVG circle in #92b195 sized to 1.5em, hung off the text's start
|
||||
// edge by margin-inline-start:-1.3em (-2em in RTL), top .3em, line-height .9. Their
|
||||
// .countries-grid comment is explicit that keeping it is deliberate ("Keeps the site's list
|
||||
// bullets (global ul padding + ::before dot)").
|
||||
// I had re-created it as a 6px border-radius:50% square, and MEASURED against live it was wrong
|
||||
// in 9 of 11 properties: 6px vs 29.2969px box, solid fill vs a transparent box carrying the
|
||||
// image, top 11.72px vs 5.86px, and positioned with inset-inline-start:-16px instead of their
|
||||
// negative margin. Not a near-miss — a different bullet.
|
||||
// The rule is a double-quoted JS string because the data URI contains single quotes.
|
||||
".country-link::before{ content:''; position:absolute; top:0.3em; width:1.5em; height:1.5em;" +
|
||||
" line-height:0.9; margin-inline-start:-1.3em; background-repeat:no-repeat;" +
|
||||
" background-image:url(\"data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='%2392b195' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='8' cy='8' r='7' stroke='%2392b195' stroke-width='1.5'/%3E%3C/svg%3E\"); }" +
|
||||
// Their RTL variant. It is a separate rule here rather than a nested [dir="rtl"] & because this
|
||||
// CSS lives in a shadow root, where a [dir] selector on an outer ancestor does not reach in.
|
||||
'[dir="rtl"] .country-link::before{ margin-inline-start:-2em; }' +
|
||||
'.country-link:hover{ text-decoration:underline; text-decoration-color:#92b195; }' +
|
||||
'.country-link:focus-visible{ outline:2px solid #92b195; outline-offset:2px; border-radius:4px; }' +
|
||||
'.country-link__count{ color:var(--dx-muted); }' +
|
||||
|
|
@ -514,7 +540,7 @@ useShadowStyles(
|
|||
<div v-else-if="loadFailed" class="rl-status rl-failed" role="status">
|
||||
Region data could not be loaded. This is a connection problem, not a filter.
|
||||
</div>
|
||||
<div v-else-if="!regions.length" class="rl-status">No regions found.</div>
|
||||
<div v-else-if="!regions.length" class="rl-status">{{ t('No regions found.') }}</div>
|
||||
|
||||
<template v-else>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -34,8 +34,14 @@ import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
|||
// check:one-palette exists because a private palette in a consumer is what once made two
|
||||
// surfaces disagree about what a colour meant.
|
||||
import { applyColor as regionColorExpression, PALETTE as REGION_PALETTE, getColor as regionColorFor } from '@map/colors/wagf-region.js'
|
||||
// ★ THIS FILE HAD NO t() AT ALL. Its legend rendered four hardcoded English strings on a page
|
||||
// whose every other word is translated into eleven languages, and three of those four were
|
||||
// ALREADY in the catalogue — translated for the Prayer Coverage card and hardcoded here.
|
||||
// Their CountryMap.vue calls t() for the same strings (:268-272).
|
||||
import { useRegionsI18n } from './useRegionsI18n.js'
|
||||
|
||||
|
||||
const { t, locale } = useRegionsI18n()
|
||||
const emit = defineEmits(['pick-country'])
|
||||
const props = defineProps({
|
||||
// ISO-3 codes to highlight, e.g. ['IND'] for a country or every code in a region.
|
||||
|
|
@ -56,6 +62,10 @@ const props = defineProps({
|
|||
zoom: { type: Number, default: 2 },
|
||||
// [[west, south], [east, north]] — takes precedence over center/zoom, as theirs does.
|
||||
bounds: { type: Array, default: null },
|
||||
// Their popup's two buttons (CountryMap.vue:156-158): Pray -> prayBaseUrl/<slug>?source=doxalife,
|
||||
// Full Profile -> researchUrl<slug>.
|
||||
prayBaseUrl: { type: String, default: 'https://pray.doxa.life' },
|
||||
researchUrl: { type: String, default: 'https://doxa.life/research/' },
|
||||
})
|
||||
|
||||
// The token ladder: ProfileLoader provides it (the same seam every map bundle uses). A nested
|
||||
|
|
@ -100,6 +110,9 @@ const geojson = computed(() => {
|
|||
inCountry: focus.has(p.code), committed: Number(p.committed) || 0,
|
||||
region: p.region || '', code: p.code || '',
|
||||
population: Number(p.population) || 0,
|
||||
// Their popup's four (CountryMap.vue:107-115). Primitives only, as their own comment says.
|
||||
rop1: p.rop1 || '', religion: p.religion || '',
|
||||
description: p.description || '', imageUrl: p.imageUrl || '',
|
||||
},
|
||||
})),
|
||||
}
|
||||
|
|
@ -298,19 +311,54 @@ function onPinClick(e) {
|
|||
const g = window.mapboxgl
|
||||
if (!g) return
|
||||
const p = f.properties || {}
|
||||
const pop = Number(p.population) || 0
|
||||
const html = '<div style="font:14px/1.45 Poppins,sans-serif;color:#2a332a">' +
|
||||
'<div style="font-weight:600;margin-bottom:2px">' + esc(p.name) + '</div>' +
|
||||
(p.country ? '<div style="color:#6d766e">' + esc(p.country) + '</div>' : '') +
|
||||
(pop ? '<div style="color:#6d766e">Population ' + pop.toLocaleString('en-US') + '</div>' : '') +
|
||||
'<div style="color:#6d766e">' + (Number(p.committed) || 0).toLocaleString('en-US') + ' praying</div>' +
|
||||
'</div>'
|
||||
const html = popupHtml(p)
|
||||
if (popup) popup.remove()
|
||||
popup = new g.Popup({ closeButton: true, maxWidth: '264px', offset: 12 })
|
||||
.setLngLat(f.geometry.coordinates).setHTML(html).addTo(map.value)
|
||||
}
|
||||
// THEIR escape, not a shorter one: CountryMap.vue:122-125 also escapes the two quote characters,
|
||||
// and this string is interpolated into href="" and alt="" attributes below, where omitting them is
|
||||
// the difference between an escape and a hole.
|
||||
function esc(s) {
|
||||
return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||
.replace(/"/g, '"').replace(/'/g, ''')
|
||||
}
|
||||
|
||||
// ★ THEIR PIN POPUP, PORTED — CountryMap.vue:130-161. Ours was a four-line stub: a bold name, the
|
||||
// country, "Population 12,345" and "678 praying", in English, with no photo, no religion, no
|
||||
// description and no way to act on it. Theirs is a card: the people group's photo, the name, the
|
||||
// country and its primary ethnolinguistic group, a definition list of Population / Religion /
|
||||
// Intercessors-out-of-100, up to three lines of the location description, and two buttons — Pray,
|
||||
// which is the entire point of the site, and Full Profile.
|
||||
// It could not have been ported before this pass because the DATA was not being fetched: rop1,
|
||||
// religion, location_description and the photo were missing from our field list.
|
||||
function popupHtml(p) {
|
||||
const name = esc(p.name || '')
|
||||
const subtitle = [p.country, p.rop1].filter(Boolean).map(esc).join(' · ')
|
||||
// Their formatPopulation: toLocaleString(languageCode), NOT a hardcoded 'en'. Ours printed
|
||||
// 'en-US' grouping in every one of the eleven locales.
|
||||
const pop = Number(p.population) > 0 ? Number(p.population).toLocaleString(locale.value || 'en') : ''
|
||||
const profileUrl = `${props.researchUrl}${p.slug || ''}`
|
||||
const prayUrl = `${String(props.prayBaseUrl).replace(/\/+$/, '')}/${p.slug || ''}?source=doxalife`
|
||||
|
||||
const rows = []
|
||||
if (pop) rows.push(`<div><dt>${esc(t('Population'))}</dt><dd>${pop}</dd></div>`)
|
||||
if (p.religion) rows.push(`<div><dt>${esc(t('Religion'))}</dt><dd>${esc(p.religion)}</dd></div>`)
|
||||
rows.push(`<div><dt>${esc(t('Intercessors'))}</dt><dd>${Number(p.committed) || 0}/${FULL_PRAYER_COVERAGE_COUNT}</dd></div>`)
|
||||
|
||||
return `<div class="cm-popup">
|
||||
${p.imageUrl ? `<img class="cm-popup__img" src="${esc(p.imageUrl)}" alt="${name}" loading="lazy">` : ''}
|
||||
<div class="cm-popup__body">
|
||||
<div class="cm-popup__name">${name}</div>
|
||||
${subtitle ? `<div class="cm-popup__sub">${subtitle}</div>` : ''}
|
||||
${rows.length ? `<dl class="cm-popup__stats">${rows.join('')}</dl>` : ''}
|
||||
${p.description ? `<p class="cm-popup__desc">${esc(p.description)}</p>` : ''}
|
||||
<div class="cm-popup__actions">
|
||||
<a class="cm-popup__btn cm-popup__btn--primary" href="${prayUrl}">${esc(t('Pray'))}</a>
|
||||
<a class="cm-popup__btn" href="${profileUrl}">${esc(t('Full Profile'))}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
}
|
||||
|
||||
// Re-frame and re-source on a new selection instead of tearing the map down: a rebuilt map
|
||||
|
|
@ -474,7 +522,34 @@ useShadowStyles(
|
|||
' flex-direction:column; gap:4px; padding:8px 10px; border-radius:8px;' +
|
||||
' background:rgba(255,255,255,0.92); font-size:12.5px; font-weight:600; color:#2a332a; }' +
|
||||
'.rcm__legend span{ display:inline-flex; align-items:center; gap:6px; }' +
|
||||
'.rcm__legend i{ width:10px; height:10px; border-radius:100px; flex:0 0 auto; }',
|
||||
'.rcm__legend i{ width:10px; height:10px; border-radius:100px; flex:0 0 auto; }' +
|
||||
|
||||
// ── THEIR PIN POPUP'S CSS, ported verbatim from CountryMap.vue's scoped block ──────────────
|
||||
// Mapbox builds the popup inside the map container, which is inside this shadow root, so these
|
||||
// reach it. The var() fallbacks are theirs and resolve to the same bytes here as there:
|
||||
// --color-brand is #3b463d and --color-brand-lighter #6d766e on live, identical to the
|
||||
// fallbacks, and --color-black is not defined on either side so #1f1f1f applies to both.
|
||||
'.mapboxgl-popup-content:has(.cm-popup){ padding:12px; border-radius:10px;' +
|
||||
' box-shadow:0 4px 16px rgba(0,0,0,0.18); }' +
|
||||
'.cm-popup{ width:240px; }' +
|
||||
'.cm-popup__img{ display:block; width:150px; aspect-ratio:4/5; object-fit:cover;' +
|
||||
' border-radius:8px; margin:0 auto 8px; }' +
|
||||
'.cm-popup__body{ padding:0; }' +
|
||||
'.cm-popup__name{ font-weight:700; font-size:15px; line-height:1.25;' +
|
||||
' color:var(--color-black, #1f1f1f); }' +
|
||||
'.cm-popup__sub{ margin-top:2px; font-size:12px; color:var(--color-brand-lighter, #6d766e); }' +
|
||||
'.cm-popup__stats{ margin:8px 0 0; display:flex; flex-direction:column; gap:3px; }' +
|
||||
'.cm-popup__stats > div{ display:flex; justify-content:space-between; gap:10px; font-size:12px; }' +
|
||||
'.cm-popup__stats dt{ margin:0; color:var(--color-brand-lighter, #6d766e); }' +
|
||||
'.cm-popup__stats dd{ margin:0; text-align:right; font-weight:600;' +
|
||||
' color:var(--color-black, #1f1f1f); }' +
|
||||
'.cm-popup__desc{ margin:8px 0 0; font-size:12px; line-height:1.45; color:#555;' +
|
||||
' display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; }' +
|
||||
'.cm-popup__actions{ display:flex; gap:6px; margin-top:10px; }' +
|
||||
'.cm-popup__btn{ flex:1; padding:6px 8px; border-radius:6px; font-size:12px; font-weight:600;' +
|
||||
' text-align:center; text-decoration:none; background:#ecf0f1;' +
|
||||
' color:var(--color-black, #1f1f1f); }' +
|
||||
'.cm-popup__btn--primary{ background:var(--color-brand, #3b463d); color:#fff; }',
|
||||
'region-country-map'
|
||||
)
|
||||
</script>
|
||||
|
|
@ -495,10 +570,10 @@ useShadowStyles(
|
|||
figures above are unaffected.
|
||||
</p>
|
||||
<div v-if="colorMode === 'prayer' && !mapFailed" class="rcm__legend">
|
||||
<span><i :style="{ background: C.prayerFull }" />100+ People Praying</span>
|
||||
<span><i :style="{ background: C.prayerPartial }" />1+ People Praying</span>
|
||||
<span><i :style="{ background: C.prayerNone }" />No One Praying</span>
|
||||
<span><i :style="{ background: C.outside }" />Outside this region</span>
|
||||
<span><i :style="{ background: C.prayerFull }" />{{ t('100+ People Praying') }}</span>
|
||||
<span><i :style="{ background: C.prayerPartial }" />{{ t('1+ People Praying') }}</span>
|
||||
<span><i :style="{ background: C.prayerNone }" />{{ t('No One Praying') }}</span>
|
||||
<span><i :style="{ background: C.outside }" />{{ t('Outside this region') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -347,15 +347,22 @@ useShadowStyles(
|
|||
' background-color:#fff; width:fit-content;' +
|
||||
' transition:border-color 150ms ease, background-color 150ms ease; }' +
|
||||
'.filter-toggle:hover{ border-color:#92b195; }' +
|
||||
// ★ THEIR ACTIVE STATE IS WHITE-ON-WHITE, CLONED ON PURPOSE. Their rule is
|
||||
// background-color: var(--color-surface-brand-lighter, rgba(0,80,160,0.05));
|
||||
// color: var(--color-white);
|
||||
// and --color-surface-brand-lighter is NOT DEFINED in their token files, so the 5%-alpha
|
||||
// fallback lands on white while the ink turns white. MEASURED on their live page: the
|
||||
// active button computes backgroundColor rgb(255,255,255) and color rgb(255,255,255) —
|
||||
// an invisible label. Reproduced so the clone matches; flagged for the Driver, because
|
||||
// defining that one token upstream fixes it for them and for us at once.
|
||||
'.filter-toggle[data-active]{ background-color:rgba(0, 80, 160, 0.05); color:#fff; }' +
|
||||
// ★ THIS SHIPPED AN ILLEGIBLE BUTTON FOR A CLONE OF A LEGIBLE ONE, and the comment that used to
|
||||
// sit here is why it lasted. It said their active state is white-on-white "on purpose", that
|
||||
// --color-surface-brand-lighter "is NOT DEFINED in their token files", and that the white-on-white
|
||||
// had been "MEASURED on their live page". Two of those three were wrong:
|
||||
// · tokens/semantic/_colors.scss:64 DOES define it — $color-green-300, #6d766e.
|
||||
// · getComputedStyle returns the SPECIFIED colour, never the composite, so neither candidate
|
||||
// could ever serialise as white: the token is #6d766e and the declared fallback is
|
||||
// rgba(0,80,160,0.05). The only rule on that button yielding white is .input's
|
||||
// var(--color-surface-white) — which is the INACTIVE state. The "measurement" had almost
|
||||
// certainly read a button without data-active set.
|
||||
// MEASURED PROPERLY (_probe-filter-state-vs-live.mjs, which CLICKS the Adopted filter on both
|
||||
// sides and then reads): their live active button is background rgb(109,118,110) on
|
||||
// color rgb(255,255,255). White on grey-green. Perfectly legible. We were shipping their DEAD
|
||||
// FALLBACK — 5%-alpha blue, which over the white .input ground leaves a white label on white.
|
||||
// So: the token's value, as theirs resolves it.
|
||||
'.filter-toggle[data-active]{ background-color:#6d766e; color:#fff; }' +
|
||||
'.filters__panel{ display:flex; flex-wrap:wrap; gap:13.3px; justify-content:center;' +
|
||||
' align-items:flex-start; }' +
|
||||
'.filters__active{ display:flex; flex-wrap:wrap; gap:var(--spacing-2xs); align-items:center;' +
|
||||
|
|
@ -366,8 +373,14 @@ useShadowStyles(
|
|||
'.filter-chip__remove{ background:none; border:0; cursor:pointer; font-size:1.1em; line-height:1;' +
|
||||
' color:inherit; padding:0; display:inline-flex; align-items:center; }' +
|
||||
'.filter-chip__remove:hover{ opacity:0.7; }' +
|
||||
// ★ Clear All is `.button compact link` on their side, and blocks/_buttons.scss:64-69 gives
|
||||
// .button.link `--button-text-color: var(--color-brand)` = $color-green-500 = #3b463d. Ours used
|
||||
// var(--dx-text) (#2a332a, the body ink) — a different green, measured against live as
|
||||
// rgb(42,51,42) vs their rgb(59,70,61). Found twice over, independently: by the applied-filter
|
||||
// diff, and by a static sweep of their markup's classes that flagged `.link` as a rule our CSS
|
||||
// had no equivalent for at all.
|
||||
'.filters__clear-all{ background:none; border:0; cursor:pointer; font:inherit; font-size:var(--font-size-sm);' +
|
||||
' color:var(--dx-text); text-decoration:underline; text-underline-offset:4px;' +
|
||||
' color:#3b463d; text-decoration:underline; text-underline-offset:4px;' +
|
||||
' text-decoration-thickness:2px; }' +
|
||||
// .repel — their space-between row (composition/_repel.scss), at --font-size-md gap.
|
||||
'.ul-total{ display:flex; gap:var(--spacing-md); justify-content:space-between; align-items:center; }' +
|
||||
|
|
|
|||
|
|
@ -55,8 +55,53 @@
|
|||
* ON via prop. This is why the swap-inside-one-element idea was genuinely complex: the two top
|
||||
* elements do not merely look different, they imply OPPOSITE control ownership below.
|
||||
*/
|
||||
import { computed } from 'vue'
|
||||
import StackLayout from '@map/layouts/StackLayout.vue'
|
||||
import { resolveEmbedBase } from '@map/utils/embedBase.js'
|
||||
import { publishMapToken } from '@map/composables/useSharedMapToken.js'
|
||||
|
||||
// ★ THE HOST'S OWN profile-config, WHICH THIS COMPOSITE USED TO THROW AWAY.
|
||||
// It declared no props at all, so a partner's <research-map-plus-grid profile-config='{"tk":"..."}'>
|
||||
// had its token dropped on the floor. On our own generated leaf that was invisible: the leaf page
|
||||
// carries a BAKED token, assigns window.MAP_TOKEN, and the shared-token bridge hands it to the
|
||||
// nested map. A partner page has no leaf and no baked token, so the JS embed — one of the two
|
||||
// shipped embed methods — mounted a map that could not draw. MEASURED on a third-party origin
|
||||
// before this: 'No Mapbox access token provided', 0 style and 0 tile requests, no canvas.
|
||||
const props = defineProps({
|
||||
/** The host's JSON config, exactly as the embed snippet writes it. */
|
||||
profileConfig: { type: [String, Object], default: null },
|
||||
})
|
||||
|
||||
const hostConfig = computed(() => {
|
||||
const raw = props.profileConfig
|
||||
if (!raw) return {}
|
||||
if (typeof raw === 'object') return raw
|
||||
// A malformed attribute must not take the whole element down with it — the map half is more
|
||||
// useful token-less than the page is with a thrown setup().
|
||||
try { return JSON.parse(raw) } catch { return {} }
|
||||
})
|
||||
|
||||
// Publish page-wide as well as threading it below. Threading covers THIS child deterministically;
|
||||
// publishing covers any element on the page that mounted before the attribute was read, which is
|
||||
// the shape the shared-token composable exists for.
|
||||
const hostToken = computed(() => {
|
||||
const tk = hostConfig.value?.tk
|
||||
return typeof tk === 'string' && tk ? tk : ''
|
||||
})
|
||||
if (hostToken.value) publishMapToken(hostToken.value)
|
||||
|
||||
// ★ THE PROVIDER IS A HOST KNOB TOO, AND FORGETTING IT BREAKS THE KEYLESS CASE ENTIRELY.
|
||||
// resolveMapProvider's ladder starts at profile-config.provider, and the child reads its OWN
|
||||
// profile-config — the one this file writes. A host asking for <research-map-plus-grid
|
||||
// profile-config='{"provider":"maplibre"}'> therefore got a child still on mapbox, which then
|
||||
// demanded a token. MEASURED on a third-party origin before this: 'No Mapbox access token
|
||||
// provided', 0 tiles, no canvas — for the exact configuration whose whole purpose is needing no
|
||||
// token. Keyless at volume is the reason MapLibre support exists; a composite that drops the
|
||||
// prop cancels it.
|
||||
const hostProvider = computed(() => {
|
||||
const p = hostConfig.value?.provider
|
||||
return p === 'maplibre' || p === 'mapbox' ? p : ''
|
||||
})
|
||||
|
||||
// The absolute url this composite is shared and iframed as. Built here rather than written as a
|
||||
// literal because resolveEmbedBase() walks profileConfig.embedBaseUrl → window.MAP_EMBED_BASE_URL →
|
||||
|
|
@ -103,7 +148,7 @@ const MAP_H = '88svh'
|
|||
const bundleSrc = (bundle, file) =>
|
||||
import.meta.env.DEV ? `/plugin-designs/${bundle}/index.js` : `../../${bundle}/${file}.js`
|
||||
|
||||
const sections = [
|
||||
const sections = computed(() => [
|
||||
// No section title: the research map self-titles through its own chrome, so a StackLayout title
|
||||
// here would render the name twice — the duplicate-header bug the Driver rejected on the desktop
|
||||
// sibling (BUG-RESEARCH-DASHBOARD-HEADER-STACK-WRONG). One header per element.
|
||||
|
|
@ -155,6 +200,12 @@ const sections = [
|
|||
// reader is scanning, a fly-tour that moves the camera underneath fights the other half.
|
||||
// The standalone leaf keeps both; this is a per-host decision, which is why it is config.
|
||||
legendTools: false,
|
||||
// Thread the host's token through to the child. Spread so a host that supplies none
|
||||
// leaves the key ABSENT rather than empty: ProfileLoader's ladder is `config.tk ||
|
||||
// sharedToken`, and an empty string would be falsy anyway, but an absent key keeps the
|
||||
// child's own config identical to what its standalone leaf sets.
|
||||
...(hostToken.value ? { tk: hostToken.value } : {}),
|
||||
...(hostProvider.value ? { provider: hostProvider.value } : {}),
|
||||
assetsBase: '../../assets',
|
||||
shareUrl: SHARE_URL
|
||||
})
|
||||
|
|
@ -176,7 +227,7 @@ const sections = [
|
|||
src: bundleSrc('people-groups-grid', 'people-groups-grid'),
|
||||
attrs: { 'show-search': 'true', 'show-filters': 'true', 'show-total': 'true' }
|
||||
}
|
||||
]
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
* layouts in library/layouts/. StackLayout mounts each section's `element` eagerly (all visible to
|
||||
* scroll) via the same element/src/attrs contract VerticalTabsLayout uses.
|
||||
*/
|
||||
import { computed } from 'vue'
|
||||
import StackLayout from '@map/layouts/StackLayout.vue'
|
||||
import { publishMapToken } from '@map/composables/useSharedMapToken.js'
|
||||
|
||||
// The two elements to stack. `src` is TREE-RELATIVE at build; the leaf pages resolve it against the
|
||||
// bundle tree root. Both elements ship their own bundles in the same catalog.
|
||||
|
|
@ -42,7 +44,30 @@ import StackLayout from '@map/layouts/StackLayout.vue'
|
|||
const bundleSrc = (bundle, file) =>
|
||||
import.meta.env.DEV ? `/plugin-designs/${bundle}/index.js` : `../../${bundle}/${file}.js`
|
||||
|
||||
const sections = [
|
||||
// ★ THE HOST'S OWN profile-config. This demo declared no props, so a partner embedding it with
|
||||
// <stack-demo profile-config='{"tk":"pk...."}'> had that token read by nobody and the nested
|
||||
// dashboard reported "No Mapbox access token provided" on a page with no baked token to fall back
|
||||
// on. Same defect the two shipped composites had; check:composite-embed-knobs names it.
|
||||
const props = defineProps({
|
||||
profileConfig: { type: [String, Object], default: null },
|
||||
})
|
||||
const hostConfig = computed(() => {
|
||||
const raw = props.profileConfig
|
||||
if (!raw) return {}
|
||||
if (typeof raw === 'object') return raw
|
||||
try { return JSON.parse(raw) } catch { return {} }
|
||||
})
|
||||
const hostToken = computed(() => {
|
||||
const tk = hostConfig.value?.tk
|
||||
return typeof tk === 'string' && tk ? tk : ''
|
||||
})
|
||||
if (hostToken.value) publishMapToken(hostToken.value)
|
||||
const hostProvider = computed(() => {
|
||||
const p = hostConfig.value?.provider
|
||||
return p === 'maplibre' || p === 'mapbox' ? p : ''
|
||||
})
|
||||
|
||||
const sections = computed(() => [
|
||||
{
|
||||
key: 'dashboard',
|
||||
title: 'Research Dashboard',
|
||||
|
|
@ -62,6 +87,10 @@ const sections = [
|
|||
profile: 'research-dashboard',
|
||||
dataSource: 'pray-tools',
|
||||
instanceId: 'stack-demo-research-dashboard',
|
||||
// Spread only when the host supplied one, so the nested mount otherwise asks for exactly
|
||||
// what its standalone leaf asks for.
|
||||
...(hostToken.value ? { tk: hostToken.value } : {}),
|
||||
...(hostProvider.value ? { provider: hostProvider.value } : {}),
|
||||
assetsBase: '../../assets'
|
||||
})
|
||||
}
|
||||
|
|
@ -73,7 +102,7 @@ const sections = [
|
|||
element: 'people-groups-grid',
|
||||
src: bundleSrc('people-groups-grid', 'people-groups-grid')
|
||||
}
|
||||
]
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -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-3kskcN7GLnCNNOrJINJt4n5ERXa0qpwyRNcuVuw4++2KzU0LwGYnLW3aepEu8jDg" crossorigin="anonymous"></script>
|
||||
<script src="../all-people-groups.js" integrity="sha384-i2Qv1FkHiMWhxFsOKGhfP4qSGTke/57SE1nrvk7ZV0lxfA5O92Ez6ZWf2dRbO88U" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
36
public/doxa-maps/cities-internet/cities-internet.js
generated
36
public/doxa-maps/cities-internet/cities-internet.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -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-b7gkA5+oZ8azx5oSxl4c985U9gcOFyNAh3TfhJd4FSUX4XawU0927HvYSFRTNzpr" crossorigin="anonymous"></script>
|
||||
<script src="../cities-internet.js" integrity="sha384-cLy6LqX5n+KGC7VdympqtscDcHqEKchYgMh4GJbHO5Z6X9nYcD3IT7/3Crq/BGEE" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-b7gkA5+oZ8azx5oSxl4c985U9gcOFyNAh3TfhJd4FSUX4XawU0927HvYSFRTNzpr" crossorigin="anonymous"></script>
|
||||
<script src="../cities-internet.js" integrity="sha384-cLy6LqX5n+KGC7VdympqtscDcHqEKchYgMh4GJbHO5Z6X9nYcD3IT7/3Crq/BGEE" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-b7gkA5+oZ8azx5oSxl4c985U9gcOFyNAh3TfhJd4FSUX4XawU0927HvYSFRTNzpr" crossorigin="anonymous"></script>
|
||||
<script src="../cities-internet.js" integrity="sha384-cLy6LqX5n+KGC7VdympqtscDcHqEKchYgMh4GJbHO5Z6X9nYcD3IT7/3Crq/BGEE" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-amheyqep13c83pKspBiNh8x4DIm5S/L7ifL34zSxsAe+LbpB0YW7DPH+a30ba6Xc" crossorigin="anonymous"></script>
|
||||
<script src="../country-posters.js" integrity="sha384-S0O8LKY8FDeykxEoMkbMbI7dHp8DZQlNAxW+xj+9rJ/XDvlGUvY4t9zEnuRym7hd" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-amheyqep13c83pKspBiNh8x4DIm5S/L7ifL34zSxsAe+LbpB0YW7DPH+a30ba6Xc" crossorigin="anonymous"></script>
|
||||
<script src="../country-posters.js" integrity="sha384-S0O8LKY8FDeykxEoMkbMbI7dHp8DZQlNAxW+xj+9rJ/XDvlGUvY4t9zEnuRym7hd" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-amheyqep13c83pKspBiNh8x4DIm5S/L7ifL34zSxsAe+LbpB0YW7DPH+a30ba6Xc" crossorigin="anonymous"></script>
|
||||
<script src="../country-posters.js" integrity="sha384-S0O8LKY8FDeykxEoMkbMbI7dHp8DZQlNAxW+xj+9rJ/XDvlGUvY4t9zEnuRym7hd" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
240
public/doxa-maps/country-posters/country-posters.js
generated
240
public/doxa-maps/country-posters/country-posters.js
generated
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -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-VOkoTUw4VURBoPSbk3YnU3Wc/JuN+ywf1eF9D6RHBI2Be/8N8FlY3WX/2CkNk5NS" crossorigin="anonymous"></script>
|
||||
<script src="../../dashboard-plus-grid.js" integrity="sha384-azKIIIa3yMfrc8/hxS9kf+J2zIQGcw/p/SxLoyil51AqGaH+MJad4mxPI9bycxiL" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-VOkoTUw4VURBoPSbk3YnU3Wc/JuN+ywf1eF9D6RHBI2Be/8N8FlY3WX/2CkNk5NS" crossorigin="anonymous"></script>
|
||||
<script src="../dashboard-plus-grid.js" integrity="sha384-azKIIIa3yMfrc8/hxS9kf+J2zIQGcw/p/SxLoyil51AqGaH+MJad4mxPI9bycxiL" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
52
public/doxa-maps/demo-map/demo-map.js
generated
52
public/doxa-maps/demo-map/demo-map.js
generated
File diff suppressed because one or more lines are too long
2
public/doxa-maps/demo-map/demo-map/index.html
generated
2
public/doxa-maps/demo-map/demo-map/index.html
generated
|
|
@ -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-WLB+/GTY8u9CWAKt72vKJroKi26oGzzjlGdA0iA3DSSP9oWHnUb8r6jtjAWSw0ee" crossorigin="anonymous"></script>
|
||||
<script src="../demo-map.js" integrity="sha384-VGZMQWOWVouP4IkUTsZ/ElUORaUYu9+wJSlbs/8r6Lc6EU8VvLYHhmTOGCJv2Y6H" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-WLB+/GTY8u9CWAKt72vKJroKi26oGzzjlGdA0iA3DSSP9oWHnUb8r6jtjAWSw0ee" crossorigin="anonymous"></script>
|
||||
<script src="../../demo-map.js" integrity="sha384-VGZMQWOWVouP4IkUTsZ/ElUORaUYu9+wJSlbs/8r6Lc6EU8VvLYHhmTOGCJv2Y6H" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
2
public/doxa-maps/doxa-maps-spa/doxa-maps-spa.js
generated
2
public/doxa-maps/doxa-maps-spa/doxa-maps-spa.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <doxa-maps-spa> custom element. -->
|
||||
<script src="../../doxa-maps-spa.js" integrity="sha384-fmp37RdhrkxuguGQ5MmwnakDu0So2YCJSYj8Bca867HoKCT1497o9z3K/wlHDlxP" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-maps-spa.js" integrity="sha384-Cmdw0USq0X4/+OshXBayXKy4U5ZBD0bR8YR/yaR/CZ76CYEMpb4bymgfug+5AGyU" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <doxa-maps-spa> custom element. -->
|
||||
<script src="../doxa-maps-spa.js" integrity="sha384-fmp37RdhrkxuguGQ5MmwnakDu0So2YCJSYj8Bca867HoKCT1497o9z3K/wlHDlxP" crossorigin="anonymous"></script>
|
||||
<script src="../doxa-maps-spa.js" integrity="sha384-Cmdw0USq0X4/+OshXBayXKy4U5ZBD0bR8YR/yaR/CZ76CYEMpb4bymgfug+5AGyU" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
104
public/doxa-maps/doxa-research-map/doxa-research-map.js
generated
104
public/doxa-maps/doxa-research-map/doxa-research-map.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -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-LyIs0sqdkyJcj3DESqefXc7jsD96o+H+YVcOIq2kCdwaS+ZeBLqcn//06n1W1blE" crossorigin="anonymous"></script>
|
||||
<script src="../doxa-research-map.js" integrity="sha384-E7/WP0pDnwiG6noaZZI3Sx92Cg3JwluCqYOA5eU+x+UARKkliojcJBk3Yx6jua7a" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-LyIs0sqdkyJcj3DESqefXc7jsD96o+H+YVcOIq2kCdwaS+ZeBLqcn//06n1W1blE" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-research-map.js" integrity="sha384-E7/WP0pDnwiG6noaZZI3Sx92Cg3JwluCqYOA5eU+x+UARKkliojcJBk3Yx6jua7a" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
88
public/doxa-maps/doxa-simple-map/doxa-simple-map.js
generated
88
public/doxa-maps/doxa-simple-map/doxa-simple-map.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -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-FtEGLeSRNfBCdmK26IURIxCldSnfKphxRT74XgjftFGzNpvube+ov/EVBFi2gXjo" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-simple-map.js" integrity="sha384-r/K0P50Wt1Qz2KkJ+fVPurKtAr68GqWKREiLb8DYZ2L0VmOQUE9FwZhrDMZzYscr" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-FtEGLeSRNfBCdmK26IURIxCldSnfKphxRT74XgjftFGzNpvube+ov/EVBFi2gXjo" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-simple-map.js" integrity="sha384-r/K0P50Wt1Qz2KkJ+fVPurKtAr68GqWKREiLb8DYZ2L0VmOQUE9FwZhrDMZzYscr" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-FtEGLeSRNfBCdmK26IURIxCldSnfKphxRT74XgjftFGzNpvube+ov/EVBFi2gXjo" crossorigin="anonymous"></script>
|
||||
<script src="../doxa-simple-map.js" integrity="sha384-r/K0P50Wt1Qz2KkJ+fVPurKtAr68GqWKREiLb8DYZ2L0VmOQUE9FwZhrDMZzYscr" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-FtEGLeSRNfBCdmK26IURIxCldSnfKphxRT74XgjftFGzNpvube+ov/EVBFi2gXjo" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-simple-map.js" integrity="sha384-r/K0P50Wt1Qz2KkJ+fVPurKtAr68GqWKREiLb8DYZ2L0VmOQUE9FwZhrDMZzYscr" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-ltb70sEfk/M2TgjZ3hyZxrAL3R3TEpo7BnLnNXD+8fiEZjiNdln70Tj4z80qCn5M" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-Zk0IwHEx3TcFvlDr4oICFoK+g1HlmsVtkxl0xj/qQoifnjvbMN/DTKdI5VpncEf7" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-ltb70sEfk/M2TgjZ3hyZxrAL3R3TEpo7BnLnNXD+8fiEZjiNdln70Tj4z80qCn5M" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-Zk0IwHEx3TcFvlDr4oICFoK+g1HlmsVtkxl0xj/qQoifnjvbMN/DTKdI5VpncEf7" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -40,7 +40,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-ltb70sEfk/M2TgjZ3hyZxrAL3R3TEpo7BnLnNXD+8fiEZjiNdln70Tj4z80qCn5M" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-Zk0IwHEx3TcFvlDr4oICFoK+g1HlmsVtkxl0xj/qQoifnjvbMN/DTKdI5VpncEf7" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -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-ltb70sEfk/M2TgjZ3hyZxrAL3R3TEpo7BnLnNXD+8fiEZjiNdln70Tj4z80qCn5M" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-Zk0IwHEx3TcFvlDr4oICFoK+g1HlmsVtkxl0xj/qQoifnjvbMN/DTKdI5VpncEf7" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-ltb70sEfk/M2TgjZ3hyZxrAL3R3TEpo7BnLnNXD+8fiEZjiNdln70Tj4z80qCn5M" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-Zk0IwHEx3TcFvlDr4oICFoK+g1HlmsVtkxl0xj/qQoifnjvbMN/DTKdI5VpncEf7" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
2
public/doxa-maps/index.html
generated
2
public/doxa-maps/index.html
generated
File diff suppressed because one or more lines are too long
140
public/doxa-maps/key-cities/key-cities.js
generated
140
public/doxa-maps/key-cities/key-cities.js
generated
File diff suppressed because one or more lines are too long
94
public/doxa-maps/manifest.json
generated
94
public/doxa-maps/manifest.json
generated
|
|
@ -13,7 +13,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-3kskcN7GLnCNNOrJINJt4n5ERXa0qpwyRNcuVuw4++2KzU0LwGYnLW3aepEu8jDg",
|
||||
"integrity": "sha384-i2Qv1FkHiMWhxFsOKGhfP4qSGTke/57SE1nrvk7ZV0lxfA5O92Ez6ZWf2dRbO88U",
|
||||
"elements": [
|
||||
"all-people-groups"
|
||||
],
|
||||
|
|
@ -29,7 +29,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-3kskcN7GLnCNNOrJINJt4n5ERXa0qpwyRNcuVuw4++2KzU0LwGYnLW3aepEu8jDg\" 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-i2Qv1FkHiMWhxFsOKGhfP4qSGTke/57SE1nrvk7ZV0lxfA5O92Ez6ZWf2dRbO88U\" 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"
|
||||
}
|
||||
|
|
@ -105,7 +105,7 @@
|
|||
"bundle": "cities-internet",
|
||||
"scriptUrl": "./cities-internet/cities-internet.js",
|
||||
"output": "doxa-maps/cities-internet/cities-internet.js",
|
||||
"integrity": "sha384-b7gkA5+oZ8azx5oSxl4c985U9gcOFyNAh3TfhJd4FSUX4XawU0927HvYSFRTNzpr",
|
||||
"integrity": "sha384-cLy6LqX5n+KGC7VdympqtscDcHqEKchYgMh4GJbHO5Z6X9nYcD3IT7/3Crq/BGEE",
|
||||
"elements": [
|
||||
"cities-internet-map"
|
||||
],
|
||||
|
|
@ -121,7 +121,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-b7gkA5+oZ8azx5oSxl4c985U9gcOFyNAh3TfhJd4FSUX4XawU0927HvYSFRTNzpr\" 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-cLy6LqX5n+KGC7VdympqtscDcHqEKchYgMh4GJbHO5Z6X9nYcD3IT7/3Crq/BGEE\" 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>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -135,7 +135,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-b7gkA5+oZ8azx5oSxl4c985U9gcOFyNAh3TfhJd4FSUX4XawU0927HvYSFRTNzpr\" 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-cLy6LqX5n+KGC7VdympqtscDcHqEKchYgMh4GJbHO5Z6X9nYcD3IT7/3Crq/BGEE\" 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>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -149,7 +149,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-b7gkA5+oZ8azx5oSxl4c985U9gcOFyNAh3TfhJd4FSUX4XawU0927HvYSFRTNzpr\" 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-cLy6LqX5n+KGC7VdympqtscDcHqEKchYgMh4GJbHO5Z6X9nYcD3IT7/3Crq/BGEE\" 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>"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -158,7 +158,7 @@
|
|||
"bundle": "country-posters",
|
||||
"scriptUrl": "./country-posters/country-posters.js",
|
||||
"output": "doxa-maps/country-posters/country-posters.js",
|
||||
"integrity": "sha384-amheyqep13c83pKspBiNh8x4DIm5S/L7ifL34zSxsAe+LbpB0YW7DPH+a30ba6Xc",
|
||||
"integrity": "sha384-S0O8LKY8FDeykxEoMkbMbI7dHp8DZQlNAxW+xj+9rJ/XDvlGUvY4t9zEnuRym7hd",
|
||||
"elements": [
|
||||
"country-posters-map"
|
||||
],
|
||||
|
|
@ -178,7 +178,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-amheyqep13c83pKspBiNh8x4DIm5S/L7ifL34zSxsAe+LbpB0YW7DPH+a30ba6Xc\" 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-S0O8LKY8FDeykxEoMkbMbI7dHp8DZQlNAxW+xj+9rJ/XDvlGUvY4t9zEnuRym7hd\" 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>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -192,7 +192,7 @@
|
|||
"scriptUrl": "./country-posters/country-posters.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./country-posters/country-poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-amheyqep13c83pKspBiNh8x4DIm5S/L7ifL34zSxsAe+LbpB0YW7DPH+a30ba6Xc\" 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-S0O8LKY8FDeykxEoMkbMbI7dHp8DZQlNAxW+xj+9rJ/XDvlGUvY4t9zEnuRym7hd\" 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>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -206,7 +206,7 @@
|
|||
"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-amheyqep13c83pKspBiNh8x4DIm5S/L7ifL34zSxsAe+LbpB0YW7DPH+a30ba6Xc\" 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-S0O8LKY8FDeykxEoMkbMbI7dHp8DZQlNAxW+xj+9rJ/XDvlGUvY4t9zEnuRym7hd\" 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>"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -215,7 +215,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-VOkoTUw4VURBoPSbk3YnU3Wc/JuN+ywf1eF9D6RHBI2Be/8N8FlY3WX/2CkNk5NS",
|
||||
"integrity": "sha384-azKIIIa3yMfrc8/hxS9kf+J2zIQGcw/p/SxLoyil51AqGaH+MJad4mxPI9bycxiL",
|
||||
"elements": [
|
||||
"dashboard-plus-grid"
|
||||
],
|
||||
|
|
@ -235,7 +235,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-VOkoTUw4VURBoPSbk3YnU3Wc/JuN+ywf1eF9D6RHBI2Be/8N8FlY3WX/2CkNk5NS\" 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-azKIIIa3yMfrc8/hxS9kf+J2zIQGcw/p/SxLoyil51AqGaH+MJad4mxPI9bycxiL\" 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": [
|
||||
{
|
||||
|
|
@ -259,7 +259,7 @@
|
|||
"bundle": "demo-map",
|
||||
"scriptUrl": "./demo-map/demo-map.js",
|
||||
"output": "doxa-maps/demo-map/demo-map.js",
|
||||
"integrity": "sha384-WLB+/GTY8u9CWAKt72vKJroKi26oGzzjlGdA0iA3DSSP9oWHnUb8r6jtjAWSw0ee",
|
||||
"integrity": "sha384-VGZMQWOWVouP4IkUTsZ/ElUORaUYu9+wJSlbs/8r6Lc6EU8VvLYHhmTOGCJv2Y6H",
|
||||
"elements": [
|
||||
"demo-map"
|
||||
],
|
||||
|
|
@ -275,7 +275,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-WLB+/GTY8u9CWAKt72vKJroKi26oGzzjlGdA0iA3DSSP9oWHnUb8r6jtjAWSw0ee\" 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-VGZMQWOWVouP4IkUTsZ/ElUORaUYu9+wJSlbs/8r6Lc6EU8VvLYHhmTOGCJv2Y6H\" 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": [
|
||||
{
|
||||
|
|
@ -302,7 +302,7 @@
|
|||
"bundle": "doxa-maps-spa",
|
||||
"scriptUrl": "./doxa-maps-spa/doxa-maps-spa.js",
|
||||
"output": "doxa-maps/doxa-maps-spa/doxa-maps-spa.js",
|
||||
"integrity": "sha384-fmp37RdhrkxuguGQ5MmwnakDu0So2YCJSYj8Bca867HoKCT1497o9z3K/wlHDlxP",
|
||||
"integrity": "sha384-Cmdw0USq0X4/+OshXBayXKy4U5ZBD0bR8YR/yaR/CZ76CYEMpb4bymgfug+5AGyU",
|
||||
"elements": [
|
||||
"doxa-maps-spa"
|
||||
],
|
||||
|
|
@ -327,7 +327,7 @@
|
|||
"scriptUrl": "./doxa-maps-spa/doxa-maps-spa.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./doxa-maps-spa/doxa-maps-spa/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-maps-spa/doxa-maps-spa.js\" integrity=\"sha384-fmp37RdhrkxuguGQ5MmwnakDu0So2YCJSYj8Bca867HoKCT1497o9z3K/wlHDlxP\" crossorigin=\"anonymous\"></script>\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-maps-spa/doxa-maps-spa.js\" integrity=\"sha384-Cmdw0USq0X4/+OshXBayXKy4U5ZBD0bR8YR/yaR/CZ76CYEMpb4bymgfug+5AGyU\" crossorigin=\"anonymous\"></script>\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
@ -354,7 +354,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-LyIs0sqdkyJcj3DESqefXc7jsD96o+H+YVcOIq2kCdwaS+ZeBLqcn//06n1W1blE",
|
||||
"integrity": "sha384-E7/WP0pDnwiG6noaZZI3Sx92Cg3JwluCqYOA5eU+x+UARKkliojcJBk3Yx6jua7a",
|
||||
"elements": [
|
||||
"doxa-research-map"
|
||||
],
|
||||
|
|
@ -370,7 +370,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-LyIs0sqdkyJcj3DESqefXc7jsD96o+H+YVcOIq2kCdwaS+ZeBLqcn//06n1W1blE\" 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-E7/WP0pDnwiG6noaZZI3Sx92Cg3JwluCqYOA5eU+x+UARKkliojcJBk3Yx6jua7a\" 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": [
|
||||
{
|
||||
|
|
@ -396,7 +396,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-FtEGLeSRNfBCdmK26IURIxCldSnfKphxRT74XgjftFGzNpvube+ov/EVBFi2gXjo",
|
||||
"integrity": "sha384-r/K0P50Wt1Qz2KkJ+fVPurKtAr68GqWKREiLb8DYZ2L0VmOQUE9FwZhrDMZzYscr",
|
||||
"elements": [
|
||||
"doxa-map",
|
||||
"doxa-simple-map"
|
||||
|
|
@ -413,7 +413,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-FtEGLeSRNfBCdmK26IURIxCldSnfKphxRT74XgjftFGzNpvube+ov/EVBFi2gXjo\" 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-r/K0P50Wt1Qz2KkJ+fVPurKtAr68GqWKREiLb8DYZ2L0VmOQUE9FwZhrDMZzYscr\" 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": [
|
||||
{
|
||||
|
|
@ -596,7 +596,7 @@
|
|||
"bundle": "gospel-resources",
|
||||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"output": "doxa-maps/gospel-resources/gospel-resources.js",
|
||||
"integrity": "sha384-ltb70sEfk/M2TgjZ3hyZxrAL3R3TEpo7BnLnNXD+8fiEZjiNdln70Tj4z80qCn5M",
|
||||
"integrity": "sha384-Zk0IwHEx3TcFvlDr4oICFoK+g1HlmsVtkxl0xj/qQoifnjvbMN/DTKdI5VpncEf7",
|
||||
"elements": [
|
||||
"gospel-resources-map"
|
||||
],
|
||||
|
|
@ -616,7 +616,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-ltb70sEfk/M2TgjZ3hyZxrAL3R3TEpo7BnLnNXD+8fiEZjiNdln70Tj4z80qCn5M\" 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-Zk0IwHEx3TcFvlDr4oICFoK+g1HlmsVtkxl0xj/qQoifnjvbMN/DTKdI5VpncEf7\" 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>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -630,7 +630,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-ltb70sEfk/M2TgjZ3hyZxrAL3R3TEpo7BnLnNXD+8fiEZjiNdln70Tj4z80qCn5M\" 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-Zk0IwHEx3TcFvlDr4oICFoK+g1HlmsVtkxl0xj/qQoifnjvbMN/DTKdI5VpncEf7\" 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>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -644,7 +644,7 @@
|
|||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./gospel-resources/gospel-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=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-ltb70sEfk/M2TgjZ3hyZxrAL3R3TEpo7BnLnNXD+8fiEZjiNdln70Tj4z80qCn5M\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"gospel-dashboard\",\"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-Zk0IwHEx3TcFvlDr4oICFoK+g1HlmsVtkxl0xj/qQoifnjvbMN/DTKdI5VpncEf7\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"gospel-dashboard\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -658,7 +658,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-ltb70sEfk/M2TgjZ3hyZxrAL3R3TEpo7BnLnNXD+8fiEZjiNdln70Tj4z80qCn5M\" 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-Zk0IwHEx3TcFvlDr4oICFoK+g1HlmsVtkxl0xj/qQoifnjvbMN/DTKdI5VpncEf7\" 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>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -672,7 +672,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-ltb70sEfk/M2TgjZ3hyZxrAL3R3TEpo7BnLnNXD+8fiEZjiNdln70Tj4z80qCn5M\" 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-Zk0IwHEx3TcFvlDr4oICFoK+g1HlmsVtkxl0xj/qQoifnjvbMN/DTKdI5VpncEf7\" 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>"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -681,7 +681,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-4WnbHvh/qt/xIADBpWm8xKj0gcGj6hStHIGhrTLibVZtGGga8Bd/YXh31SD/tDCv",
|
||||
"integrity": "sha384-eEbOnVD6pMXOvGXN1VAnX8J3UfTAVruDCirw1585wIGTS+LwN/gCvupPPecye4yf",
|
||||
"elements": [
|
||||
"my-upg-100-list-map"
|
||||
],
|
||||
|
|
@ -701,7 +701,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-4WnbHvh/qt/xIADBpWm8xKj0gcGj6hStHIGhrTLibVZtGGga8Bd/YXh31SD/tDCv\" 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-eEbOnVD6pMXOvGXN1VAnX8J3UfTAVruDCirw1585wIGTS+LwN/gCvupPPecye4yf\" 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>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -715,7 +715,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-4WnbHvh/qt/xIADBpWm8xKj0gcGj6hStHIGhrTLibVZtGGga8Bd/YXh31SD/tDCv\" 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-eEbOnVD6pMXOvGXN1VAnX8J3UfTAVruDCirw1585wIGTS+LwN/gCvupPPecye4yf\" 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>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -729,7 +729,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-4WnbHvh/qt/xIADBpWm8xKj0gcGj6hStHIGhrTLibVZtGGga8Bd/YXh31SD/tDCv\" 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-eEbOnVD6pMXOvGXN1VAnX8J3UfTAVruDCirw1585wIGTS+LwN/gCvupPPecye4yf\" 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>"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -799,7 +799,7 @@
|
|||
"bundle": "plugin-studio",
|
||||
"scriptUrl": "./plugin-studio/plugin-studio.js",
|
||||
"output": "doxa-maps/plugin-studio/plugin-studio.js",
|
||||
"integrity": "sha384-2RlLFRU2XdjBN7w+FPguj8INgj57JFg4IFT2AmdefGnR9QQLehbiiAffV45LcsFH",
|
||||
"integrity": "sha384-D++rzhYeOQb6jBAa8CIB+8VvmvRij/YX1WF9TVHHLkGmUZUZSoOwUx6cgFuzkHOS",
|
||||
"elements": [
|
||||
"plugin-studio"
|
||||
],
|
||||
|
|
@ -827,7 +827,7 @@
|
|||
"scriptUrl": "./plugin-studio/plugin-studio.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./plugin-studio/plugin-studio/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=\"./plugin-studio/plugin-studio.js\" integrity=\"sha384-2RlLFRU2XdjBN7w+FPguj8INgj57JFg4IFT2AmdefGnR9QQLehbiiAffV45LcsFH\" crossorigin=\"anonymous\"></script>\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./plugin-studio/plugin-studio.js\" integrity=\"sha384-D++rzhYeOQb6jBAa8CIB+8VvmvRij/YX1WF9TVHHLkGmUZUZSoOwUx6cgFuzkHOS\" crossorigin=\"anonymous\"></script>\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
@ -879,7 +879,7 @@
|
|||
"bundle": "regions-dashboard",
|
||||
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
|
||||
"output": "doxa-maps/regions-dashboard/regions-dashboard.js",
|
||||
"integrity": "sha384-o2n8vzVstdRyYCQ4YnWVCpZYCOfaNGa+4BABLAeVw5vuXbnm1R71Zx3WT9FJc22n",
|
||||
"integrity": "sha384-RROi/svcB/vhqo1W8SwZCYhJbi2HbGft9lGxxJQ4UAYjNzrbHKjSzJ6MmS7imr6o",
|
||||
"elements": [
|
||||
"regions-dashboard"
|
||||
],
|
||||
|
|
@ -899,7 +899,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-o2n8vzVstdRyYCQ4YnWVCpZYCOfaNGa+4BABLAeVw5vuXbnm1R71Zx3WT9FJc22n\" 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-RROi/svcB/vhqo1W8SwZCYhJbi2HbGft9lGxxJQ4UAYjNzrbHKjSzJ6MmS7imr6o\" 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>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -913,7 +913,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-o2n8vzVstdRyYCQ4YnWVCpZYCOfaNGa+4BABLAeVw5vuXbnm1R71Zx3WT9FJc22n\" 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-RROi/svcB/vhqo1W8SwZCYhJbi2HbGft9lGxxJQ4UAYjNzrbHKjSzJ6MmS7imr6o\" 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>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -927,7 +927,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-o2n8vzVstdRyYCQ4YnWVCpZYCOfaNGa+4BABLAeVw5vuXbnm1R71Zx3WT9FJc22n\" 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-RROi/svcB/vhqo1W8SwZCYhJbi2HbGft9lGxxJQ4UAYjNzrbHKjSzJ6MmS7imr6o\" 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>"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -936,7 +936,7 @@
|
|||
"bundle": "research-dashboard",
|
||||
"scriptUrl": "./research-dashboard/research-dashboard.js",
|
||||
"output": "doxa-maps/research-dashboard/research-dashboard.js",
|
||||
"integrity": "sha384-tAUIe2wERKg/ZRvINilfjrgfNYZeix7iSXYTJI1iSvf3eRtafkVt1a8cHIGyyRTF",
|
||||
"integrity": "sha384-hlPWMwkdwPg7Ze8QD4PwXTNv65fDKqwUOCrtX8NsH8h+rZHK1rZSnq43Vsz9O7Kt",
|
||||
"elements": [
|
||||
"research-dashboard-map"
|
||||
],
|
||||
|
|
@ -952,7 +952,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-tAUIe2wERKg/ZRvINilfjrgfNYZeix7iSXYTJI1iSvf3eRtafkVt1a8cHIGyyRTF\" 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-hlPWMwkdwPg7Ze8QD4PwXTNv65fDKqwUOCrtX8NsH8h+rZHK1rZSnq43Vsz9O7Kt\" 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"
|
||||
}
|
||||
|
|
@ -962,7 +962,7 @@
|
|||
"bundle": "research-map-plus-grid",
|
||||
"scriptUrl": "./research-map-plus-grid/research-map-plus-grid.js",
|
||||
"output": "doxa-maps/research-map-plus-grid/research-map-plus-grid.js",
|
||||
"integrity": "sha384-sOkaMV0UFr2uNXfoJpRvaD+gHD6xFlkmpR7MzEwwFdarYdid8aN9Nj1Y8TqQJuFo",
|
||||
"integrity": "sha384-LQYR+uASPJFjo/VTpIpAVxUv+O5KrgBqfOFYOcOi0ZmIvtwcjWTZV4AjAr2ewc7Z",
|
||||
"elements": [
|
||||
"research-map-plus-grid"
|
||||
],
|
||||
|
|
@ -982,7 +982,7 @@
|
|||
"scriptUrl": "./research-map-plus-grid/research-map-plus-grid.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./research-map-plus-grid/research-map-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=\"./research-map-plus-grid/research-map-plus-grid.js\" integrity=\"sha384-sOkaMV0UFr2uNXfoJpRvaD+gHD6xFlkmpR7MzEwwFdarYdid8aN9Nj1Y8TqQJuFo\" crossorigin=\"anonymous\"></script>\n<research-map-plus-grid profile-config='{\"profile\":\"research-map-plus-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-map-plus-grid>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-map-plus-grid/research-map-plus-grid.js\" integrity=\"sha384-LQYR+uASPJFjo/VTpIpAVxUv+O5KrgBqfOFYOcOi0ZmIvtwcjWTZV4AjAr2ewc7Z\" crossorigin=\"anonymous\"></script>\n<research-map-plus-grid profile-config='{\"profile\":\"research-map-plus-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-map-plus-grid>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
@ -1006,7 +1006,7 @@
|
|||
"bundle": "stack-demo",
|
||||
"scriptUrl": "./stack-demo/stack-demo.js",
|
||||
"output": "doxa-maps/stack-demo/stack-demo.js",
|
||||
"integrity": "sha384-gnwM6s+puf1K60Nl7crQcC2QC+9BxwpkaTx4OepLZ8VUCraZc+aRlWpsb6nj6Gyf",
|
||||
"integrity": "sha384-EI3V6JX9ws4fGxKBzMOgwhG5de8MvL6va3zqmB2gTXecd/m0mxNq8eUht/SGzH1B",
|
||||
"elements": [
|
||||
"stack-demo"
|
||||
],
|
||||
|
|
@ -1026,7 +1026,7 @@
|
|||
"scriptUrl": "./stack-demo/stack-demo.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./stack-demo/stack-demo/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=\"./stack-demo/stack-demo.js\" integrity=\"sha384-gnwM6s+puf1K60Nl7crQcC2QC+9BxwpkaTx4OepLZ8VUCraZc+aRlWpsb6nj6Gyf\" crossorigin=\"anonymous\"></script>\n<stack-demo profile-config='{\"profile\":\"stack-demo\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></stack-demo>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./stack-demo/stack-demo.js\" integrity=\"sha384-EI3V6JX9ws4fGxKBzMOgwhG5de8MvL6va3zqmB2gTXecd/m0mxNq8eUht/SGzH1B\" crossorigin=\"anonymous\"></script>\n<stack-demo profile-config='{\"profile\":\"stack-demo\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></stack-demo>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
@ -1050,7 +1050,7 @@
|
|||
"bundle": "template-bundle",
|
||||
"scriptUrl": "./template-bundle/template-bundle.js",
|
||||
"output": "doxa-maps/template-bundle/template-bundle.js",
|
||||
"integrity": "sha384-Arx3XL5Mhdv0VcU7RX9gwggLBjx3SH4WFltOaoEJ6mW/jw/E6wgGQHIOkFyRtBRd",
|
||||
"integrity": "sha384-LhhbW7T6VzMBsasbX4ezhA2vembuHwp1cNM1WNooIHMdGp00x8rOr7F9NdMndaG4",
|
||||
"elements": [
|
||||
"template-bundle"
|
||||
],
|
||||
|
|
@ -1066,7 +1066,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-Arx3XL5Mhdv0VcU7RX9gwggLBjx3SH4WFltOaoEJ6mW/jw/E6wgGQHIOkFyRtBRd\" 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-LhhbW7T6VzMBsasbX4ezhA2vembuHwp1cNM1WNooIHMdGp00x8rOr7F9NdMndaG4\" 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"
|
||||
},
|
||||
|
|
@ -1081,7 +1081,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-Arx3XL5Mhdv0VcU7RX9gwggLBjx3SH4WFltOaoEJ6mW/jw/E6wgGQHIOkFyRtBRd\" 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-LhhbW7T6VzMBsasbX4ezhA2vembuHwp1cNM1WNooIHMdGp00x8rOr7F9NdMndaG4\" 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"
|
||||
}
|
||||
|
|
@ -1091,7 +1091,7 @@
|
|||
"bundle": "upg-neighbor",
|
||||
"scriptUrl": "./upg-neighbor/upg-neighbor.js",
|
||||
"output": "doxa-maps/upg-neighbor/upg-neighbor.js",
|
||||
"integrity": "sha384-nhreYhnnIGRgIkQXr3h0xmwX71B2Yhd47erUuAOAqAYgTyNw/IvXaO/FjR09wvKz",
|
||||
"integrity": "sha384-EwHRhn6v9ffMpvgViAzs6KpLdGI5FS0jhrU0E4bFfERGt0NywaxilnsRPQdcRcdX",
|
||||
"elements": [
|
||||
"upg-neighbor"
|
||||
],
|
||||
|
|
@ -1107,7 +1107,7 @@
|
|||
"scriptUrl": "./upg-neighbor/upg-neighbor.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./upg-neighbor/upg-neighbor/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=\"./upg-neighbor/upg-neighbor.js\" integrity=\"sha384-nhreYhnnIGRgIkQXr3h0xmwX71B2Yhd47erUuAOAqAYgTyNw/IvXaO/FjR09wvKz\" crossorigin=\"anonymous\"></script>\n<upg-neighbor profile-config='{\"profile\":\"upg-neighbor\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></upg-neighbor>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./upg-neighbor/upg-neighbor.js\" integrity=\"sha384-EwHRhn6v9ffMpvgViAzs6KpLdGI5FS0jhrU0E4bFfERGt0NywaxilnsRPQdcRcdX\" crossorigin=\"anonymous\"></script>\n<upg-neighbor profile-config='{\"profile\":\"upg-neighbor\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></upg-neighbor>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
|
|||
190
public/doxa-maps/my-upg-100-list/my-upg-100-list.js
generated
190
public/doxa-maps/my-upg-100-list/my-upg-100-list.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -26,7 +26,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-4WnbHvh/qt/xIADBpWm8xKj0gcGj6hStHIGhrTLibVZtGGga8Bd/YXh31SD/tDCv" crossorigin="anonymous"></script>
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-eEbOnVD6pMXOvGXN1VAnX8J3UfTAVruDCirw1585wIGTS+LwN/gCvupPPecye4yf" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-4WnbHvh/qt/xIADBpWm8xKj0gcGj6hStHIGhrTLibVZtGGga8Bd/YXh31SD/tDCv" crossorigin="anonymous"></script>
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-eEbOnVD6pMXOvGXN1VAnX8J3UfTAVruDCirw1585wIGTS+LwN/gCvupPPecye4yf" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-4WnbHvh/qt/xIADBpWm8xKj0gcGj6hStHIGhrTLibVZtGGga8Bd/YXh31SD/tDCv" crossorigin="anonymous"></script>
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-eEbOnVD6pMXOvGXN1VAnX8J3UfTAVruDCirw1585wIGTS+LwN/gCvupPPecye4yf" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
44
public/doxa-maps/plugin-studio/plugin-studio.js
generated
44
public/doxa-maps/plugin-studio/plugin-studio.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <plugin-studio> custom element. -->
|
||||
<script src="../plugin-studio.js" integrity="sha384-2RlLFRU2XdjBN7w+FPguj8INgj57JFg4IFT2AmdefGnR9QQLehbiiAffV45LcsFH" crossorigin="anonymous"></script>
|
||||
<script src="../plugin-studio.js" integrity="sha384-D++rzhYeOQb6jBAa8CIB+8VvmvRij/YX1WF9TVHHLkGmUZUZSoOwUx6cgFuzkHOS" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <plugin-studio> custom element. -->
|
||||
<script src="../../plugin-studio.js" integrity="sha384-2RlLFRU2XdjBN7w+FPguj8INgj57JFg4IFT2AmdefGnR9QQLehbiiAffV45LcsFH" crossorigin="anonymous"></script>
|
||||
<script src="../../plugin-studio.js" integrity="sha384-D++rzhYeOQb6jBAa8CIB+8VvmvRij/YX1WF9TVHHLkGmUZUZSoOwUx6cgFuzkHOS" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-o2n8vzVstdRyYCQ4YnWVCpZYCOfaNGa+4BABLAeVw5vuXbnm1R71Zx3WT9FJc22n" crossorigin="anonymous"></script>
|
||||
<script src="../regions-dashboard.js" integrity="sha384-RROi/svcB/vhqo1W8SwZCYhJbi2HbGft9lGxxJQ4UAYjNzrbHKjSzJ6MmS7imr6o" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
204
public/doxa-maps/regions-dashboard/regions-dashboard.js
generated
204
public/doxa-maps/regions-dashboard/regions-dashboard.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -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-o2n8vzVstdRyYCQ4YnWVCpZYCOfaNGa+4BABLAeVw5vuXbnm1R71Zx3WT9FJc22n" crossorigin="anonymous"></script>
|
||||
<script src="../regions-dashboard.js" integrity="sha384-RROi/svcB/vhqo1W8SwZCYhJbi2HbGft9lGxxJQ4UAYjNzrbHKjSzJ6MmS7imr6o" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-o2n8vzVstdRyYCQ4YnWVCpZYCOfaNGa+4BABLAeVw5vuXbnm1R71Zx3WT9FJc22n" crossorigin="anonymous"></script>
|
||||
<script src="../regions-dashboard.js" integrity="sha384-RROi/svcB/vhqo1W8SwZCYhJbi2HbGft9lGxxJQ4UAYjNzrbHKjSzJ6MmS7imr6o" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -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-tAUIe2wERKg/ZRvINilfjrgfNYZeix7iSXYTJI1iSvf3eRtafkVt1a8cHIGyyRTF" crossorigin="anonymous"></script>
|
||||
<script src="../research-dashboard.js" integrity="sha384-hlPWMwkdwPg7Ze8QD4PwXTNv65fDKqwUOCrtX8NsH8h+rZHK1rZSnq43Vsz9O7Kt" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <research-map-plus-grid> custom element. -->
|
||||
<script src="../../research-map-plus-grid.js" integrity="sha384-sOkaMV0UFr2uNXfoJpRvaD+gHD6xFlkmpR7MzEwwFdarYdid8aN9Nj1Y8TqQJuFo" crossorigin="anonymous"></script>
|
||||
<script src="../../research-map-plus-grid.js" integrity="sha384-LQYR+uASPJFjo/VTpIpAVxUv+O5KrgBqfOFYOcOi0ZmIvtwcjWTZV4AjAr2ewc7Z" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <research-map-plus-grid> custom element. -->
|
||||
<script src="../research-map-plus-grid.js" integrity="sha384-sOkaMV0UFr2uNXfoJpRvaD+gHD6xFlkmpR7MzEwwFdarYdid8aN9Nj1Y8TqQJuFo" crossorigin="anonymous"></script>
|
||||
<script src="../research-map-plus-grid.js" integrity="sha384-LQYR+uASPJFjo/VTpIpAVxUv+O5KrgBqfOFYOcOi0ZmIvtwcjWTZV4AjAr2ewc7Z" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
16
public/doxa-maps/stack-demo/stack-demo.js
generated
16
public/doxa-maps/stack-demo/stack-demo.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <stack-demo> custom element. -->
|
||||
<script src="../stack-demo.js" integrity="sha384-gnwM6s+puf1K60Nl7crQcC2QC+9BxwpkaTx4OepLZ8VUCraZc+aRlWpsb6nj6Gyf" crossorigin="anonymous"></script>
|
||||
<script src="../stack-demo.js" integrity="sha384-EI3V6JX9ws4fGxKBzMOgwhG5de8MvL6va3zqmB2gTXecd/m0mxNq8eUht/SGzH1B" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <stack-demo> custom element. -->
|
||||
<script src="../../stack-demo.js" integrity="sha384-gnwM6s+puf1K60Nl7crQcC2QC+9BxwpkaTx4OepLZ8VUCraZc+aRlWpsb6nj6Gyf" crossorigin="anonymous"></script>
|
||||
<script src="../../stack-demo.js" integrity="sha384-EI3V6JX9ws4fGxKBzMOgwhG5de8MvL6va3zqmB2gTXecd/m0mxNq8eUht/SGzH1B" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
30
public/doxa-maps/template-bundle/template-bundle.js
generated
30
public/doxa-maps/template-bundle/template-bundle.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -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-Arx3XL5Mhdv0VcU7RX9gwggLBjx3SH4WFltOaoEJ6mW/jw/E6wgGQHIOkFyRtBRd" crossorigin="anonymous"></script>
|
||||
<script src="../template-bundle.js" integrity="sha384-LhhbW7T6VzMBsasbX4ezhA2vembuHwp1cNM1WNooIHMdGp00x8rOr7F9NdMndaG4" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -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-Arx3XL5Mhdv0VcU7RX9gwggLBjx3SH4WFltOaoEJ6mW/jw/E6wgGQHIOkFyRtBRd" crossorigin="anonymous"></script>
|
||||
<script src="../template-bundle.js" integrity="sha384-LhhbW7T6VzMBsasbX4ezhA2vembuHwp1cNM1WNooIHMdGp00x8rOr7F9NdMndaG4" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
164
public/doxa-maps/upg-neighbor/upg-neighbor.js
generated
164
public/doxa-maps/upg-neighbor/upg-neighbor.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <upg-neighbor> custom element. -->
|
||||
<script src="../../upg-neighbor.js" integrity="sha384-nhreYhnnIGRgIkQXr3h0xmwX71B2Yhd47erUuAOAqAYgTyNw/IvXaO/FjR09wvKz" crossorigin="anonymous"></script>
|
||||
<script src="../../upg-neighbor.js" integrity="sha384-EwHRhn6v9ffMpvgViAzs6KpLdGI5FS0jhrU0E4bFfERGt0NywaxilnsRPQdcRcdX" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <upg-neighbor> custom element. -->
|
||||
<script src="../../upg-neighbor.js" integrity="sha384-nhreYhnnIGRgIkQXr3h0xmwX71B2Yhd47erUuAOAqAYgTyNw/IvXaO/FjR09wvKz" crossorigin="anonymous"></script>
|
||||
<script src="../../upg-neighbor.js" integrity="sha384-EwHRhn6v9ffMpvgViAzs6KpLdGI5FS0jhrU0E4bFfERGt0NywaxilnsRPQdcRcdX" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <upg-neighbor> custom element. -->
|
||||
<script src="../upg-neighbor.js" integrity="sha384-nhreYhnnIGRgIkQXr3h0xmwX71B2Yhd47erUuAOAqAYgTyNw/IvXaO/FjR09wvKz" crossorigin="anonymous"></script>
|
||||
<script src="../upg-neighbor.js" integrity="sha384-EwHRhn6v9ffMpvgViAzs6KpLdGI5FS0jhrU0E4bFfERGt0NywaxilnsRPQdcRcdX" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <upg-neighbor> custom element. -->
|
||||
<script src="../../upg-neighbor.js" integrity="sha384-nhreYhnnIGRgIkQXr3h0xmwX71B2Yhd47erUuAOAqAYgTyNw/IvXaO/FjR09wvKz" crossorigin="anonymous"></script>
|
||||
<script src="../../upg-neighbor.js" integrity="sha384-EwHRhn6v9ffMpvgViAzs6KpLdGI5FS0jhrU0E4bFfERGt0NywaxilnsRPQdcRcdX" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <upg-neighbor> custom element. -->
|
||||
<script src="../../upg-neighbor.js" integrity="sha384-nhreYhnnIGRgIkQXr3h0xmwX71B2Yhd47erUuAOAqAYgTyNw/IvXaO/FjR09wvKz" crossorigin="anonymous"></script>
|
||||
<script src="../../upg-neighbor.js" integrity="sha384-EwHRhn6v9ffMpvgViAzs6KpLdGI5FS0jhrU0E4bFfERGt0NywaxilnsRPQdcRcdX" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <upg-neighbor> custom element. -->
|
||||
<script src="../../upg-neighbor.js" integrity="sha384-nhreYhnnIGRgIkQXr3h0xmwX71B2Yhd47erUuAOAqAYgTyNw/IvXaO/FjR09wvKz" crossorigin="anonymous"></script>
|
||||
<script src="../../upg-neighbor.js" integrity="sha384-EwHRhn6v9ffMpvgViAzs6KpLdGI5FS0jhrU0E4bFfERGt0NywaxilnsRPQdcRcdX" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
Loading…
Reference in a new issue