Reduced motion jumps, and 31 more strings stop being typed in English
★ THE CAMERA DID NOT JUMP, AND THE DRIVER IS PHOTOSENSITIVE.
rega measured it in a real browser: with prefers-reduced-motion set, the
grid→map framing still animated for ~5.0s on MapLibre and ~6.7s on Mapbox —
indistinguishable from no preference at all, where a jump is ~0ms. The
preference was read correctly here and thrown away one layer down: useMapFly's
`flyToCoords(coords, zoom)` takes NO options argument, so the `{ duration: 0 }`
being handed to it went nowhere. Its neighbour `fitBounds(bounds, padding,
options)` does accept one — two functions in one file, different signatures, and
nothing at the call site to show it.
So the reduced-motion branch now drives the engine directly (jumpTo, or
fitBounds with duration 0) instead of depending on whether a helper forwards an
option. The eased paths are unchanged and still go through mapFly, so ordinary
motion keeps one owner. The library asymmetry is reported separately; it affects
every reduced-motion caller of flyToCoords, not just this one.
check:reduced-motion-jumps proves the DECISION headlessly — it lifts the real
camera block out of the SFC and runs it against a mocked matchMedia and a
recording map, over four shapes of selection:
several peoples reduce=true → map.fitBounds(duration 0) false → mapFly.fitBounds
one people reduce=true → map.jumpTo false → mapFly.flyToCoords
tight cluster reduce=true → map.jumpTo false → mapFly.flyToCoords
globe-spanning reduce=true → map.jumpTo false → mapFly.flyToCoords
It cannot prove the engine honours duration 0 — that stays rega's half. It
proves we ASK for a jump, which is the half that was wrong, and it runs in
milliseconds instead of six seconds of watching movestart→moveend.
★ AND THE SCREEN-READER BLIND SPOT. A source audit of both my maps found 31
user-visible strings that no check could see: 24 with no catalogue entry at all
(invisible to check:composite-locale-leaks, whose criterion is that the
catalogue already holds the string) and 7 that HAVE a translation in eleven
languages and were still typed into the template. Most are aria-labels, titles
and tooltips — text only a screen-reader user or a hovering mouse ever meets.
Our localization verification had been "what can I see", and the blind spot was
exactly the readers who most need the words.
All 31 are wired now; the audit reports 0/0 for this lane. Two were duplicates
resolved by REUSING the existing key rather than adding a second: "Export CSV ↓"
→ dashboard.export_csv with the arrow kept as a glyph, and the chip's "Clear
all" → controls.reset_all, since clearing every filter is the action that button
already names. Two keys for one action is how a control ends up saying two
different things in two languages.
The keys themselves live in library/i18n and are a separate rule-5B handoff, so
until they land every one of these falls back to the English it reads today.
This commit is contained in:
parent
bda2d6fa6c
commit
7d6bb6bcdd
25 changed files with 352 additions and 187 deletions
|
|
@ -49,6 +49,7 @@
|
|||
* Becomes tab-1 of the Cat-5 SPA.
|
||||
*/
|
||||
import { computed, reactive, ref, watchEffect } from 'vue'
|
||||
import { tStatic } from '@map/i18n/index.js'
|
||||
import { SUPPORTED_LOCALES, setRuntimeLocale } from '@map/i18n/index.js'
|
||||
import BpResearchHeader from './src/components/BpResearchHeader.vue'
|
||||
// The REAL cap-2 grid — same component the standalone <people-groups-grid> ships (no fork).
|
||||
|
|
@ -146,7 +147,7 @@ function onGroupsFiltered(payload) {
|
|||
architecture note (header↔grid via props/events, no shared bus, tab-1 of the SPA)
|
||||
lives in this file's header block, not in the UI where an end user reads it. -->
|
||||
<footer class="bp-foot">
|
||||
Search and filter the world's people groups · least-reached shown first
|
||||
{{ tStatic('dashboard.bp_subtitle') || "Search and filter the world's people groups · least-reached shown first" }}
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -154,6 +154,11 @@ import { useLegendData } from '@map/composables/legends/useLegendData.js'
|
|||
import { mapDefaults } from '@map/constants/mapDefaults.js'
|
||||
import { getColorStrategy } from '@map/colors/_registry.js'
|
||||
import { RELIGION_FAMILIES } from '@map/colors/religion.js'
|
||||
import { tStatic } from '@map/i18n/index.js'
|
||||
|
||||
// This map's own chrome, read out of the catalogue. tStatic and not useI18n: this component is the
|
||||
// root of a custom element, where useI18n() cannot resolve its injection and throws.
|
||||
const T = (key, en) => tStatic(key) || en
|
||||
import { DataSourceManager } from '@map/utils/DataSourceManager.js'
|
||||
import sourcesConfig from '@map/api/sources.json'
|
||||
|
||||
|
|
@ -2269,18 +2274,36 @@ function applyFitSlugs(slugs) {
|
|||
}
|
||||
if (!n) return // nothing this map holds — say nothing rather than fly nowhere
|
||||
|
||||
const duration = prefersReducedMotion() ? 0 : FLY_DURATION_MS
|
||||
const spanLng = maxLng - minLng
|
||||
const spanLat = maxLat - minLat
|
||||
if (spanLng > WIDE_SPAN_DEG) {
|
||||
mapFly.flyToCoords?.({ longitude: (minLng + maxLng) / 2, latitude: (minLat + maxLat) / 2 }, WORLD_ZOOM, { duration })
|
||||
return
|
||||
const centre = { longitude: (minLng + maxLng) / 2, latitude: (minLat + maxLat) / 2 }
|
||||
const point = spanLng > WIDE_SPAN_DEG ? { c: centre, z: WORLD_ZOOM }
|
||||
: (n === 1 || (spanLng < DEGENERATE_SPAN_DEG && spanLat < DEGENERATE_SPAN_DEG))
|
||||
? { c: { longitude: minLng, latitude: minLat }, z: SINGLE_ROW_ZOOM }
|
||||
: null
|
||||
|
||||
// ★ REDUCED MOTION DRIVES THE MAP DIRECTLY, and that is not belt-and-braces.
|
||||
// MEASURED by rega with the browser's prefers-reduced-motion: reduce set: the framing move still
|
||||
// animated for ~5s on MapLibre and ~6.7s on Mapbox — essentially the same as without it, where a
|
||||
// jump is ~0ms. So the preference was being honoured in THIS file and thrown away downstream:
|
||||
// useMapFly's flyToCoords(coords, zoom) takes NO options argument at all, so the `{ duration: 0 }`
|
||||
// I was passing it went nowhere. (fitBounds does accept one; flyToCoords does not — a difference
|
||||
// between two neighbours in one file, invisible at the call site.)
|
||||
//
|
||||
// A photosensitive reader is the whole reason this branch exists, so it no longer depends on
|
||||
// whether a helper happens to forward an option: it calls the engine's own jump. The eased paths
|
||||
// are unchanged and still go through mapFly, so ordinary motion keeps one owner.
|
||||
const m = map.value
|
||||
if (prefersReducedMotion() && m) {
|
||||
try {
|
||||
if (point) m.jumpTo({ center: [point.c.longitude, point.c.latitude], zoom: point.z })
|
||||
else m.fitBounds([[minLng, minLat], [maxLng, maxLat]], { padding: FIT_PADDING_PX, maxZoom: FIT_MAX_ZOOM, duration: 0 })
|
||||
return
|
||||
} catch (_) { /* fall through to the eased path rather than not moving at all */ }
|
||||
}
|
||||
if (n === 1 || (spanLng < DEGENERATE_SPAN_DEG && spanLat < DEGENERATE_SPAN_DEG)) {
|
||||
mapFly.flyToCoords?.({ longitude: minLng, latitude: minLat }, SINGLE_ROW_ZOOM, { duration })
|
||||
return
|
||||
}
|
||||
mapFly.fitBounds?.([[minLng, minLat], [maxLng, maxLat]], FIT_PADDING_PX, { maxZoom: FIT_MAX_ZOOM, duration })
|
||||
|
||||
if (point) { mapFly.flyToCoords?.(point.c, point.z); return }
|
||||
mapFly.fitBounds?.([[minLng, minLat], [maxLng, maxLat]], FIT_PADDING_PX, { maxZoom: FIT_MAX_ZOOM, duration: FLY_DURATION_MS })
|
||||
}
|
||||
|
||||
// ─── Clusters wiring: TWO CONTROLS, ONE STATE ────────────────────────────────
|
||||
|
|
@ -2557,8 +2580,8 @@ onBeforeUnmount(() => {
|
|||
</div>
|
||||
|
||||
<div class="rm-map-area">
|
||||
<div v-if="!appReady && !mapError" class="rm-loading">Research map loading…</div>
|
||||
<div v-if="mapError" class="rm-error">The map could not be loaded. {{ mapError }}</div>
|
||||
<div v-if="!appReady && !mapError" class="rm-loading">{{ T('dashboard.map_loading', 'Research map loading…') }}</div>
|
||||
<div v-if="mapError" class="rm-error">{{ T('allPeopleGroups.loadError', 'The map could not be loaded.') }} {{ mapError }}</div>
|
||||
<div ref="mapContainer" class="rm-map-canvas" />
|
||||
<div class="map-scroll-edge map-scroll-edge--left" />
|
||||
<div class="map-scroll-edge map-scroll-edge--right" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,122 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* check-reduced-motion-jumps.mjs — with prefers-reduced-motion, the grid→map framing must JUMP.
|
||||
*
|
||||
* ★ THE DRIVER IS PHOTOSENSITIVE. This is not a polish item: a camera that sweeps the globe every
|
||||
* time a list is filtered is the strobe class this repo has already paid for once.
|
||||
*
|
||||
* THE DEFECT, measured by rega in a real browser with the preference set: the framing move still
|
||||
* animated for ~5.0s on MapLibre and ~6.7s on Mapbox — indistinguishable from no preference at all,
|
||||
* where a jump is ~0ms. The preference WAS being read correctly in research-map.vue and then thrown
|
||||
* away one layer down: useMapFly's `flyToCoords(coords, zoom)` takes NO options argument, so the
|
||||
* `{ duration: 0 }` being passed to it went nowhere. Its neighbour `fitBounds(bounds, padding,
|
||||
* options)` does accept one — two functions in one file, different signatures, and nothing at the
|
||||
* call site to show it.
|
||||
*
|
||||
* ★ WHY THIS RUNS WITHOUT A BROWSER, WHICH IS THE POINT. rega found it by watching movestart →
|
||||
* moveend for six seconds; only rega can do that, and only occasionally. What can be checked any
|
||||
* time, in milliseconds, is the DECISION: given the preference, which camera call does the code
|
||||
* make? So this lifts the real camera block out of the SFC, runs it against a mocked matchMedia and
|
||||
* a recording map, and asserts the call that comes out.
|
||||
*
|
||||
* It cannot prove the engine honours duration 0 — that is rega's half. It proves we ASK for a jump,
|
||||
* which is the half that was wrong.
|
||||
*
|
||||
* ASSERTIONS:
|
||||
* reduced motion ON the engine's own jumpTo / fitBounds(duration:0) is called, and the eased
|
||||
* helper (mapFly) is NOT — a single eased call is the whole bug.
|
||||
* reduced motion OFF the eased path is used, so ordinary motion is unchanged.
|
||||
* one row / a tight cluster / a globe-spanning set all take their own branch under both.
|
||||
*
|
||||
* Exit: 0 pass · 1 fail · 2 the camera block could not be found (reported, never silently skipped).
|
||||
*/
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve, dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { parse as parseSFC } from '@vue/compiler-sfc'
|
||||
|
||||
const TAG = 'REDUCED-MOTION-JUMPS'
|
||||
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', '..')
|
||||
const FILE = join(ROOT, 'plugin-designs', 'doxa-research-map', 'research-map.vue')
|
||||
|
||||
const src = readFileSync(FILE, 'utf8')
|
||||
const { descriptor } = parseSFC(src, { filename: FILE })
|
||||
const script = (descriptor.scriptSetup || descriptor.script || {}).content || ''
|
||||
|
||||
// The block is delimited by its own banner comments, so a refactor that moves it renames the
|
||||
// markers with it rather than leaving this gate quietly reading the wrong lines.
|
||||
const START = 'const FIT_PADDING_PX'
|
||||
const END = '// ─── Clusters wiring: TWO CONTROLS, ONE STATE'
|
||||
// indexOf from the START, not from 0: an identical-looking line can appear earlier in a file this
|
||||
// size, and a block that runs from the right start to the wrong end parses into nonsense.
|
||||
const a = script.indexOf(START)
|
||||
const b = a >= 0 ? script.indexOf(END, a) : -1
|
||||
if (a < 0 || b < 0 || b < a) {
|
||||
console.log(`${TAG}: FAIL — could not find the camera block in research-map.vue (markers moved?).`)
|
||||
process.exit(2)
|
||||
}
|
||||
const block = script.slice(a, b)
|
||||
if (!/function applyFitSlugs/.test(block) || !/function prefersReducedMotion/.test(block)) {
|
||||
console.log(`${TAG}: FAIL — the block found does not contain applyFitSlugs and prefersReducedMotion.`)
|
||||
process.exit(2)
|
||||
}
|
||||
|
||||
/** Build the block with its collaborators injected, so the REAL code runs against fakes. */
|
||||
function makeCamera({ reduce }) {
|
||||
const calls = []
|
||||
const rec = (name) => (...args) => calls.push({ name, args })
|
||||
const map = { value: { jumpTo: rec('map.jumpTo'), fitBounds: rec('map.fitBounds'), easeTo: rec('map.easeTo'), flyTo: rec('map.flyTo') } }
|
||||
const mapFly = { flyToCoords: rec('mapFly.flyToCoords'), fitBounds: rec('mapFly.fitBounds'), flyTo: rec('mapFly.flyTo') }
|
||||
const rows = []
|
||||
const mapData = { normalizedPeopleGroups: { value: rows } }
|
||||
const win = { matchMedia: (q) => ({ matches: reduce && /prefers-reduced-motion/.test(q) }) }
|
||||
// eslint-disable-next-line no-new-func
|
||||
const factory = new Function('map', 'mapData', 'mapFly', 'window', `${block}\n;return { applyFitSlugs, prefersReducedMotion }`)
|
||||
const api = factory(map, mapData, mapFly, win)
|
||||
return { ...api, calls, rows }
|
||||
}
|
||||
|
||||
const cases = [
|
||||
{ name: 'several peoples', rows: [
|
||||
{ slug: 'a', longitude: 10, latitude: 5 }, { slug: 'b', longitude: 14, latitude: 9 }, { slug: 'c', longitude: 12, latitude: 7 },
|
||||
], slugs: ['a', 'b', 'c'] },
|
||||
{ name: 'one people', rows: [{ slug: 'a', longitude: 10, latitude: 5 }], slugs: ['a'] },
|
||||
{ name: 'tight cluster', rows: [
|
||||
{ slug: 'a', longitude: 10, latitude: 5 }, { slug: 'b', longitude: 10.001, latitude: 5.001 },
|
||||
], slugs: ['a', 'b'] },
|
||||
{ name: 'globe-spanning', rows: [
|
||||
{ slug: 'a', longitude: -170, latitude: -40 }, { slug: 'b', longitude: 170, latitude: 60 },
|
||||
], slugs: ['a', 'b'] },
|
||||
]
|
||||
|
||||
const fails = []
|
||||
const lines = []
|
||||
for (const c of cases) {
|
||||
for (const reduce of [true, false]) {
|
||||
const cam = makeCamera({ reduce })
|
||||
cam.rows.push(...c.rows)
|
||||
cam.applyFitSlugs(c.slugs)
|
||||
const names = cam.calls.map((k) => k.name)
|
||||
const easedUsed = names.some((n) => n.startsWith('mapFly.'))
|
||||
const jumped = names.some((n) => n === 'map.jumpTo')
|
||||
|| cam.calls.some((k) => k.name === 'map.fitBounds' && k.args[1] && k.args[1].duration === 0)
|
||||
lines.push(` · ${c.name.padEnd(16)} reduce=${String(reduce).padEnd(5)} → ${names.join(', ') || '(no camera call)'}`)
|
||||
|
||||
if (!names.length) { fails.push(`${c.name} (reduce=${reduce}) made no camera call at all.`); continue }
|
||||
if (reduce) {
|
||||
if (!jumped) fails.push(`${c.name}: with reduced motion the code did not ask for a jump — it called ${names.join(', ')}.`)
|
||||
if (easedUsed) fails.push(`${c.name}: with reduced motion it still used the EASED helper (${names.filter((n) => n.startsWith('mapFly.')).join(', ')}) — a single eased call is the whole defect.`)
|
||||
} else {
|
||||
if (!easedUsed) fails.push(`${c.name}: without the preference the eased path should be used, got ${names.join(', ')} — ordinary motion must be unchanged.`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const l of lines) console.log(l)
|
||||
if (fails.length) {
|
||||
console.log(`\n${TAG}: FAIL`)
|
||||
for (const f of fails) console.log(` ✗ ${f}`)
|
||||
console.log('\n The Driver is photosensitive. A camera that sweeps on every filter is the defect.')
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(`${TAG}: PASS — reduced motion asks the engine to jump on every branch, and ordinary motion is untouched.`)
|
||||
|
|
@ -23,6 +23,13 @@
|
|||
* DashboardSearchHeader (DOXA-LIB-3) remains available in the kit but is not mounted here.
|
||||
*/
|
||||
import { computed, watch, inject, ref, unref, onMounted } from 'vue'
|
||||
import { tStatic } from '@map/i18n/index.js'
|
||||
|
||||
// This component's chrome, read out of the catalogue. tStatic and not useI18n: these mount inside
|
||||
// custom elements that install no i18n plugin, and an unguarded useI18n() throws on the way in and
|
||||
// takes the subtree with it. The English stays as the fallback, so a missing key degrades to what
|
||||
// shipped rather than to a key name.
|
||||
const T = (key, en) => tStatic(key) || en
|
||||
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
||||
import { useDashboardShell, fmt } from './src/composables/useDashboardShell.js'
|
||||
import { useDashboardLayout } from './src/composables/useDashboardLayout.js'
|
||||
|
|
@ -732,12 +739,12 @@ onMounted(() => {
|
|||
owns, so the two input methods can never disagree about the current value. -->
|
||||
<div v-show="!isNarrow && !facetCollapsed" class="rd-rz rd-rz-facet" data-resize="facet"
|
||||
role="separator" aria-orientation="vertical" tabindex="0"
|
||||
title="Drag or use arrow keys to resize the filters rail" aria-label="Resize filters rail"
|
||||
:title="T('aria.resizeFiltersRailHint', 'Drag or use arrow keys to resize the filters rail')" :aria-label="T('aria.resizeFiltersRail', 'Resize filters rail')"
|
||||
:aria-valuenow="facetW" aria-valuemin="160" aria-valuemax="420"
|
||||
@pointerdown="startFacetResize" @keydown="onResizeKeydown('facet', $event)"></div>
|
||||
<div v-show="!isNarrow && !railCollapsed" class="rd-rz rd-rz-rail" data-resize="rail"
|
||||
role="separator" aria-orientation="vertical" tabindex="0"
|
||||
title="Drag or use arrow keys to resize the charts rail" aria-label="Resize charts rail"
|
||||
:title="T('aria.resizeChartsRailHint', 'Drag or use arrow keys to resize the charts rail')" :aria-label="T('aria.resizeChartsRail', 'Resize charts rail')"
|
||||
:aria-valuenow="railW" aria-valuemin="200" aria-valuemax="520"
|
||||
@pointerdown="startRailResize" @keydown="onResizeKeydown('rail', $event)"></div>
|
||||
<!-- ★ FIXED (BUG-SHELL-HANDLE-BOUND-TO-WRONG-DIVIDER): this handle is the MAP/TABLE SPLIT
|
||||
|
|
@ -762,8 +769,8 @@ onMounted(() => {
|
|||
band), so there is nothing for this handle to do outside page-scroll. -->
|
||||
<div v-show="!isNarrow && pageScroll" class="rd-rz rd-rz-shell" data-resize="shell"
|
||||
role="separator" aria-orientation="horizontal" tabindex="0"
|
||||
title="Drag or use arrow keys to resize the dashboard's height"
|
||||
aria-label="Resize dashboard height"
|
||||
:title="T('aria.resizeDashboardHeightHint', `Drag or use arrow keys to resize the dashboard's height`)"
|
||||
:aria-label="T('aria.resizeDashboardHeight', 'Resize dashboard height')"
|
||||
:aria-valuenow="shellH" aria-valuemin="400" aria-valuemax="2600"
|
||||
@pointerdown="startShellResize" @keydown="onResizeKeydown('shell', $event)"></div>
|
||||
<div class="rd-seg" data-segmented @click="setView">
|
||||
|
|
@ -771,8 +778,10 @@ onMounted(() => {
|
|||
</div>
|
||||
<div v-if="selCount" class="rd-exportbar" data-export-bar @click="onBarClick">
|
||||
<b>{{ selCount }} selected</b><span class="sp"></span>
|
||||
<button class="x-clr" data-bar-clear>Clear</button>
|
||||
<button class="x-go" data-bar-export>Export CSV ↓</button>
|
||||
<button class="x-clr" data-bar-clear>{{ T('controls.clear', 'Clear') }}</button>
|
||||
<!-- The glyph stays a glyph and the words come from the catalogue — one spelling of this
|
||||
action across the dashboard, not two. -->
|
||||
<button class="x-go" data-bar-export>{{ T('dashboard.export_csv', 'Export CSV') }} ↓</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ useShadowStyles(`
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="rd-breadcrumb" data-breadcrumb @click="onClick" aria-label="Filter breadcrumb">
|
||||
<nav class="rd-breadcrumb" data-breadcrumb @click="onClick" :aria-label="tStatic('aria.filterBreadcrumb') || 'Filter breadcrumb'">
|
||||
<span class="rd-crumb root" data-crumb="__root__">{{ L('world', 'World') }}</span>
|
||||
<template v-for="(c, i) in crumbs" :key="c.k">
|
||||
<span class="rd-sep">▸</span>
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ useShadowStyles(`
|
|||
So the second tab renders DISABLED with an explicit reason rather than being hidden. A hidden
|
||||
tab is indistinguishable from an unbuilt one; a disabled tab that says why is a status report.
|
||||
-->
|
||||
<div class="rd-tabs" role="tablist" aria-label="Rail views">
|
||||
<div class="rd-tabs" role="tablist" :aria-label="tStatic('aria.railViews') || 'Rail views'">
|
||||
<button
|
||||
v-for="t in tabs" :key="t.id"
|
||||
class="rd-tab" :class="{ on: activeTab === t.id, off: t.disabled }"
|
||||
|
|
|
|||
|
|
@ -806,10 +806,10 @@ useShadowStyles(`
|
|||
<template v-if="selCount">
|
||||
<button class="rd-vtog" :class="{ on: onlySelected }" data-only-selected
|
||||
:aria-pressed="onlySelected ? 'true' : 'false'"
|
||||
title="Show only the selected people groups" @click="toggleOnlySelected">Only selected</button>
|
||||
:title="T('dashboard.only_selected_hint', 'Show only the selected people groups')" @click="toggleOnlySelected">{{ T('dashboard.only_selected', 'Only selected') }}</button>
|
||||
<button class="rd-vtog" :class="{ on: selectedFirst }" data-selected-first
|
||||
:aria-pressed="selectedFirst ? 'true' : 'false'"
|
||||
title="Float the selected people groups to the top, keeping your column sort" @click="toggleSelectedFirst">Selected first</button>
|
||||
:title="T('dashboard.selected_first_hint', 'Float the selected people groups to the top, keeping your column sort')" @click="toggleSelectedFirst">{{ T('dashboard.selected_first', 'Selected first') }}</button>
|
||||
</template>
|
||||
<span class="rd-bar-sp"></span>
|
||||
<!--
|
||||
|
|
|
|||
|
|
@ -157,13 +157,13 @@ useShadowStyles(`
|
|||
<section class="rd-detail" data-region="detail-drawer">
|
||||
<div class="rd-dh">
|
||||
<span>{{ T('dashboard.detail', 'Detail') }}</span>
|
||||
<button v-if="record" class="rd-detail-close" type="button" aria-label="Close detail" data-detail-close @click="clearDetail">✕</button>
|
||||
<button v-if="record" class="rd-detail-close" type="button" :aria-label="T('aria.closeDetail', 'Close detail')" data-detail-close @click="clearDetail">✕</button>
|
||||
</div>
|
||||
<div v-if="!record" class="rd-empty" data-detail-empty>{{ T('dashboard.detail_empty', 'Select a people group to see detail') }}</div>
|
||||
<template v-else>
|
||||
<div class="rd-top">
|
||||
<img v-if="showPhoto" class="rd-thumb" :src="record.image_url" :alt="record.name" data-detail-thumb />
|
||||
<div v-else class="rd-ph" data-detail-thumb>No photo</div>
|
||||
<div v-else class="rd-ph" data-detail-thumb>{{ T('dashboard.no_photo', 'No photo') }}</div>
|
||||
<div>
|
||||
<div class="rd-name" data-detail-name>{{ record.name || '—' }}</div>
|
||||
<div class="rd-meta">{{ lbl(record.country_code) || '—' }} · {{ lbl(record.religion) || '—' }}</div>
|
||||
|
|
@ -180,14 +180,14 @@ useShadowStyles(`
|
|||
</a>
|
||||
</div>
|
||||
<div class="rd-rows">
|
||||
<div class="rd-row"><span class="k">Language</span><span class="v">{{ lbl(record.primary_language) || '—' }}<span v-if="record.imb_language_family" class="fam"> ({{ record.imb_language_family }})</span></span></div>
|
||||
<div class="rd-row"><span class="k">Population</span><span class="v">{{ fmt(record.population) }}</span></div>
|
||||
<div class="rd-row"><span class="k">People praying</span><span class="v">{{ fmt(record.people_praying) }}</span></div>
|
||||
<div class="rd-row"><span class="k">People committed</span><span class="v">{{ fmt(record.people_committed) }}</span></div>
|
||||
<div class="rd-row"><span class="k">Adopted by churches</span><span class="v">{{ fmt(record.adopted_by_churches) }}</span></div>
|
||||
<div class="rd-row"><span class="k">Engagement</span><span class="v">{{ lbl(record.engagement_status) || '—' }}</span></div>
|
||||
<div class="rd-row"><span class="k">{{ T('dashboard.language', 'Language') }}</span><span class="v">{{ lbl(record.primary_language) || '—' }}<span v-if="record.imb_language_family" class="fam"> ({{ record.imb_language_family }})</span></span></div>
|
||||
<div class="rd-row"><span class="k">{{ T('dashboard.population', 'Population') }}</span><span class="v">{{ fmt(record.population) }}</span></div>
|
||||
<div class="rd-row"><span class="k">{{ T('dashboard.people_praying', 'People praying') }}</span><span class="v">{{ fmt(record.people_praying) }}</span></div>
|
||||
<div class="rd-row"><span class="k">{{ T('dashboard.people_committed', 'People committed') }}</span><span class="v">{{ fmt(record.people_committed) }}</span></div>
|
||||
<div class="rd-row"><span class="k">{{ T('dashboard.adopted_by_churches', 'Adopted by churches') }}</span><span class="v">{{ fmt(record.adopted_by_churches) }}</span></div>
|
||||
<div class="rd-row"><span class="k">{{ T('dashboard.engagement', 'Engagement') }}</span><span class="v">{{ lbl(record.engagement_status) || '—' }}</span></div>
|
||||
</div>
|
||||
<button class="rd-exp" type="button" data-detail-export @click="exportThis">Export this selection ↓</button>
|
||||
<button class="rd-exp" type="button" data-detail-export @click="exportThis">{{ T('dashboard.export_selection', 'Export this selection') }} ↓</button>
|
||||
</template>
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,12 @@
|
|||
* and is what CSV export reads later. Click delegation on the bar (defineCustomElement-safe).
|
||||
*/
|
||||
import { inject, computed } from 'vue'
|
||||
import { tStatic } from '@map/i18n/index.js'
|
||||
|
||||
// This component's chrome, read out of the catalogue. tStatic and not useI18n: these mount inside
|
||||
// custom elements that install no i18n plugin, and an unguarded useI18n() throws on the way in and
|
||||
// takes the subtree with it.
|
||||
const T = (key, en) => tStatic(key) || en
|
||||
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
||||
import { useTreeLegendLabels } from '../../composables/useTreeLegendLabels.js'
|
||||
|
||||
|
|
@ -82,6 +88,10 @@ useShadowStyles(`
|
|||
:title="c.facet + ': ' + c.text">
|
||||
<span class="fc">{{ c.facet }}:</span><span class="rd-chip-val">{{ c.text }}</span> <i>✕</i>
|
||||
</span>
|
||||
<span class="rd-chip rd-clear" data-chip="__all__">Clear all</span>
|
||||
<!-- ★ REUSES controls.reset_all rather than adding a second key. This chip clears every
|
||||
filter, which is the same action that button names, and two keys for one action is how
|
||||
a control ends up saying two different things in two languages. The English shifts from
|
||||
"Clear all" to "Reset all" — a deliberate consequence of having one name for one thing. -->
|
||||
<span class="rd-chip rd-clear" data-chip="__all__">{{ T('controls.reset_all', 'Reset all') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1679,7 +1679,7 @@ useShadowStyles(`
|
|||
<span class="rd-proj" role="button" tabindex="0" data-proj-toggle @click="toggleProjection">
|
||||
{{ projection === 'globe' ? '🌐 Globe' : '▭ Flat' }}
|
||||
</span>
|
||||
<div class="rd-legend-map" data-map-legend aria-label="UPG count legend">
|
||||
<div class="rd-legend-map" data-map-legend :aria-label="T('aria.upgCountLegend', 'UPG count legend')">
|
||||
<!-- ★ COMPOSED FROM TWO EXISTING CATALOGUE ENTRIES, not from new wording. This legend title
|
||||
was the last piece of English chrome here that could be translated without inventing a
|
||||
phrase in ten languages: legend.columns.upgs and dashboard.country both already ship in
|
||||
|
|
|
|||
|
|
@ -297,8 +297,8 @@ useShadowStyles(`
|
|||
<span class="rd-spacer" />
|
||||
<div v-if="showTopBarSearch" class="rd-search" data-search>
|
||||
<span class="ic">⌕</span>
|
||||
<input type="text" v-model="q" placeholder="Search people groups…" data-search-input
|
||||
aria-label="Search people groups" @input="onInput" @focus="onInput" @keydown="onKeydown" />
|
||||
<input type="text" v-model="q" :placeholder="tStatic('grid.search') || 'Search people groups…'" data-search-input
|
||||
:aria-label="tStatic('aria.searchPeopleGroups') || 'Search people groups'" @input="onInput" @focus="onInput" @keydown="onKeydown" />
|
||||
<div v-if="open && q.trim().length >= 2" class="rd-results" data-search-results @click="onResultsClick">
|
||||
<template v-if="results.length">
|
||||
<div v-for="(r, i) in results" :key="r.slug" class="rd-res" :class="{ on: i === active }" :data-slug="r.slug">
|
||||
|
|
@ -306,7 +306,7 @@ useShadowStyles(`
|
|||
<span class="sub">{{ lbl(r.country_code) }} · {{ lbl(r.religion) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="rd-empty">No people groups match “{{ q.trim() }}”.</div>
|
||||
<div v-else class="rd-empty">{{ (tStatic('dashboard.no_match') || 'No people groups match “{q}”.').replace('{q}', q.trim()) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="rd-align" role="button" tabindex="0" data-align-btn
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <bp-big-picture> custom element. -->
|
||||
<script src="../../big-picture.js" integrity="sha384-1ve8Id/pMRSvIucwovg81oEvCfRhFH/JzFH3WuaZmWE/B+fEDqwccO9g6o54dqqF" crossorigin="anonymous"></script>
|
||||
<script src="../../big-picture.js" integrity="sha384-H338G0CZrzPqd7wAGQAS+cZDSn34FgcjHGg5MxEitj5l7dEJzp5R/11PjttXwXdo" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <bp-big-picture> custom element. -->
|
||||
<script src="../../big-picture.js" integrity="sha384-1ve8Id/pMRSvIucwovg81oEvCfRhFH/JzFH3WuaZmWE/B+fEDqwccO9g6o54dqqF" crossorigin="anonymous"></script>
|
||||
<script src="../../big-picture.js" integrity="sha384-H338G0CZrzPqd7wAGQAS+cZDSn34FgcjHGg5MxEitj5l7dEJzp5R/11PjttXwXdo" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <bp-big-picture> custom element. -->
|
||||
<script src="../big-picture.js" integrity="sha384-1ve8Id/pMRSvIucwovg81oEvCfRhFH/JzFH3WuaZmWE/B+fEDqwccO9g6o54dqqF" crossorigin="anonymous"></script>
|
||||
<script src="../big-picture.js" integrity="sha384-H338G0CZrzPqd7wAGQAS+cZDSn34FgcjHGg5MxEitj5l7dEJzp5R/11PjttXwXdo" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -47,7 +47,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-Rma0K7fAGs6UMLQWS9QltMXu0+HFklJtBEx5la/DowF3eROMbvntpkPrz4k8dTnA" crossorigin="anonymous"></script>
|
||||
<script src="../../dashboard-plus-grid.js" integrity="sha384-QSd3UVAQytfgz8tp5Cw/jBOfktd7wMHyp/8HJ4T6uIpgeHXosXeVkfaHlKIpMhCo" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -47,7 +47,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-Rma0K7fAGs6UMLQWS9QltMXu0+HFklJtBEx5la/DowF3eROMbvntpkPrz4k8dTnA" crossorigin="anonymous"></script>
|
||||
<script src="../dashboard-plus-grid.js" integrity="sha384-QSd3UVAQytfgz8tp5Cw/jBOfktd7wMHyp/8HJ4T6uIpgeHXosXeVkfaHlKIpMhCo" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"bundle": "big-picture",
|
||||
"scriptUrl": "./big-picture/big-picture.js",
|
||||
"output": "dx-maps/big-picture/big-picture.js",
|
||||
"integrity": "sha384-1ve8Id/pMRSvIucwovg81oEvCfRhFH/JzFH3WuaZmWE/B+fEDqwccO9g6o54dqqF",
|
||||
"integrity": "sha384-H338G0CZrzPqd7wAGQAS+cZDSn34FgcjHGg5MxEitj5l7dEJzp5R/11PjttXwXdo",
|
||||
"elements": [
|
||||
"bp-big-picture",
|
||||
"bp-research-header",
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
"scriptUrl": "./big-picture/big-picture.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./big-picture/big-picture/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./big-picture/big-picture.js\" integrity=\"sha384-1ve8Id/pMRSvIucwovg81oEvCfRhFH/JzFH3WuaZmWE/B+fEDqwccO9g6o54dqqF\" crossorigin=\"anonymous\"></script>\n<bp-big-picture profile-config='{\"profile\":\"big-picture\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></bp-big-picture>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./big-picture/big-picture.js\" integrity=\"sha384-H338G0CZrzPqd7wAGQAS+cZDSn34FgcjHGg5MxEitj5l7dEJzp5R/11PjttXwXdo\" crossorigin=\"anonymous\"></script>\n<bp-big-picture profile-config='{\"profile\":\"big-picture\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></bp-big-picture>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
@ -215,7 +215,7 @@
|
|||
"bundle": "dashboard-plus-grid",
|
||||
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
|
||||
"output": "dx-maps/dashboard-plus-grid/dashboard-plus-grid.js",
|
||||
"integrity": "sha384-Rma0K7fAGs6UMLQWS9QltMXu0+HFklJtBEx5la/DowF3eROMbvntpkPrz4k8dTnA",
|
||||
"integrity": "sha384-QSd3UVAQytfgz8tp5Cw/jBOfktd7wMHyp/8HJ4T6uIpgeHXosXeVkfaHlKIpMhCo",
|
||||
"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-Rma0K7fAGs6UMLQWS9QltMXu0+HFklJtBEx5la/DowF3eROMbvntpkPrz4k8dTnA\" 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-QSd3UVAQytfgz8tp5Cw/jBOfktd7wMHyp/8HJ4T6uIpgeHXosXeVkfaHlKIpMhCo\" 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": "dx-maps/doxa-research-map/doxa-research-map.js",
|
||||
"integrity": "sha384-GgCN0nGHKw8J7FGSbGz2bt24VSYJ46wvwqoS+K6av+vkMKt9laxtButs/bY0GNtp",
|
||||
"integrity": "sha384-iBVUiDfuIK/eEa4QUg1DO1hgF3VfUngI6X0J4eySkyTLEr2fd2hRICfwmXMuQHTf",
|
||||
"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-GgCN0nGHKw8J7FGSbGz2bt24VSYJ46wvwqoS+K6av+vkMKt9laxtButs/bY0GNtp\" 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-iBVUiDfuIK/eEa4QUg1DO1hgF3VfUngI6X0J4eySkyTLEr2fd2hRICfwmXMuQHTf\" 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": "dx-maps/research-dashboard/research-dashboard.js",
|
||||
"integrity": "sha384-N8ZJTvr/l0jCSaV+3iP3gk/5R7SEwoJpMJFKEO9TYDC33wufmanR0eijkwSTO6mz",
|
||||
"integrity": "sha384-qDvCnWSrsyCV05z9BCleobeC80n7zVLObB3+kQfBhsqhCble4pf+RpOWQT5xcGS2",
|
||||
"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-N8ZJTvr/l0jCSaV+3iP3gk/5R7SEwoJpMJFKEO9TYDC33wufmanR0eijkwSTO6mz\" 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-qDvCnWSrsyCV05z9BCleobeC80n7zVLObB3+kQfBhsqhCble4pf+RpOWQT5xcGS2\" 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"
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -36,7 +36,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-GgCN0nGHKw8J7FGSbGz2bt24VSYJ46wvwqoS+K6av+vkMKt9laxtButs/bY0GNtp" crossorigin="anonymous"></script>
|
||||
<script src="../doxa-research-map.js" integrity="sha384-iBVUiDfuIK/eEa4QUg1DO1hgF3VfUngI6X0J4eySkyTLEr2fd2hRICfwmXMuQHTf" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -33,7 +33,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-GgCN0nGHKw8J7FGSbGz2bt24VSYJ46wvwqoS+K6av+vkMKt9laxtButs/bY0GNtp" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-research-map.js" integrity="sha384-iBVUiDfuIK/eEa4QUg1DO1hgF3VfUngI6X0J4eySkyTLEr2fd2hRICfwmXMuQHTf" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"bundle": "big-picture",
|
||||
"scriptUrl": "./big-picture/big-picture.js",
|
||||
"output": "dx-maps/big-picture/big-picture.js",
|
||||
"integrity": "sha384-1ve8Id/pMRSvIucwovg81oEvCfRhFH/JzFH3WuaZmWE/B+fEDqwccO9g6o54dqqF",
|
||||
"integrity": "sha384-H338G0CZrzPqd7wAGQAS+cZDSn34FgcjHGg5MxEitj5l7dEJzp5R/11PjttXwXdo",
|
||||
"elements": [
|
||||
"bp-big-picture",
|
||||
"bp-research-header",
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
"scriptUrl": "./big-picture/big-picture.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./big-picture/big-picture/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./big-picture/big-picture.js\" integrity=\"sha384-1ve8Id/pMRSvIucwovg81oEvCfRhFH/JzFH3WuaZmWE/B+fEDqwccO9g6o54dqqF\" crossorigin=\"anonymous\"></script>\n<bp-big-picture profile-config='{\"profile\":\"big-picture\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></bp-big-picture>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./big-picture/big-picture.js\" integrity=\"sha384-H338G0CZrzPqd7wAGQAS+cZDSn34FgcjHGg5MxEitj5l7dEJzp5R/11PjttXwXdo\" crossorigin=\"anonymous\"></script>\n<bp-big-picture profile-config='{\"profile\":\"big-picture\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></bp-big-picture>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
@ -215,7 +215,7 @@
|
|||
"bundle": "dashboard-plus-grid",
|
||||
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
|
||||
"output": "dx-maps/dashboard-plus-grid/dashboard-plus-grid.js",
|
||||
"integrity": "sha384-Rma0K7fAGs6UMLQWS9QltMXu0+HFklJtBEx5la/DowF3eROMbvntpkPrz4k8dTnA",
|
||||
"integrity": "sha384-QSd3UVAQytfgz8tp5Cw/jBOfktd7wMHyp/8HJ4T6uIpgeHXosXeVkfaHlKIpMhCo",
|
||||
"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-Rma0K7fAGs6UMLQWS9QltMXu0+HFklJtBEx5la/DowF3eROMbvntpkPrz4k8dTnA\" 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-QSd3UVAQytfgz8tp5Cw/jBOfktd7wMHyp/8HJ4T6uIpgeHXosXeVkfaHlKIpMhCo\" 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": "dx-maps/doxa-research-map/doxa-research-map.js",
|
||||
"integrity": "sha384-GgCN0nGHKw8J7FGSbGz2bt24VSYJ46wvwqoS+K6av+vkMKt9laxtButs/bY0GNtp",
|
||||
"integrity": "sha384-iBVUiDfuIK/eEa4QUg1DO1hgF3VfUngI6X0J4eySkyTLEr2fd2hRICfwmXMuQHTf",
|
||||
"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-GgCN0nGHKw8J7FGSbGz2bt24VSYJ46wvwqoS+K6av+vkMKt9laxtButs/bY0GNtp\" 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-iBVUiDfuIK/eEa4QUg1DO1hgF3VfUngI6X0J4eySkyTLEr2fd2hRICfwmXMuQHTf\" 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": "dx-maps/research-dashboard/research-dashboard.js",
|
||||
"integrity": "sha384-N8ZJTvr/l0jCSaV+3iP3gk/5R7SEwoJpMJFKEO9TYDC33wufmanR0eijkwSTO6mz",
|
||||
"integrity": "sha384-qDvCnWSrsyCV05z9BCleobeC80n7zVLObB3+kQfBhsqhCble4pf+RpOWQT5xcGS2",
|
||||
"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-N8ZJTvr/l0jCSaV+3iP3gk/5R7SEwoJpMJFKEO9TYDC33wufmanR0eijkwSTO6mz\" 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-qDvCnWSrsyCV05z9BCleobeC80n7zVLObB3+kQfBhsqhCble4pf+RpOWQT5xcGS2\" 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"
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -36,7 +36,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-N8ZJTvr/l0jCSaV+3iP3gk/5R7SEwoJpMJFKEO9TYDC33wufmanR0eijkwSTO6mz" crossorigin="anonymous"></script>
|
||||
<script src="../research-dashboard.js" integrity="sha384-qDvCnWSrsyCV05z9BCleobeC80n7zVLObB3+kQfBhsqhCble4pf+RpOWQT5xcGS2" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
Loading…
Reference in a new issue