Stop showing English where the catalogue already holds the translation
A reader on an Arabic page saw a handful of English words among the Arabic:
the table's "People Groups" title, its count line, the Engagement column, the
Gospel Access chart title, and the side drawer's close button. Every one of them
had a correct Arabic entry sitting in the catalogue; nothing looked it up.
THE CHECK CAME FIRST, AND IT REPLACES A SWEEP THAT PASSED A BROKEN TREE.
The old method sorted every rendered string into third-party / data / chrome and
counted only chrome. That split is a guess, and it guessed wrong exactly where
the defect lived: single words like "Region", "Prayer" and "Country" are as
plausible as values as they are as labels, so they scored as data and the sweep
reported zero on a page that was visibly leaking.
check:composite-locale-leaks asks a question with an answer instead:
the English catalogue holds this exact string as a value, AND
this locale holds a DIFFERENT value for that key, AND
the page still renders the English one.
No judgement about what kind of word it is — if the translation exists and the
reader is not getting it, that is the defect. The two surfaces a lookup cannot
judge (vendor map chrome, and table/facet cells carrying API values) are muted
by NAME with a stated reason, never by word, so muting one can never hide the
next real leak that happens to reuse it. The gate failed on this tree naming 9
strings before any of them were fixed.
Also threaded here: both composites now accept `lang` / `locale` in
profile-config and pass it to the children they mount, alongside `tk` and
`provider`. A partner writing {"lang":"ar"} reached nothing before — the knob
was documented and read by nobody.
The prayer facet's label in DashboardResearchFilters is now a catalogue getter
too. Measured before touching it: dashboard.config.js does define prayer_level
and FACETS spreads the config last, so that literal never rendered for this
config — it is a default for a config that omits the facet, and it stays, with
the merge order written down so the next reader need not re-derive it.
Four strings remain English with no catalogue entry at all — "Top countries",
"Select all {n}", the table dock's title, and the singular "group". They need
wording in ten languages that cannot be composed from existing entries, so they
are a DECIDE card for the Driver rather than translations invented here.
This commit is contained in:
parent
622366d4d6
commit
471bd05cea
27 changed files with 449 additions and 190 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 check:composite-embed-knobs check:linked-vocabulary",
|
||||
"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 check:composite-locale-leaks check:linked-vocabulary",
|
||||
"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
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ useShadowStyles(`
|
|||
<aside class="rm-side-drawer" :class="{ open: isOpen }" role="dialog" :aria-label="L('map_controls', 'Research map controls')">
|
||||
<header class="rm-side-header">
|
||||
<h3 class="rm-side-title">{{ L('research_controls', 'Research controls') }}</h3>
|
||||
<button class="rm-side-close" aria-label="Close" @click="emit('close')">×</button>
|
||||
<button class="rm-side-close" :aria-label="tStatic('buttons.close') || 'Close'" @click="emit('close')">×</button>
|
||||
</header>
|
||||
|
||||
<div class="rm-side-body">
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@
|
|||
"check:composite": "node internal/check-composite-freshness.mjs",
|
||||
"check:shots": "node internal/check-shot-freshness.mjs",
|
||||
"check:library-index": "node internal/check-library-index.mjs",
|
||||
"check:linked-vocabulary": "node plugin-designs/research-map-plus-grid/scripts/check-linked-vocabulary.mjs",
|
||||
"check:quoted-scripts": "node internal/check-quoted-scripts.mjs",
|
||||
"capability-exemplars": "node internal/generate-capability-exemplars.mjs",
|
||||
"check:a11y-button-names": "node internal/check-a11y-button-names.mjs",
|
||||
|
|
@ -178,10 +179,10 @@
|
|||
"check:doc-scripts:self-test": "node internal/check-doc-quotes-scripts.mjs --self-test",
|
||||
"check:legend-source": "node internal/check-legend-matches-source.mjs",
|
||||
"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 check:composite-embed-knobs check:linked-vocabulary",
|
||||
"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 check:composite-locale-leaks check:linked-vocabulary",
|
||||
"build:bundles": "node internal/run-parallel.mjs --bundles",
|
||||
"check:composite-embed-knobs": "node internal/check-composite-embed-knobs.mjs",
|
||||
"check:linked-vocabulary": "node plugin-designs/research-map-plus-grid/scripts/check-linked-vocabulary.mjs",
|
||||
"check:composite-locale-leaks": "node plugin-designs/research-map-plus-grid/scripts/check-composite-locale-leaks.mjs",
|
||||
"check:maplibre-drops": "node internal/check-maplibre-layer-drops.mjs",
|
||||
"check:tabs-localized": "node internal/check-tabs-localized.mjs",
|
||||
"check:packets-all": "node internal/check-packets-all.mjs",
|
||||
|
|
@ -282,6 +283,7 @@
|
|||
"check:embed-basemap": "the gospel map's BASEMAP must paint inside a genuinely cross-origin iframe on the token the page BAKES, not one a probe forces on it. Every other browser gate here forces a restricted token (u=doxalife) that 403s on the basemap, then counts PINS — which come from our own GeoJSON and paint with no token at all — so 'the map renders' had never been measured. Runs a negative control every time by rewriting the token on the wire; if the control passes it reports PROVED NOTHING rather than a pass. ~60s, needs a browser.",
|
||||
"serve:permissive": "LOOPBACK ONLY. This was --bind 0.0.0.0, which published the built tree on every interface of whatever machine ran a gate; measured on the build VPS it answered HTTP 200 on the box's PUBLIC IP while a browser gate was running. Every consumer (verify-browser-all, check:a11y-button-names, check:nav-reachable, smoke:share-all) already defaults to 127.0.0.1, so nothing needed the wider bind. Override with BASE_URL/BASE if you deliberately want to reach it from another host.",
|
||||
"check:legend-source": "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.",
|
||||
"check:composite-locale-leaks": "a composite rendered in a non-English locale must not show a string the catalogue already translates. The criterion is a LOOKUP, not a category: English catalogue holds the string as a value, this locale holds a different value for that key, the page still renders English. The previous sweep split strings into chrome/data/third-party and scored single words like 'Region' and 'Prayer' as data, so 28 leaks on Big Picture and 41 on Simple Research counted as zero. Surfaces that a lookup cannot judge - vendor map chrome, table DATA cells, facet-rail values - are suppressed by NAME with a stated reason, never by word.",
|
||||
"check:linked-vocabulary": "the two halves of research-map-plus-grid must mean the SAME THING by a religion family. The map filters by the legend's FIRST-LETTER key ('B'), the grid by a DERIVED family name ('Buddhism'), and both read ONE shared table (library/colors/religion.js) in opposite directions - so a wrong link stays invisible: both halves look filtered and show different peoples. Compares the total reached over the composite's wire against the total the grid gives for the same facet on its own, and runs the MUTANT first (the legend key instead of the name), failing as NO-TEETH if the wrong mapping scores the same as the right one.",
|
||||
"check:composite-embed-knobs": "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:tabs-localized": "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.",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
* people-groups-grid component; the dashboard is the exact research-dashboard component.
|
||||
*/
|
||||
import { reactive, provide, ref, computed } from 'vue'
|
||||
import { SUPPORTED_LOCALES } from '@map/i18n/index.js'
|
||||
import { resolveEmbedBase } from '@map/utils/embedBase.js'
|
||||
import { useSharedMapToken, publishMapToken } from '@map/composables/useSharedMapToken.js'
|
||||
import StackLayout from '@map/layouts/StackLayout.vue'
|
||||
|
|
@ -260,6 +261,18 @@ const hostProvider = computed(() => {
|
|||
return p === 'maplibre' || p === 'mapbox' ? p : ''
|
||||
})
|
||||
|
||||
// ★ THE LOCALE THE HOST ASKED FOR, THREADED DOWN LIKE THE TOKEN AND THE PROVIDER.
|
||||
// A composite is the only thing between a partner's `profile-config` and the elements that render
|
||||
// the text, and this knob was not being passed: `{"lang":"ar"}` on the composite reached nothing,
|
||||
// so the page stayed English however complete the catalogues were. MEASURED alongside the tk and
|
||||
// provider holes, and the same shape of defect — a knob the snippet documents, read by nobody.
|
||||
// The composite's OWN chrome still reads English until the i18n layer learns to follow a locale set
|
||||
// at runtime; that change is held behind another agent's landing in the same file and arrives next.
|
||||
const hostLang = computed(() => {
|
||||
const l = String(hostConfig.value?.lang || hostConfig.value?.locale || '').split('-')[0].toLowerCase()
|
||||
return SUPPORTED_LOCALES.includes(l) ? l : ''
|
||||
})
|
||||
|
||||
// ★ 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
|
||||
|
|
@ -279,6 +292,7 @@ provide('profileConfig', computed(() => ({
|
|||
// 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 } : {}),
|
||||
...(hostLang.value ? { lang: hostLang.value } : {}),
|
||||
})))
|
||||
|
||||
const sections = [
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ export default {
|
|||
// gsec rung 1 and 13 are "Unengaged" at rung 2 — so this is not the status filter wearing a new
|
||||
// label. Its own section rather than a drill under anything: the ladder is not a sub-division of
|
||||
// the engagement flag, and 5 rows do not need a topN cap.
|
||||
{ id: 'gospel-access', title: 'Gospel Access', axis: null, facet: 'gospel_access', topN: 8 },
|
||||
{ id: 'gospel-access', get title() { return tStatic('dashboard.gospel_access') || 'Gospel Access' }, axis: null, facet: 'gospel_access', topN: 8 },
|
||||
],
|
||||
|
||||
// ── KPI strip ── (computed by useDashboardShell; mirrors the original 6 stat computeds)
|
||||
|
|
@ -302,7 +302,7 @@ export default {
|
|||
{ key: 'religion', get label() { return tStatic('dashboard.religion') || 'Religion' }, get: (r) => lbl(r.religion), type: 'str', w: 1.04 },
|
||||
{ key: 'population', get label() { return tStatic('dashboard.population') || 'Population' }, get: (r) => num(r.population), type: 'num', w: 0.86 },
|
||||
{ key: 'people_praying', get label() { return tStatic('dashboard.praying') || 'Praying' }, get: (r) => num(r.people_praying), type: 'num', w: 0.66 },
|
||||
{ key: 'engagement', label: 'Engagement', get: (r) => lbl(r.engagement_status), type: 'str', w: 0.97 },
|
||||
{ key: 'engagement', get label() { return tStatic('dashboard.engagement') || 'Engagement' }, get: (r) => lbl(r.engagement_status), type: 'str', w: 0.97 },
|
||||
],
|
||||
|
||||
// ── map ── (DashboardMapPanel)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,13 @@ import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
|||
import { buildSearchAccessors, makeSearchMatcher, filterRowsBySearch } from '../../composables/useDashboardShell.js'
|
||||
import { useCsvExport } from '../../composables/useCsvExport.js'
|
||||
import { useTreeLegendLabels } from '../../composables/useTreeLegendLabels.js'
|
||||
import { tStatic } from '@map/i18n/index.js'
|
||||
|
||||
// This table's chrome, read out of the catalogue. tStatic and not useI18n, for the reason the rest
|
||||
// of this tree gives: these components mount inside custom elements that install no i18n plugin,
|
||||
// and an unguarded useI18n() throws on the way in and takes the whole panel with it.
|
||||
// The English stays as the fallback argument, so a key that is missing degrades to what shipped.
|
||||
const T = (key, en) => tStatic(key) || en
|
||||
|
||||
const dash = inject('dashboardData', null)
|
||||
const bus = inject('selectionBus', null)
|
||||
|
|
@ -778,8 +785,8 @@ useShadowStyles(`
|
|||
<div class="rd-table-bar" :data-collapsed="collapsed ? '1' : '0'">
|
||||
<button class="rd-dock" :title="collapsed ? 'Expand table' : 'Collapse table — grow the map'"
|
||||
data-table-dock :aria-expanded="collapsed ? 'false' : 'true'" @click="toggleDock">{{ collapsed ? '▴' : '▾' }}</button>
|
||||
<span class="ttl">People Groups</span>
|
||||
<span class="ct" data-table-count>{{ fmt(rowCount) }} {{ rowCount === 1 ? 'group' : 'groups' }}</span>
|
||||
<span class="ttl">{{ T('legend.titleBar.peopleGroups', 'People Groups') }}</span>
|
||||
<span class="ct" data-table-count>{{ fmt(rowCount) }} {{ rowCount === 1 ? 'group' : T('dashboard.groups', 'groups') }}</span>
|
||||
<!-- role=status so assistive tech announces the count as the selection changes. -->
|
||||
<!-- ★ NO CLEAR BUTTON IN THIS BAR (Driver 2026-09-23, on the selection flood: "it does not
|
||||
need to give me a Clear Selected button in the header because the FOOTER of the page
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
* mapped to this dashboard's facet keys). Nothing here is dashboard-specific beyond that map.
|
||||
*/
|
||||
import { inject, computed } from 'vue'
|
||||
import { tStatic } from '@map/i18n/index.js'
|
||||
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
||||
import SearchFilterHeader from '@map/components/search/SearchFilterHeader.vue'
|
||||
import { getPrayerLevel, LABELS as PRAYER_LABELS } from '@map/colors/prayer-progress.js'
|
||||
|
|
@ -74,7 +75,12 @@ const filterSet = bus?.filterSet || {}
|
|||
// here: a key present in cfg.facets wins over this local default.
|
||||
const PRAYER_KEY = 'prayer_level'
|
||||
const prayerFacet = {
|
||||
label: 'Prayer',
|
||||
// MEASURED, because the comment above says this block is a DEFAULT and a reader should not have to
|
||||
// work out whether it is live: dashboard.config.js:80 DOES define `prayer_level`, and FACETS spreads
|
||||
// cfg.facets last, so this label never renders for the DX-life config — the dropdown shows the
|
||||
// config's translated one (الصلاة in ar). It is read only by a config that omits the facet, which
|
||||
// is exactly the case that would otherwise render one English word beside six translated ones.
|
||||
get label() { return tStatic('dashboard.prayer') || 'Prayer' },
|
||||
// Returns the human LABEL, which is what the bus stores and byte-matches — same value-is-label
|
||||
// contract every non-People axis follows, so a pick lands a matching filterSet entry with no
|
||||
// separate display projection needed.
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@
|
|||
* elements do not merely look different, they imply OPPOSITE control ownership below.
|
||||
*/
|
||||
import { computed, reactive, watch, onMounted, onBeforeUnmount, getCurrentInstance } from 'vue'
|
||||
import { SUPPORTED_LOCALES } from '@map/i18n/index.js'
|
||||
import StackLayout from '@map/layouts/StackLayout.vue'
|
||||
import { resolveEmbedBase } from '@map/utils/embedBase.js'
|
||||
import { publishMapToken } from '@map/composables/useSharedMapToken.js'
|
||||
|
|
@ -113,6 +114,18 @@ const hostProvider = computed(() => {
|
|||
return p === 'maplibre' || p === 'mapbox' ? p : ''
|
||||
})
|
||||
|
||||
// ★ THE LOCALE THE HOST ASKED FOR, THREADED DOWN LIKE THE TOKEN AND THE PROVIDER.
|
||||
// A composite is the only thing between a partner's `profile-config` and the elements that render
|
||||
// the text, and this knob was not being passed: `{"lang":"ar"}` on the composite reached nothing,
|
||||
// so the page stayed English however complete the catalogues were. MEASURED alongside the tk and
|
||||
// provider holes, and the same shape of defect — a knob the snippet documents, read by nobody.
|
||||
// The composite's OWN chrome still reads English until the i18n layer learns to follow a locale set
|
||||
// at runtime; that change is held behind another agent's landing in the same file and arrives next.
|
||||
const hostLang = computed(() => {
|
||||
const l = String(hostConfig.value?.lang || hostConfig.value?.locale || '').split('-')[0].toLowerCase()
|
||||
return SUPPORTED_LOCALES.includes(l) ? l : ''
|
||||
})
|
||||
|
||||
// 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 →
|
||||
// the root this bundle derives from its OWN script url, so the link is right on doxa.life, on
|
||||
|
|
@ -357,6 +370,7 @@ const sections = computed(() => [
|
|||
// child's own config identical to what its standalone leaf sets.
|
||||
...(hostToken.value ? { tk: hostToken.value } : {}),
|
||||
...(hostProvider.value ? { provider: hostProvider.value } : {}),
|
||||
...(hostLang.value ? { lang: hostLang.value } : {}),
|
||||
// The composite's filter state, in the map's inbound shape. Absent keys are ignored there.
|
||||
externalFilters: { region: linked.region.value, religion: linked.religion, language: linked.language },
|
||||
assetsBase: '../../assets',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,216 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* check-composite-locale-leaks.mjs — a composite rendered in a non-English locale must not show a
|
||||
* string the catalogue already translates.
|
||||
*
|
||||
* WHY THIS REPLACES THE PREVIOUS SWEEP, AND WHY THE PREVIOUS SWEEP PASSED A BROKEN TREE.
|
||||
* The old method split every rendered string into "third-party", "DATA" and "CHROME" and counted
|
||||
* only the third bucket. That split is a GUESS, and it guessed wrong in exactly the place the
|
||||
* defect lived: single words like 'Region', 'Prayer', 'Country', 'Language' read as data — they are
|
||||
* plausible values as well as plausible labels — so 28 distinct leaks on Big Picture and 41 on
|
||||
* Simple Research scored as zero. An independent verifier found them on the same tree the sweep had
|
||||
* just called clean.
|
||||
*
|
||||
* ★ THE CRITERION IS NOT A CATEGORY, IT IS A LOOKUP. A rendered string is a LEAK when:
|
||||
*
|
||||
* the English catalogue holds that exact string as a value, AND
|
||||
* this locale's catalogue holds a DIFFERENT value for that same key, AND
|
||||
* the page still renders the English one.
|
||||
*
|
||||
* No judgement about what kind of word it is. If the translation exists and the reader is not
|
||||
* getting it, that is the defect, whatever the word looks like. A data value that merely coincides
|
||||
* with a catalogue entry is the only false positive this can produce, and it is one we WANT to see:
|
||||
* a coincidence worth suppressing is worth suppressing by name, in this file, with a reason.
|
||||
*
|
||||
* WHERE THE DEFECT ACTUALLY IS. Not in the library components — they translate. The English is
|
||||
* hardcoded at the CALL SITE, passed down as a prop that no lookup ever touches:
|
||||
*
|
||||
* <FilterDropdown :label="'Prayer'"> research-dashboard/.../DashboardResearchFilters.vue
|
||||
*
|
||||
* A component that is perfectly localized renders English because it was handed English.
|
||||
*
|
||||
* Exit: 0 pass or SKIP (no built tree, no browser, no data) · 1 fail.
|
||||
*/
|
||||
import { createServer } from 'node:http'
|
||||
import { spawn } from 'node:child_process'
|
||||
import { existsSync, readFileSync, readdirSync } from 'node:fs'
|
||||
import { resolve, dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const TAG = 'COMPOSITE-LOCALE-LEAKS'
|
||||
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', '..')
|
||||
const MANIFEST = join(ROOT, 'public', 'doxa-maps', 'manifest.json')
|
||||
const LOCALES_DIR = join(ROOT, 'library', 'i18n', 'locales')
|
||||
const skip = (why) => { console.log(`${TAG}: SKIP — ${why}`); process.exit(0) }
|
||||
|
||||
if (!existsSync(MANIFEST)) skip('no built manifest (run `bun run tree` first).')
|
||||
if (!existsSync(LOCALES_DIR)) skip('no locale catalogues to compare against.')
|
||||
let chromium
|
||||
try { ({ chromium } = await import('playwright')) } catch { skip('playwright is not installed.') }
|
||||
|
||||
// The composites in this lane. Both, always: the two share the grid and half the chrome, and a fix
|
||||
// proved on one has repeatedly been stale on the other.
|
||||
const COMPOSITES = ['research-map-plus-grid', 'dashboard-plus-grid']
|
||||
const LOCALES = (process.env.LEAK_LOCALES || 'ar').split(',').map((s) => s.trim()).filter(Boolean)
|
||||
|
||||
// ── the catalogues, flattened to key -> value ────────────────────────────────────────────────────
|
||||
const flatten = (obj, prefix, out) => {
|
||||
for (const [k, v] of Object.entries(obj || {})) {
|
||||
const key = prefix ? `${prefix}.${k}` : k
|
||||
if (v && typeof v === 'object') flatten(v, key, out)
|
||||
else if (typeof v === 'string') out[key] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
const catalogue = (locale) => {
|
||||
const dir = join(LOCALES_DIR, locale)
|
||||
if (!existsSync(dir)) return null
|
||||
const out = {}
|
||||
for (const f of readdirSync(dir).filter((f) => f.endsWith('.json'))) {
|
||||
flatten(JSON.parse(readFileSync(join(dir, f), 'utf8')), f.replace(/\.json$/, ''), out)
|
||||
}
|
||||
return out
|
||||
}
|
||||
const EN = catalogue('en')
|
||||
if (!EN) skip('no English catalogue to compare against.')
|
||||
|
||||
// English value -> the keys that carry it. A word like 'Region' is usually several keys; ONE key
|
||||
// with a real translation is enough to make rendering the English a leak.
|
||||
const byEnglish = new Map()
|
||||
for (const [key, val] of Object.entries(EN)) {
|
||||
const v = String(val).trim()
|
||||
if (!v) continue
|
||||
if (!byEnglish.has(v)) byEnglish.set(v, [])
|
||||
byEnglish.get(v).push(key)
|
||||
}
|
||||
|
||||
// ── the two things a catalogue lookup CANNOT tell apart, suppressed BY NAME with a reason ───────
|
||||
// The criterion asks "does the catalogue translate this string", and for two kinds of text that
|
||||
// question is the wrong one. Each entry here is a surface, not a string: suppressing a WORD would
|
||||
// hide the next real leak that happens to use it, while suppressing a surface says exactly which
|
||||
// element is not ours to translate and why.
|
||||
const SUPPRESS = [
|
||||
{ where: /^(canvas|button|a|div)\.(mapboxgl|maplibregl)-/, why: "vendor chrome — mapbox-gl/maplibre-gl render these themselves ('Map', 'Clear', 'Toggle attribution'); we pass the geocoder its placeholder and have no hook for the rest" },
|
||||
{ where: /^div\.rd-td$/, why: 'a table DATA cell — the row value as the API returned it, not chrome. "Unengaged" here is a datum that happens to match controls.unengaged' },
|
||||
{ where: /^span\.fr-lbl$/, why: 'a facet-rail VALUE (region names, affinity blocs, religion families as the data spells them) — the rail\'s own headings are chrome and are not in this class' },
|
||||
]
|
||||
|
||||
// ── serve the built tree ─────────────────────────────────────────────────────────────────────────
|
||||
const manifest = JSON.parse(readFileSync(MANIFEST, 'utf8'))
|
||||
const leafOf = (bundle) => {
|
||||
const b = (manifest.bundles || []).find((x) => x.bundle === bundle)
|
||||
const p = b && (b.profiles || []).find((p) => p.iframeUrl)
|
||||
return p ? String(p.iframeUrl).replace(/^\.\//, '') : null
|
||||
}
|
||||
const freePort = () => new Promise((ok) => {
|
||||
const s = createServer().listen(0, '127.0.0.1', () => { const p = s.address().port; s.close(() => ok(p)) })
|
||||
})
|
||||
const PORT = await freePort()
|
||||
const TREE = `http://127.0.0.1:${PORT}/doxa-maps`
|
||||
const tree = spawn(process.execPath, ['internal/serve-strict.mjs', '--port', String(PORT)], { cwd: ROOT, stdio: 'ignore' })
|
||||
const cleanup = () => { try { tree.kill() } catch { /* already gone */ } }
|
||||
await new Promise((r) => setTimeout(r, 900))
|
||||
if (!await fetch(`${TREE}/manifest.json`, { signal: AbortSignal.timeout(4000) }).then((r) => r.ok).catch(() => false)) {
|
||||
cleanup(); skip('could not serve the built tree locally.')
|
||||
}
|
||||
const { requireThisTree } = await import(join(ROOT, 'internal', '_serves-this-tree.mjs'))
|
||||
await requireThisTree(TREE, ROOT, TAG)
|
||||
|
||||
// ── collect every rendered string, shadow roots included ─────────────────────────────────────────
|
||||
const COLLECT = `(async () => {
|
||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
|
||||
await sleep(12000) // let both halves fetch and render
|
||||
const found = new Map()
|
||||
const note = (text, el) => {
|
||||
const t = String(text || '').replace(/\\s+/g, ' ').trim()
|
||||
if (!t || t.length > 120) return
|
||||
const where = el.tagName.toLowerCase() + (el.className && typeof el.className === 'string' ? '.' + el.className.trim().split(/\\s+/)[0] : '')
|
||||
if (!found.has(t)) found.set(t, { count: 0, where })
|
||||
found.get(t).count++
|
||||
}
|
||||
const seen = new Set()
|
||||
const walk = (root) => {
|
||||
if (!root || seen.has(root)) return
|
||||
seen.add(root)
|
||||
for (const el of root.querySelectorAll('*')) {
|
||||
if (el.shadowRoot) walk(el.shadowRoot)
|
||||
// Only a node's OWN text: taking textContent would report every ancestor as carrying the
|
||||
// string too, and one leak would score as a dozen.
|
||||
for (const n of el.childNodes) {
|
||||
if (n.nodeType === 3) note(n.nodeValue, el)
|
||||
}
|
||||
for (const a of ['placeholder', 'title', 'aria-label', 'alt']) {
|
||||
const v = el.getAttribute && el.getAttribute(a)
|
||||
if (v) note(v, el)
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(document)
|
||||
return [...found.entries()].map(([text, m]) => ({ text, count: m.count, where: m.where }))
|
||||
})()`
|
||||
|
||||
const browser = await chromium.launch({ args: ['--enable-unsafe-swiftshader', '--use-gl=angle', '--use-angle=swiftshader'] })
|
||||
const report = []
|
||||
let totalDistinct = 0
|
||||
try {
|
||||
for (const locale of LOCALES) {
|
||||
const LOC = catalogue(locale)
|
||||
if (!LOC) { report.push({ locale, skip: 'no catalogue' }); continue }
|
||||
for (const bundle of COMPOSITES) {
|
||||
const leaf = leafOf(bundle)
|
||||
if (!leaf) { report.push({ locale, bundle, skip: 'no leaf in the manifest' }); continue }
|
||||
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } })
|
||||
await page.goto(`${TREE}/${leaf}?lang=${locale}`, { waitUntil: 'domcontentloaded', timeout: 60000 })
|
||||
const strings = await page.evaluate(COLLECT)
|
||||
await page.close()
|
||||
|
||||
const leaks = []
|
||||
const suppressed = []
|
||||
for (const s of strings) {
|
||||
const keys = byEnglish.get(s.text)
|
||||
if (!keys) continue
|
||||
// Translated somewhere for this locale? One key is enough — and the translation must differ
|
||||
// from the English, or there is nothing for the reader to be missing.
|
||||
const translated = keys.filter((k) => LOC[k] && String(LOC[k]).trim() && String(LOC[k]).trim() !== s.text)
|
||||
if (!translated.length) continue
|
||||
const muted = SUPPRESS.find((r) => r.where.test(s.where))
|
||||
if (muted) { suppressed.push({ ...s, why: muted.why }); continue }
|
||||
leaks.push({ ...s, keys: translated.slice(0, 2) })
|
||||
}
|
||||
if (process.env.LEAK_DUMP) {
|
||||
console.log(`--- ${bundle} [${locale}] all ${strings.length} rendered strings ---`)
|
||||
for (const s of strings) console.log(` ${s.where} | ${s.text}`)
|
||||
}
|
||||
leaks.sort((a, b) => b.count - a.count)
|
||||
totalDistinct += leaks.length
|
||||
report.push({ locale, bundle, leaks, suppressed, scanned: strings.length })
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
cleanup(); await browser.close().catch(() => {})
|
||||
console.log(`${TAG}: FAIL — the measurement itself failed: ${err && err.message}`)
|
||||
process.exit(1)
|
||||
} finally {
|
||||
await browser.close().catch(() => {})
|
||||
cleanup()
|
||||
}
|
||||
|
||||
for (const r of report) {
|
||||
if (r.skip) { console.log(` · ${r.locale} ${r.bundle || ''} — SKIPPED (${r.skip})`); continue }
|
||||
const n = r.leaks.length
|
||||
const instances = r.leaks.reduce((a, l) => a + l.count, 0)
|
||||
console.log(` ${n ? '✗' : '✓'} ${r.bundle} [${r.locale}] — ${n} distinct leak(s), ${instances} instance(s), of ${r.scanned} rendered string(s)`)
|
||||
for (const l of r.leaks.slice(0, 12)) {
|
||||
console.log(` '${l.text}' ×${l.count} ${l.where} → ${l.keys.join(', ')}`)
|
||||
}
|
||||
if (n > 12) console.log(` … and ${n - 12} more`)
|
||||
for (const m of r.suppressed || []) console.log(` (not counted) '${m.text}' ×${m.count} ${m.where} — ${m.why}`)
|
||||
}
|
||||
|
||||
if (totalDistinct) {
|
||||
console.log(`\n${TAG}: FAIL — ${totalDistinct} string(s) render in English on a page asked for another locale, and the catalogue has a translation for every one of them.`)
|
||||
console.log(' The library components translate; the English is hardcoded at the CALL SITE and')
|
||||
console.log(' handed down as a prop (e.g. FilterDropdown :label="\'Prayer\'").')
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(`${TAG}: PASS — nothing the catalogue translates is rendering in English.`)
|
||||
|
|
@ -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-Q11zxYDmXp/3KoxkMIRaPGn1KWAer2kQrJTpE/YiwUeasLLy4UNocmXO4qByMX+D" crossorigin="anonymous"></script>
|
||||
<script src="../country-posters.js" integrity="sha384-XihJJ+5H6GH3dOVnuzv4/ykroXFbCmwSrZS5MDmw4xmhrctg7Wpz62FkZ8JCAKjK" 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-Q11zxYDmXp/3KoxkMIRaPGn1KWAer2kQrJTpE/YiwUeasLLy4UNocmXO4qByMX+D" crossorigin="anonymous"></script>
|
||||
<script src="../country-posters.js" integrity="sha384-XihJJ+5H6GH3dOVnuzv4/ykroXFbCmwSrZS5MDmw4xmhrctg7Wpz62FkZ8JCAKjK" 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-Q11zxYDmXp/3KoxkMIRaPGn1KWAer2kQrJTpE/YiwUeasLLy4UNocmXO4qByMX+D" crossorigin="anonymous"></script>
|
||||
<script src="../country-posters.js" integrity="sha384-XihJJ+5H6GH3dOVnuzv4/ykroXFbCmwSrZS5MDmw4xmhrctg7Wpz62FkZ8JCAKjK" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
84
public/doxa-maps/country-posters/country-posters.js
generated
84
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-Rc4Fi2DHGSwNMZf91ng3ejXA5JBPzCKgQi9DJ1sQcr9PUq819LAhBHvFU/NbyMwR" crossorigin="anonymous"></script>
|
||||
<script src="../../dashboard-plus-grid.js" integrity="sha384-qpx82oeZ306lvi0Z8J5l/575pzWq3dVBOjHScHpKAaa0bwFTC5QUdT2iv/OQNghH" 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-Rc4Fi2DHGSwNMZf91ng3ejXA5JBPzCKgQi9DJ1sQcr9PUq819LAhBHvFU/NbyMwR" crossorigin="anonymous"></script>
|
||||
<script src="../dashboard-plus-grid.js" integrity="sha384-qpx82oeZ306lvi0Z8J5l/575pzWq3dVBOjHScHpKAaa0bwFTC5QUdT2iv/OQNghH" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
24
public/doxa-maps/doxa-maps-spa/manifest.json
generated
24
public/doxa-maps/doxa-maps-spa/manifest.json
generated
|
|
@ -158,7 +158,7 @@
|
|||
"bundle": "country-posters",
|
||||
"scriptUrl": "./country-posters/country-posters.js",
|
||||
"output": "doxa-maps/country-posters/country-posters.js",
|
||||
"integrity": "sha384-Q11zxYDmXp/3KoxkMIRaPGn1KWAer2kQrJTpE/YiwUeasLLy4UNocmXO4qByMX+D",
|
||||
"integrity": "sha384-XihJJ+5H6GH3dOVnuzv4/ykroXFbCmwSrZS5MDmw4xmhrctg7Wpz62FkZ8JCAKjK",
|
||||
"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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-Q11zxYDmXp/3KoxkMIRaPGn1KWAer2kQrJTpE/YiwUeasLLy4UNocmXO4qByMX+D\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-XihJJ+5H6GH3dOVnuzv4/ykroXFbCmwSrZS5MDmw4xmhrctg7Wpz62FkZ8JCAKjK\" 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-Q11zxYDmXp/3KoxkMIRaPGn1KWAer2kQrJTpE/YiwUeasLLy4UNocmXO4qByMX+D\" 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-XihJJ+5H6GH3dOVnuzv4/ykroXFbCmwSrZS5MDmw4xmhrctg7Wpz62FkZ8JCAKjK\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-Q11zxYDmXp/3KoxkMIRaPGn1KWAer2kQrJTpE/YiwUeasLLy4UNocmXO4qByMX+D\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-XihJJ+5H6GH3dOVnuzv4/ykroXFbCmwSrZS5MDmw4xmhrctg7Wpz62FkZ8JCAKjK\" 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-Rc4Fi2DHGSwNMZf91ng3ejXA5JBPzCKgQi9DJ1sQcr9PUq819LAhBHvFU/NbyMwR",
|
||||
"integrity": "sha384-qpx82oeZ306lvi0Z8J5l/575pzWq3dVBOjHScHpKAaa0bwFTC5QUdT2iv/OQNghH",
|
||||
"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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-Rc4Fi2DHGSwNMZf91ng3ejXA5JBPzCKgQi9DJ1sQcr9PUq819LAhBHvFU/NbyMwR\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-qpx82oeZ306lvi0Z8J5l/575pzWq3dVBOjHScHpKAaa0bwFTC5QUdT2iv/OQNghH\" 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": [
|
||||
{
|
||||
|
|
@ -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-anX4V4pEfRqe+f9rN213v39mEAh0xxI0lfKOPD+mnaIk6+xV+RX1Y5wKcDgfcK6d",
|
||||
"integrity": "sha384-AAattix3svi8r4BuxeWrOrNjBj3Wj8qN4eKNzxbzN6jN5m7cZRzlgk1WKJf32Exo",
|
||||
"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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-research-map/doxa-research-map.js\" integrity=\"sha384-anX4V4pEfRqe+f9rN213v39mEAh0xxI0lfKOPD+mnaIk6+xV+RX1Y5wKcDgfcK6d\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-research-map/doxa-research-map.js\" integrity=\"sha384-AAattix3svi8r4BuxeWrOrNjBj3Wj8qN4eKNzxbzN6jN5m7cZRzlgk1WKJf32Exo\" 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": [
|
||||
{
|
||||
|
|
@ -945,7 +945,7 @@
|
|||
"bundle": "research-dashboard",
|
||||
"scriptUrl": "./research-dashboard/research-dashboard.js",
|
||||
"output": "doxa-maps/research-dashboard/research-dashboard.js",
|
||||
"integrity": "sha384-XSv+S9wdJPrm9k2jVIG4/ePgm1bLW8LYytJuk5kqXP9yI5xOuJCZQ44m4XOt1u9n",
|
||||
"integrity": "sha384-+uouXw2z3eWUn0rgvEz2ShH++tNE1peL6y71YwSTtIb8U3ZmiNZLHo4VeNdbM2z3",
|
||||
"elements": [
|
||||
"research-dashboard-map"
|
||||
],
|
||||
|
|
@ -961,7 +961,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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-XSv+S9wdJPrm9k2jVIG4/ePgm1bLW8LYytJuk5kqXP9yI5xOuJCZQ44m4XOt1u9n\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-+uouXw2z3eWUn0rgvEz2ShH++tNE1peL6y71YwSTtIb8U3ZmiNZLHo4VeNdbM2z3\" 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"
|
||||
}
|
||||
|
|
@ -971,7 +971,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-t6tBUjmfjY8cMNakP20wiAraSH/bCaDW/WjXB+nm1dptLXjbTg4aqvKaXeYFjNvD",
|
||||
"integrity": "sha384-v2+Jd0fQXjGxkzsP4eonNOTQ4FeZQFVgdrOYGsLmtuUIXKWgUJ9PBf33AF+mNQKX",
|
||||
"elements": [
|
||||
"research-map-plus-grid"
|
||||
],
|
||||
|
|
@ -991,7 +991,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-t6tBUjmfjY8cMNakP20wiAraSH/bCaDW/WjXB+nm1dptLXjbTg4aqvKaXeYFjNvD\" 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-v2+Jd0fQXjGxkzsP4eonNOTQ4FeZQFVgdrOYGsLmtuUIXKWgUJ9PBf33AF+mNQKX\" 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": [
|
||||
{
|
||||
|
|
|
|||
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-anX4V4pEfRqe+f9rN213v39mEAh0xxI0lfKOPD+mnaIk6+xV+RX1Y5wKcDgfcK6d" crossorigin="anonymous"></script>
|
||||
<script src="../doxa-research-map.js" integrity="sha384-AAattix3svi8r4BuxeWrOrNjBj3Wj8qN4eKNzxbzN6jN5m7cZRzlgk1WKJf32Exo" 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-anX4V4pEfRqe+f9rN213v39mEAh0xxI0lfKOPD+mnaIk6+xV+RX1Y5wKcDgfcK6d" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-research-map.js" integrity="sha384-AAattix3svi8r4BuxeWrOrNjBj3Wj8qN4eKNzxbzN6jN5m7cZRzlgk1WKJf32Exo" 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
24
public/doxa-maps/manifest.json
generated
24
public/doxa-maps/manifest.json
generated
|
|
@ -158,7 +158,7 @@
|
|||
"bundle": "country-posters",
|
||||
"scriptUrl": "./country-posters/country-posters.js",
|
||||
"output": "doxa-maps/country-posters/country-posters.js",
|
||||
"integrity": "sha384-Q11zxYDmXp/3KoxkMIRaPGn1KWAer2kQrJTpE/YiwUeasLLy4UNocmXO4qByMX+D",
|
||||
"integrity": "sha384-XihJJ+5H6GH3dOVnuzv4/ykroXFbCmwSrZS5MDmw4xmhrctg7Wpz62FkZ8JCAKjK",
|
||||
"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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-Q11zxYDmXp/3KoxkMIRaPGn1KWAer2kQrJTpE/YiwUeasLLy4UNocmXO4qByMX+D\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-XihJJ+5H6GH3dOVnuzv4/ykroXFbCmwSrZS5MDmw4xmhrctg7Wpz62FkZ8JCAKjK\" 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-Q11zxYDmXp/3KoxkMIRaPGn1KWAer2kQrJTpE/YiwUeasLLy4UNocmXO4qByMX+D\" 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-XihJJ+5H6GH3dOVnuzv4/ykroXFbCmwSrZS5MDmw4xmhrctg7Wpz62FkZ8JCAKjK\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-Q11zxYDmXp/3KoxkMIRaPGn1KWAer2kQrJTpE/YiwUeasLLy4UNocmXO4qByMX+D\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-XihJJ+5H6GH3dOVnuzv4/ykroXFbCmwSrZS5MDmw4xmhrctg7Wpz62FkZ8JCAKjK\" 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-Rc4Fi2DHGSwNMZf91ng3ejXA5JBPzCKgQi9DJ1sQcr9PUq819LAhBHvFU/NbyMwR",
|
||||
"integrity": "sha384-qpx82oeZ306lvi0Z8J5l/575pzWq3dVBOjHScHpKAaa0bwFTC5QUdT2iv/OQNghH",
|
||||
"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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-Rc4Fi2DHGSwNMZf91ng3ejXA5JBPzCKgQi9DJ1sQcr9PUq819LAhBHvFU/NbyMwR\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-qpx82oeZ306lvi0Z8J5l/575pzWq3dVBOjHScHpKAaa0bwFTC5QUdT2iv/OQNghH\" 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": [
|
||||
{
|
||||
|
|
@ -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-anX4V4pEfRqe+f9rN213v39mEAh0xxI0lfKOPD+mnaIk6+xV+RX1Y5wKcDgfcK6d",
|
||||
"integrity": "sha384-AAattix3svi8r4BuxeWrOrNjBj3Wj8qN4eKNzxbzN6jN5m7cZRzlgk1WKJf32Exo",
|
||||
"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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-research-map/doxa-research-map.js\" integrity=\"sha384-anX4V4pEfRqe+f9rN213v39mEAh0xxI0lfKOPD+mnaIk6+xV+RX1Y5wKcDgfcK6d\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-research-map/doxa-research-map.js\" integrity=\"sha384-AAattix3svi8r4BuxeWrOrNjBj3Wj8qN4eKNzxbzN6jN5m7cZRzlgk1WKJf32Exo\" 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": [
|
||||
{
|
||||
|
|
@ -945,7 +945,7 @@
|
|||
"bundle": "research-dashboard",
|
||||
"scriptUrl": "./research-dashboard/research-dashboard.js",
|
||||
"output": "doxa-maps/research-dashboard/research-dashboard.js",
|
||||
"integrity": "sha384-XSv+S9wdJPrm9k2jVIG4/ePgm1bLW8LYytJuk5kqXP9yI5xOuJCZQ44m4XOt1u9n",
|
||||
"integrity": "sha384-+uouXw2z3eWUn0rgvEz2ShH++tNE1peL6y71YwSTtIb8U3ZmiNZLHo4VeNdbM2z3",
|
||||
"elements": [
|
||||
"research-dashboard-map"
|
||||
],
|
||||
|
|
@ -961,7 +961,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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-XSv+S9wdJPrm9k2jVIG4/ePgm1bLW8LYytJuk5kqXP9yI5xOuJCZQ44m4XOt1u9n\" 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": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-+uouXw2z3eWUn0rgvEz2ShH++tNE1peL6y71YwSTtIb8U3ZmiNZLHo4VeNdbM2z3\" 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"
|
||||
}
|
||||
|
|
@ -971,7 +971,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-t6tBUjmfjY8cMNakP20wiAraSH/bCaDW/WjXB+nm1dptLXjbTg4aqvKaXeYFjNvD",
|
||||
"integrity": "sha384-v2+Jd0fQXjGxkzsP4eonNOTQ4FeZQFVgdrOYGsLmtuUIXKWgUJ9PBf33AF+mNQKX",
|
||||
"elements": [
|
||||
"research-map-plus-grid"
|
||||
],
|
||||
|
|
@ -991,7 +991,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-t6tBUjmfjY8cMNakP20wiAraSH/bCaDW/WjXB+nm1dptLXjbTg4aqvKaXeYFjNvD\" 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-v2+Jd0fQXjGxkzsP4eonNOTQ4FeZQFVgdrOYGsLmtuUIXKWgUJ9PBf33AF+mNQKX\" 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": [
|
||||
{
|
||||
|
|
|
|||
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-XSv+S9wdJPrm9k2jVIG4/ePgm1bLW8LYytJuk5kqXP9yI5xOuJCZQ44m4XOt1u9n" crossorigin="anonymous"></script>
|
||||
<script src="../research-dashboard.js" integrity="sha384-+uouXw2z3eWUn0rgvEz2ShH++tNE1peL6y71YwSTtIb8U3ZmiNZLHo4VeNdbM2z3" 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-t6tBUjmfjY8cMNakP20wiAraSH/bCaDW/WjXB+nm1dptLXjbTg4aqvKaXeYFjNvD" crossorigin="anonymous"></script>
|
||||
<script src="../../research-map-plus-grid.js" integrity="sha384-v2+Jd0fQXjGxkzsP4eonNOTQ4FeZQFVgdrOYGsLmtuUIXKWgUJ9PBf33AF+mNQKX" 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-t6tBUjmfjY8cMNakP20wiAraSH/bCaDW/WjXB+nm1dptLXjbTg4aqvKaXeYFjNvD" crossorigin="anonymous"></script>
|
||||
<script src="../research-map-plus-grid.js" integrity="sha384-v2+Jd0fQXjGxkzsP4eonNOTQ4FeZQFVgdrOYGsLmtuUIXKWgUJ9PBf33AF+mNQKX" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
Loading…
Reference in a new issue