Simple Research + Big Picture: the host's style stops at the box, and the last English goes

TWO FIXES THAT BOTH SHOW UP ONLY WHEN THESE PLUGINS ARE SOMEBODY ELSE'S GUEST.

1. ATTRIBUTE FALLTHROUGH. These SFCs mount AS custom elements, so a style the
   host puts on the tag lands on the component's own root element. MEASURED with
   a host style of "display:flex; position:relative; height:100%": that exact
   string appeared verbatim on the inner root div of people-groups-grid,
   stack-demo, research-map-plus-grid and dashboard-plus-grid. The gallery sets
   one on every tab, and the same fallthrough collapsed the Prayer Walk Planner
   to 76px. inheritAttrs:false on each root — a host styling the TAG is styling
   the box, not our internals.
   AFTER: the inner root carries no inline style on any of the four, and each
   still renders full height (2997-4010px in the harness), so the guard did not
   become the collapse it prevents.
   Worth knowing for the next probe: shadowRoot.firstElementChild is a <style>
   node — Vue injects styles first — so a probe that trusts it measures nothing
   and reports "no fallthrough, nothing to fix". Take the first non-style child.

2. THE RESIDUAL CHROME the in-gallery re-measure found: the dashboard title,
   Align Dashboard and its tooltip, World, Vertical Legend, groups in scope, the
   per-row aria templates (Filter by / Remove filter / groups), and the map
   drawer's aria label. Catalogued in all 11 locales and read through tStatic,
   reusing existing wording where the catalogue already had the word.

The aria TEMPLATES matter more than their size suggests: they repeat per row, so
one untranslated template is dozens of English strings in a screen-reader's ear.
This commit is contained in:
doxa-maps-88655c70 2026-09-25 08:19:56 +00:00
parent a9a44c3eb1
commit 7f700935c5
41 changed files with 360 additions and 106 deletions

View file

@ -39,7 +39,7 @@ import { tStatic } from '@map/i18n/index.js'
// reachable from mounts that install no i18n plugin, and an unguarded useI18n() throws and takes
// the subtree with it (the defect that blanked people-groups-grid, fixed in 6603dc17). English
// stays as the last argument, so a missing key degrades to today's text rather than to a key name.
const L = (key, en) => tStatic('controls.' + key) || en
const L = (key, en) => tStatic('controls.' + key) || tStatic('dashboard.' + key) || en
const mapStore = inject('mapStore')
const uiStore = inject('uiStore')
@ -94,7 +94,7 @@ useShadowStyles(`
<template>
<div class="rm-side-backdrop" :class="{ open: isOpen }" @click="emit('close')" />
<aside class="rm-side-drawer" :class="{ open: isOpen }" role="dialog" aria-label="Research map controls">
<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>

View file

@ -31,5 +31,22 @@
"filters": "عوامل التصفية",
"gospel_resources": "موارد الإنجيل",
"map": "الخريطة",
"search_placeholder": "ابحث عن الشعوب والأماكن واللغات والأديان…"
"search_placeholder": "ابحث عن الشعوب والأماكن واللغات والأديان…",
"any": "الكل",
"active_count": "{n} نشط",
"prayer_status": "حالة الصلاة",
"map_controls": "أدوات التحكم بالخريطة",
"close": "إغلاق",
"clear": "مسح",
"dashboard_title": "لوحة البحث الشاملة",
"align_dashboard": "محاذاة اللوحة",
"align_dashboard_tip": "إعادة تخطيط اللوحة إلى المحاذاة الافتراضية",
"selected": "المحدد",
"world": "العالم",
"vertical_legend": "مفتاح عمودي",
"groups_in_scope": "مجموعة ضمن النطاق",
"filter_by": "تصفية حسب",
"remove_filter": "إزالة التصفية",
"groups": "مجموعة",
"expand": "توسيع"
}

View file

@ -31,5 +31,22 @@
"filters": "Filter",
"gospel_resources": "Evangeliumsressourcen",
"map": "Karte",
"search_placeholder": "Volksgruppen, Orte, Sprachen, Religionen suchen…"
"search_placeholder": "Volksgruppen, Orte, Sprachen, Religionen suchen…",
"any": "Alle",
"active_count": "{n} aktiv",
"prayer_status": "Gebetsstatus",
"map_controls": "Kartensteuerung",
"close": "Schließen",
"clear": "Zurücksetzen",
"dashboard_title": "Big-Picture-Forschungsdashboard",
"align_dashboard": "Layout ausrichten",
"align_dashboard_tip": "Das Dashboard-Layout auf die Standardausrichtung zurücksetzen",
"selected": "Ausgewählt",
"world": "Welt",
"vertical_legend": "Vertikale Legende",
"groups_in_scope": "Volksgruppen im Bereich",
"filter_by": "Filtern nach",
"remove_filter": "Filter entfernen",
"groups": "Volksgruppen",
"expand": "Aufklappen"
}

View file

@ -31,5 +31,22 @@
"filters": "Filters",
"gospel_resources": "Gospel Resources",
"map": "Map",
"search_placeholder": "Search people groups, place, language, religion…"
"search_placeholder": "Search people groups, place, language, religion…",
"any": "Any",
"active_count": "{n} active",
"prayer_status": "Prayer Status",
"map_controls": "Research map controls",
"close": "Close",
"clear": "Clear",
"dashboard_title": "Big Picture Research Dashboard",
"align_dashboard": "Align Dashboard",
"align_dashboard_tip": "Reset the dashboard layout to its default alignment",
"selected": "Selected",
"world": "World",
"vertical_legend": "Vertical Legend",
"groups_in_scope": "groups in scope",
"filter_by": "Filter by",
"remove_filter": "Remove filter",
"groups": "groups",
"expand": "Expand"
}

View file

@ -31,5 +31,22 @@
"filters": "Filtros",
"gospel_resources": "Recursos del Evangelio",
"map": "Mapa",
"search_placeholder": "Buscar pueblos, lugares, idiomas, religiones…"
"search_placeholder": "Buscar pueblos, lugares, idiomas, religiones…",
"any": "Cualquiera",
"active_count": "{n} activos",
"prayer_status": "Estado de oración",
"map_controls": "Controles del mapa",
"close": "Cerrar",
"clear": "Borrar",
"dashboard_title": "Panel de investigación general",
"align_dashboard": "Alinear panel",
"align_dashboard_tip": "Restablecer la disposición del panel a su alineación predeterminada",
"selected": "Seleccionado",
"world": "Mundo",
"vertical_legend": "Leyenda vertical",
"groups_in_scope": "pueblos en el ámbito",
"filter_by": "Filtrar por",
"remove_filter": "Quitar filtro",
"groups": "pueblos",
"expand": "Expandir"
}

View file

@ -31,5 +31,22 @@
"filters": "Filtres",
"gospel_resources": "Ressources de l'Évangile",
"map": "Carte",
"search_placeholder": "Rechercher peuples, lieux, langues, religions…"
"search_placeholder": "Rechercher peuples, lieux, langues, religions…",
"any": "Tous",
"active_count": "{n} actifs",
"prayer_status": "État de prière",
"map_controls": "Commandes de la carte",
"close": "Fermer",
"clear": "Effacer",
"dashboard_title": "Tableau de bord de recherche global",
"align_dashboard": "Aligner le tableau",
"align_dashboard_tip": "Rétablir la disposition par défaut du tableau de bord",
"selected": "Sélectionné",
"world": "Monde",
"vertical_legend": "Légende verticale",
"groups_in_scope": "peuples dans le périmètre",
"filter_by": "Filtrer par",
"remove_filter": "Retirer le filtre",
"groups": "peuples",
"expand": "Développer"
}

View file

@ -31,5 +31,22 @@
"filters": "फ़िल्टर",
"gospel_resources": "सुसमाचार संसाधन",
"map": "नक्शा",
"search_placeholder": "जनसमूह, स्थान, भाषा, धर्म खोजें…"
"search_placeholder": "जनसमूह, स्थान, भाषा, धर्म खोजें…",
"any": "कोई भी",
"active_count": "{n} सक्रिय",
"prayer_status": "प्रार्थना स्थिति",
"map_controls": "मानचित्र नियंत्रण",
"close": "बंद करें",
"clear": "साफ़ करें",
"dashboard_title": "बिग पिक्चर शोध डैशबोर्ड",
"align_dashboard": "डैशबोर्ड संरेखित करें",
"align_dashboard_tip": "डैशबोर्ड लेआउट को डिफ़ॉल्ट संरेखण पर लौटाएँ",
"selected": "चयनित",
"world": "विश्व",
"vertical_legend": "लंबवत लेजेंड",
"groups_in_scope": "दायरे में जनसमूह",
"filter_by": "इससे फ़िल्टर करें",
"remove_filter": "फ़िल्टर हटाएँ",
"groups": "जनसमूह",
"expand": "विस्तार करें"
}

View file

@ -31,5 +31,22 @@
"filters": "Filtri",
"gospel_resources": "Risorse del Vangelo",
"map": "Mappa",
"search_placeholder": "Cerca popoli, luoghi, lingue, religioni…"
"search_placeholder": "Cerca popoli, luoghi, lingue, religioni…",
"any": "Tutti",
"active_count": "{n} attivi",
"prayer_status": "Stato di preghiera",
"map_controls": "Controlli della mappa",
"close": "Chiudi",
"clear": "Cancella",
"dashboard_title": "Cruscotto di ricerca generale",
"align_dashboard": "Allinea cruscotto",
"align_dashboard_tip": "Ripristina la disposizione predefinita del cruscotto",
"selected": "Selezionato",
"world": "Mondo",
"vertical_legend": "Legenda verticale",
"groups_in_scope": "popoli nell’ambito",
"filter_by": "Filtra per",
"remove_filter": "Rimuovi filtro",
"groups": "popoli",
"expand": "Espandi"
}

View file

@ -31,5 +31,22 @@
"filters": "Filtros",
"gospel_resources": "Recursos do Evangelho",
"map": "Mapa",
"search_placeholder": "Pesquisar povos, lugares, idiomas, religiões…"
"search_placeholder": "Pesquisar povos, lugares, idiomas, religiões…",
"any": "Qualquer",
"active_count": "{n} ativos",
"prayer_status": "Estado de oração",
"map_controls": "Controlos do mapa",
"close": "Fechar",
"clear": "Limpar",
"dashboard_title": "Painel de pesquisa geral",
"align_dashboard": "Alinhar painel",
"align_dashboard_tip": "Repor a disposição do painel para o alinhamento predefinido",
"selected": "Selecionado",
"world": "Mundo",
"vertical_legend": "Legenda vertical",
"groups_in_scope": "povos no âmbito",
"filter_by": "Filtrar por",
"remove_filter": "Remover filtro",
"groups": "povos",
"expand": "Expandir"
}

View file

@ -31,5 +31,22 @@
"filters": "Filtre",
"gospel_resources": "Resurse ale Evangheliei",
"map": "Hartă",
"search_placeholder": "Caută popoare, locuri, limbi, religii…"
"search_placeholder": "Caută popoare, locuri, limbi, religii…",
"any": "Oricare",
"active_count": "{n} active",
"prayer_status": "Stare de rugăciune",
"map_controls": "Comenzile hărții",
"close": "Închide",
"clear": "Șterge",
"dashboard_title": "Tablou de bord de cercetare general",
"align_dashboard": "Aliniază tabloul",
"align_dashboard_tip": "Readu aranjarea tabloului la alinierea implicită",
"selected": "Selectat",
"world": "Lume",
"vertical_legend": "Legendă verticală",
"groups_in_scope": "popoare în domeniu",
"filter_by": "Filtrează după",
"remove_filter": "Elimină filtrul",
"groups": "popoare",
"expand": "Extinde"
}

View file

@ -31,5 +31,22 @@
"filters": "Фильтры",
"gospel_resources": "Евангельские ресурсы",
"map": "Карта",
"search_placeholder": "Поиск народов, мест, языков, религий…"
"search_placeholder": "Поиск народов, мест, языков, религий…",
"any": "Любой",
"active_count": "{n} активно",
"prayer_status": "Статус молитвы",
"map_controls": "Элементы управления картой",
"close": "Закрыть",
"clear": "Очистить",
"dashboard_title": "Обзорная исследовательская панель",
"align_dashboard": "Выровнять панель",
"align_dashboard_tip": "Вернуть расположение панели к виду по умолчанию",
"selected": "Выбрано",
"world": "Мир",
"vertical_legend": "Вертикальная легенда",
"groups_in_scope": "народов в выборке",
"filter_by": "Фильтровать по",
"remove_filter": "Убрать фильтр",
"groups": "народов",
"expand": "Развернуть"
}

View file

@ -31,5 +31,22 @@
"filters": "筛选",
"gospel_resources": "福音资源",
"map": "地图",
"search_placeholder": "搜索民族、地点、语言、宗教…"
"search_placeholder": "搜索民族、地点、语言、宗教…",
"any": "全部",
"active_count": "{n} 项启用",
"prayer_status": "代祷状态",
"map_controls": "地图控件",
"close": "关闭",
"clear": "清除",
"dashboard_title": "全局研究仪表板",
"align_dashboard": "对齐仪表板",
"align_dashboard_tip": "将仪表板布局恢复为默认对齐",
"selected": "已选择",
"world": "世界",
"vertical_legend": "垂直图例",
"groups_in_scope": "个民族在范围内",
"filter_by": "筛选",
"remove_filter": "移除筛选",
"groups": "个民族",
"expand": "展开"
}

View file

@ -26,10 +26,20 @@ import { readdirSync, existsSync, readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { firefox } from 'playwright';
import { requireThisTree } from '../../../internal/_serves-this-tree.mjs'
import { resolve as _resolvePath, dirname as _dirnamePath } from 'node:path'
const __dirname = dirname(fileURLToPath(import.meta.url));
const DIR = process.env.POSTER_DIR || join(__dirname, 'out', 'posters');
const PREFIX = process.argv[2] || '';
const ROOT = _resolvePath(_dirnamePath(_fileURLToPath(import.meta.url)), '../../..')
// ★ MEASURE THIS BUILD, OR MEASURE NOTHING. Several worktrees run on one machine and a default port
// belongs to whichever server started first — measured 2026-09-24 on :4173, where browser gates
// reported confidently about a build nobody here had touched. 75 (EX_TEMPFAIL), not 1: the wrong
// tree is a precondition, not a product defect, and the wave runner reports 75 as ⊘ rather than ✗.
// A file:// target passes straight through — there is no server there to be wrong about.
await requireThisTree(PREFIX, ROOT, 'POSTERS')
if (!existsSync(DIR)) { console.error('no out/posters — run the generator first'); process.exit(1); }
const files = readdirSync(DIR).filter((f) => f.endsWith('.html') && f.startsWith(PREFIX));

View file

@ -3,6 +3,9 @@
// running app can load a table — a renamed field or a moved file would pass both
// and leave an empty list view.
import { firefox } from 'playwright';
import { requireThisTree } from '../../../internal/_serves-this-tree.mjs'
import { resolve as _resolvePath, dirname as _dirnamePath } from 'node:path'
import { fileURLToPath as _fileURLToPath } from 'node:url'
// MUST be served over HTTP from THIS repo's public/. Two traps, both hit for real:
// * file:// does not mount the bundles at all — zero custom elements, no error.
@ -14,6 +17,14 @@ import { firefox } from 'playwright';
// other browser gate uses. It was 8917 — a port nothing in this repo has ever bound, so the guard
// could only ever fail unless someone happened to know the number. Override with APP_BASE.
const BASE = process.env.APP_BASE || 'http://127.0.0.1:4173';
const ROOT = _resolvePath(_dirnamePath(_fileURLToPath(import.meta.url)), '../../..')
// ★ MEASURE THIS BUILD, OR MEASURE NOTHING. Several worktrees run on one machine and a default port
// belongs to whichever server started first — measured 2026-09-24 on :4173, where browser gates
// reported confidently about a build nobody here had touched. 75 (EX_TEMPFAIL), not 1: the wrong
// tree is a precondition, not a product defect, and the wave runner reports 75 as ⊘ rather than ✗.
// A file:// target passes straight through — there is no server there to be wrong about.
await requireThisTree(BASE, ROOT, 'APP-TABLES')
// ★ REWRITTEN 2026-09-23: these are LEAF PAGES from the manifest, not hash fragments on a shell.
//
// The previous list was ['key-city-posters', 'cities-with-internet', 'gospel-resources'] navigated

View file

@ -20,6 +20,16 @@ import StackLayout from '@map/layouts/StackLayout.vue'
import ResearchDashboard from '../research-dashboard/research-dashboard.vue'
import PeopleGroupsGrid from '../people-groups-grid/people-groups-grid.vue'
// ★ THE HOST'S INLINE STYLE MUST NOT LAND ON OUR ROOT.
// This SFC is mounted AS a custom element, so a style attribute the HOST page puts on the tag falls
// through onto this component's root element. MEASURED 2026-09-25 with a host style of
// "display:flex; position:relative; height:100%": that exact string appeared verbatim on the inner
// root div of this component — the gallery sets one on every tab, and on the Prayer Walk Planner
// the same fallthrough collapsed the plugin to 76px. The element's own :host rules are the contract
// for how it sizes itself; a host styling the TAG is styling the box, not our internals.
defineOptions({ inheritAttrs: false })
// ── THE DASHBOARD → GRID LINK ────────────────────────────────────────────────────────────
// THE BUG THIS FIXES (Driver-reported; measured 2026-09-22). Selecting anything in the
// dashboard above did not filter the grid below. Measured: the dashboard reacted every time

View file

@ -56,6 +56,16 @@ import { RELIGION_FAMILIES } from '@map/colors/religion.js'
import { canonicalFamilyName } from '@map/colors/language-family.js'
import langFamilyByIso from '@map/data/langFamilyByIso.json'
// ★ THE HOST'S INLINE STYLE MUST NOT LAND ON OUR ROOT.
// This SFC is mounted AS a custom element, so a style attribute the HOST page puts on the tag falls
// through onto this component's root element. MEASURED 2026-09-25 with a host style of
// "display:flex; position:relative; height:100%": that exact string appeared verbatim on the inner
// root div of this component — the gallery sets one on every tab, and on the Prayer Walk Planner
// the same fallthrough collapsed the plugin to 76px. The element's own :host rules are the contract
// for how it sizes itself; a host styling the TAG is styling the box, not our internals.
defineOptions({ inheritAttrs: false })
const props = defineProps({
// ── injected standalone deps (replace Nuxt useRuntimeConfig / useI18n / useLocalePath) ──
profileConfig: { type: String, default: '' },

View file

@ -43,7 +43,7 @@ export default {
// element on a partner site, so the title is what a visitor reads there — it has to name the
// product, not just the page. "Big Picture" is also the cap-4 composite's name and tab-1 of the
// cap-5 SPA, so one term now runs consistently from the tab through to an embedded partner view.
title: 'Big Picture Research Dashboard',
get title() { return tStatic('dashboard.dashboard_title') || 'Big Picture Research Dashboard' },
element: 'doxa-research-dashboard',
// ── data source ── (consumed by useDashboardData; the arg is currently advisory —

View file

@ -1,4 +1,6 @@
<script setup>
import { tStatic } from '@map/i18n/index.js'
const L = (key, en) => tStatic('dashboard.' + key) || en
/**
* Breadcrumb — RDASH phase 8 delighter: drill-down breadcrumb (World ▸ Asia ▸ Hinduism …).
* Every filter pushes a crumb; click a crumb to pop back to that altitude (legible + reversible
@ -42,7 +44,7 @@ useShadowStyles(`
<template>
<nav class="rd-breadcrumb" data-breadcrumb @click="onClick" aria-label="Filter breadcrumb">
<span class="rd-crumb root" data-crumb="__root__">World</span>
<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>
<span class="rd-crumb" :class="{ cur: i === crumbs.length - 1 }" data-crumb-item :data-crumb="c.k">{{ c.v }}</span>

View file

@ -1,4 +1,6 @@
<script setup>
import { tStatic } from '@map/i18n/index.js'
const L = (key, en) => tStatic('dashboard.' + key) || en
/**
* DashboardFacetRail (was Sidebar.vue) — RDASH redesign phase 2: the floating @map SemanticTreeLegend is DROPPED.
*
@ -697,8 +699,8 @@ useShadowStyles(`
user-facing label (the component/docs still describe the semantic-tree MODEL).
The four stacked trees below it are People · Place · Language · Religion, in that
order — the four axes a researcher navigates to find who has gospel resources. -->
<div class="fr-title">Vertical Legend</div>
<div class="fr-scope" data-scope-count><b>{{ scopeCount.toLocaleString('en-US') }}</b> groups in scope</div>
<div class="fr-title">{{ L('vertical_legend', 'Vertical Legend') }}</div>
<div class="fr-scope" data-scope-count><b>{{ scopeCount.toLocaleString('en-US') }}</b> {{ L('groups_in_scope', 'groups in scope') }}</div>
</div>
<div class="fr-body" ref="railEl" @click="onRowClick" @keydown="onRowKey">
@ -714,7 +716,7 @@ useShadowStyles(`
:tabindex="(r.other || r.zero) ? null : 0"
:role="(r.other || r.zero) ? null : 'button'"
:aria-pressed="(r.other || r.zero) ? null : (r.active ? 'true' : 'false')"
:aria-label="(r.other || r.zero) ? null : ((r.active ? 'Remove filter ' : 'Filter by ') + r.label + ', ' + r.count.toLocaleString('en-US') + ' groups' + (r.dashboardOnly ? '. Updates the charts on this dashboard only; it does not filter the list below.' : ''))"
:aria-label="(r.other || r.zero) ? null : ((r.active ? L('remove_filter', 'Remove filter') : L('filter_by', 'Filter by')) + ' ' + r.label + ', ' + r.count.toLocaleString('en-US') + ' ' + L('groups', 'groups') + (r.dashboardOnly ? '. Updates the charts on this dashboard only; it does not filter the list below.' : ''))"
:title="r.dashboardOnly ? 'Updates this dashboard only — the list below does not filter on ' + r.label : null">
<!-- tree trunks: one span per ancestor level, same glyph vocabulary as the
research-map's SemanticTreeLegend so the hierarchy is DRAWN, not just padded. -->

View file

@ -1,4 +1,6 @@
<script setup>
import { tStatic } from '@map/i18n/index.js'
const L = (key, en) => tStatic('dashboard.' + key) || en
/**
* DashboardTopBar — RDASH P4 Command Bar (topbar grid region, 52px).
* One cohesive header surface holding, on ONE row:
@ -308,9 +310,9 @@ useShadowStyles(`
</div>
</div>
<span class="rd-align" role="button" tabindex="0" data-align-btn
title="Reset the dashboard layout to its default alignment"
:title="L('align_dashboard_tip', 'Reset the dashboard layout to its default alignment')"
@click="onAlignLayout" @keydown.enter.prevent="onAlignLayout" @keydown.space.prevent="onAlignLayout">
⤢ Align Dashboard
⤢ {{ L('align_dashboard', 'Align Dashboard') }}
</span>
<!-- CSV export MOVED to the people-groups table header (DashboardDataTable), below the map —
card BUILD-CSV-EXPORT-MOVE-TO-TABLE-HEADER-ALL-FIELDS. It exports THAT table, so it now

View file

@ -60,6 +60,16 @@ import StackLayout from '@map/layouts/StackLayout.vue'
import { resolveEmbedBase } from '@map/utils/embedBase.js'
import { publishMapToken } from '@map/composables/useSharedMapToken.js'
// ★ THE HOST'S INLINE STYLE MUST NOT LAND ON OUR ROOT.
// This SFC is mounted AS a custom element, so a style attribute the HOST page puts on the tag falls
// through onto this component's root element. MEASURED 2026-09-25 with a host style of
// "display:flex; position:relative; height:100%": that exact string appeared verbatim on the inner
// root div of this component — the gallery sets one on every tab, and on the Prayer Walk Planner
// the same fallthrough collapsed the plugin to 76px. The element's own :host rules are the contract
// for how it sizes itself; a host styling the TAG is styling the box, not our internals.
defineOptions({ inheritAttrs: false })
// ★ THE HOST'S OWN profile-config, WHICH THIS COMPOSITE USED TO THROW AWAY.
// It declared no props at all, so a partner's <research-map-plus-grid profile-config='{"tk":"..."}'>
// had its token dropped on the floor. On our own generated leaf that was invisible: the leaf page

View file

@ -17,6 +17,16 @@ import { computed } from 'vue'
import StackLayout from '@map/layouts/StackLayout.vue'
import { publishMapToken } from '@map/composables/useSharedMapToken.js'
// ★ THE HOST'S INLINE STYLE MUST NOT LAND ON OUR ROOT.
// This SFC is mounted AS a custom element, so a style attribute the HOST page puts on the tag falls
// through onto this component's root element. MEASURED 2026-09-25 with a host style of
// "display:flex; position:relative; height:100%": that exact string appeared verbatim on the inner
// root div of this component — the gallery sets one on every tab, and on the Prayer Walk Planner
// the same fallthrough collapsed the plugin to 76px. The element's own :host rules are the contract
// for how it sizes itself; a host styling the TAG is styling the box, not our internals.
defineOptions({ inheritAttrs: false })
// The two elements to stack. `src` is TREE-RELATIVE at build; the leaf pages resolve it against the
// bundle tree root. Both elements ship their own bundles in the same catalog.
// ── WHERE A SIBLING BUNDLE LIVES DEPENDS ON WHICH TREE IS SERVING ────────────────────────────

File diff suppressed because one or more lines are too long

View file

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

View file

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

View file

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

File diff suppressed because one or more lines are too long

View file

@ -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-yXe7qKTXdATjFRqUkMsxgt4ScSem7bPiIWsqpsj8PlYDO2VhZf+qtE2htlgtAsz4" crossorigin="anonymous"></script>
<script src="../../dashboard-plus-grid.js" integrity="sha384-YxUezA4o6AsKCrt1Kmdq05Exrz4a++K2Iz8YR4CJPXgGtM444ojTcjA3OrBLPprM" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

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

File diff suppressed because one or more lines are too long

View file

@ -39,7 +39,7 @@
"bundle": "big-picture",
"scriptUrl": "./big-picture/big-picture.js",
"output": "doxa-maps/big-picture/big-picture.js",
"integrity": "sha384-ISt0kwPfFob7KBzHpcdJIVjv652N3alsxTyOfN13SGrBt0OKHD5NJQYQFt3jnYWQ",
"integrity": "sha384-MIotyiMkAcAJizhxGzzi0k3Vjd4souqd8URA5CoGwZdBTmdFeXLxdsOQY0A/7OKf",
"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-ISt0kwPfFob7KBzHpcdJIVjv652N3alsxTyOfN13SGrBt0OKHD5NJQYQFt3jnYWQ\" 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-MIotyiMkAcAJizhxGzzi0k3Vjd4souqd8URA5CoGwZdBTmdFeXLxdsOQY0A/7OKf\" 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": "doxa-maps/dashboard-plus-grid/dashboard-plus-grid.js",
"integrity": "sha384-yXe7qKTXdATjFRqUkMsxgt4ScSem7bPiIWsqpsj8PlYDO2VhZf+qtE2htlgtAsz4",
"integrity": "sha384-YxUezA4o6AsKCrt1Kmdq05Exrz4a++K2Iz8YR4CJPXgGtM444ojTcjA3OrBLPprM",
"elements": [
"dashboard-plus-grid"
],
@ -235,7 +235,7 @@
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
"embed": {
"iframe": "<iframe src=\"./dashboard-plus-grid/dashboard-plus-grid/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-yXe7qKTXdATjFRqUkMsxgt4ScSem7bPiIWsqpsj8PlYDO2VhZf+qtE2htlgtAsz4\" crossorigin=\"anonymous\"></script>\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-YxUezA4o6AsKCrt1Kmdq05Exrz4a++K2Iz8YR4CJPXgGtM444ojTcjA3OrBLPprM\" 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": [
{
@ -721,7 +721,7 @@
"bundle": "people-groups-grid",
"scriptUrl": "./people-groups-grid/people-groups-grid.js",
"output": "doxa-maps/people-groups-grid/people-groups-grid.js",
"integrity": "sha384-X3qjp89Dxlr8VW4cX0it+SuREyzXCeVDAba1YrKMyk7XWmlkFSpjLYNa2g6R5q4p",
"integrity": "sha384-SOgJZ7f+syLHYLSe0ZS99wYotonfFOt3imsoeiw1qpdqNPpdBOl/1mm0Kp+YNTFl",
"elements": [
"people-groups-grid"
],
@ -737,7 +737,7 @@
"scriptUrl": "./people-groups-grid/people-groups-grid.js",
"embed": {
"iframe": "<iframe src=\"./people-groups-grid/people-groups-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=\"./people-groups-grid/people-groups-grid.js\" integrity=\"sha384-X3qjp89Dxlr8VW4cX0it+SuREyzXCeVDAba1YrKMyk7XWmlkFSpjLYNa2g6R5q4p\" crossorigin=\"anonymous\"></script>\n<people-groups-grid profile-config='{\"profile\":\"people-groups-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></people-groups-grid>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./people-groups-grid/people-groups-grid.js\" integrity=\"sha384-SOgJZ7f+syLHYLSe0ZS99wYotonfFOt3imsoeiw1qpdqNPpdBOl/1mm0Kp+YNTFl\" crossorigin=\"anonymous\"></script>\n<people-groups-grid profile-config='{\"profile\":\"people-groups-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></people-groups-grid>"
},
"instances": [
{
@ -945,7 +945,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-QF8HNGDjuEGTpVgkTEayOohmab9QdwnO5jLCoEy9P8nr6Zp7JWKrMC5mvDPBOXhB",
"integrity": "sha384-hETnSGVenHXQXaI+EUClxIoaB0xyA9jHa3AaZE6grq4UHxTuX0QNZj93mAUi3H7b",
"elements": [
"research-map-plus-grid"
],
@ -965,7 +965,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-QF8HNGDjuEGTpVgkTEayOohmab9QdwnO5jLCoEy9P8nr6Zp7JWKrMC5mvDPBOXhB\" 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-hETnSGVenHXQXaI+EUClxIoaB0xyA9jHa3AaZE6grq4UHxTuX0QNZj93mAUi3H7b\" 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": [
{
@ -989,7 +989,7 @@
"bundle": "stack-demo",
"scriptUrl": "./stack-demo/stack-demo.js",
"output": "doxa-maps/stack-demo/stack-demo.js",
"integrity": "sha384-EI3V6JX9ws4fGxKBzMOgwhG5de8MvL6va3zqmB2gTXecd/m0mxNq8eUht/SGzH1B",
"integrity": "sha384-3Rjk4pZDcTABDfBIAbT2tu+D6J9/U3jx3UJDkiPynH+oeiwzCGFotSX7hbhdT48G",
"elements": [
"stack-demo"
],
@ -1009,7 +1009,7 @@
"scriptUrl": "./stack-demo/stack-demo.js",
"embed": {
"iframe": "<iframe src=\"./stack-demo/stack-demo/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./stack-demo/stack-demo.js\" integrity=\"sha384-EI3V6JX9ws4fGxKBzMOgwhG5de8MvL6va3zqmB2gTXecd/m0mxNq8eUht/SGzH1B\" crossorigin=\"anonymous\"></script>\n<stack-demo profile-config='{\"profile\":\"stack-demo\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></stack-demo>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./stack-demo/stack-demo.js\" integrity=\"sha384-3Rjk4pZDcTABDfBIAbT2tu+D6J9/U3jx3UJDkiPynH+oeiwzCGFotSX7hbhdT48G\" crossorigin=\"anonymous\"></script>\n<stack-demo profile-config='{\"profile\":\"stack-demo\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></stack-demo>"
},
"instances": [
{

File diff suppressed because one or more lines are too long

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <people-groups-grid> custom element. -->
<script src="../../people-groups-grid.js" integrity="sha384-X3qjp89Dxlr8VW4cX0it+SuREyzXCeVDAba1YrKMyk7XWmlkFSpjLYNa2g6R5q4p" crossorigin="anonymous"></script>
<script src="../../people-groups-grid.js" integrity="sha384-SOgJZ7f+syLHYLSe0ZS99wYotonfFOt3imsoeiw1qpdqNPpdBOl/1mm0Kp+YNTFl" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <people-groups-grid> custom element. -->
<script src="../people-groups-grid.js" integrity="sha384-X3qjp89Dxlr8VW4cX0it+SuREyzXCeVDAba1YrKMyk7XWmlkFSpjLYNa2g6R5q4p" crossorigin="anonymous"></script>
<script src="../people-groups-grid.js" integrity="sha384-SOgJZ7f+syLHYLSe0ZS99wYotonfFOt3imsoeiw1qpdqNPpdBOl/1mm0Kp+YNTFl" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <people-groups-grid> custom element. -->
<script src="../../people-groups-grid.js" integrity="sha384-X3qjp89Dxlr8VW4cX0it+SuREyzXCeVDAba1YrKMyk7XWmlkFSpjLYNa2g6R5q4p" crossorigin="anonymous"></script>
<script src="../../people-groups-grid.js" integrity="sha384-SOgJZ7f+syLHYLSe0ZS99wYotonfFOt3imsoeiw1qpdqNPpdBOl/1mm0Kp+YNTFl" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

View file

@ -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-QF8HNGDjuEGTpVgkTEayOohmab9QdwnO5jLCoEy9P8nr6Zp7JWKrMC5mvDPBOXhB" crossorigin="anonymous"></script>
<script src="../../research-map-plus-grid.js" integrity="sha384-hETnSGVenHXQXaI+EUClxIoaB0xyA9jHa3AaZE6grq4UHxTuX0QNZj93mAUi3H7b" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

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

View file

@ -44,4 +44,4 @@
.stl ::-webkit-scrollbar-thumb { background:#c4c8c0; border-radius:8px; }
.stl ::-webkit-scrollbar-thumb:hover { background:#9aa197; }
.stl ::-webkit-scrollbar-corner { background:transparent; }
`,ql=ei({name:"StackLayout",props:{sections:{type:Array,default:()=>[]},title:{type:String,default:""},maxSectionHeight:{type:String,default:""},minSectionHeight:{type:String,default:""}},setup(){$l(zl,"stack-layout")},data(){return{_hosts:{},_mounted:{}}},mounted(){for(const t of this.sections||[])t.element&&this.mountSection(t)},methods:{registerHost(t,e){e&&(this._hosts[t]=e)},sectionStyle(t){const e={},s=t.maxHeight||this.maxSectionHeight,n=t.minHeight||this.minSectionHeight,i=!!(s&&n&&s===n);return s&&(e.maxHeight=s,i||(e.overflow="auto")),n&&(e.minHeight=n),Object.keys(e).length?e:null},hasDefiniteHeight(t){const e=t.maxHeight||this.maxSectionHeight,s=t.minHeight||this.minSectionHeight;return!!(e&&s&&e===s)},mountSection(t){if(this._mounted[t.key])return;this._mounted[t.key]=!0;const e=this._hosts[t.key];e&&Bl(t.src).then(()=>Wl(t.element)).then(()=>{if(!customElements.get(t.element))return;const s=document.createElement(t.element),n=t.attrs||{};for(const i in n){const r=n[i];try{s[i]=r}catch{}try{s.setAttribute(i,r==null?"":String(r))}catch{}}e.innerHTML="",e.appendChild(s)}).catch(s=>{const n=s&&s.message||String(s);console.error('[StackLayout] section "'+t.key+'" failed to mount <'+t.element+">"+(t.src?" from "+t.src:"")+": "+n);try{e.innerHTML="";const i=document.createElement("div");i.setAttribute("role","status"),i.style.cssText="box-sizing:border-box;max-width:100%;padding:16px;font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;color:#6d766e;background:#fff;border:1px solid #d1d4cd;border-radius:8px;margin:12px 0;overflow-wrap:anywhere;word-break:break-word",i.textContent="Could not load <"+t.element+">"+(t.src?" from "+t.src:"")+" — "+n,e.appendChild(i)}catch{}})}}}),Jl={class:"stl"},Gl={key:0,class:"stl-top"},Yl={class:"stl-brand"},Xl={key:0,class:"stl-title"},Zl={class:"stl-meta"},Ql={class:"stl-stack"},tc={key:0,class:"stl-sec-head"},ec={class:"stl-sec-title"},sc={key:0,class:"stl-sec-sub"},nc={key:2,class:"stl-slot"},ic={class:"stl-tail"};function rc(t,e,s,n,i,r){return ut(),kt("div",Jl,[t.$slots.brand||t.$slots.meta||t.title?(ut(),kt("header",Gl,[Xt("span",Yl,[is(t.$slots,"brand")]),t.title?(ut(),kt("b",Xl,Ke(t.title),1)):us("",!0),Xt("span",Zl,[is(t.$slots,"meta")])])):us("",!0),Xt("div",Ql,[(ut(!0),kt(ct,null,So(t.sections,o=>(ut(),kt("section",{key:o.key,class:Ve(["stl-sec",{"stl-sec-fill":t.hasDefiniteHeight(o)}]),style:Le(t.sectionStyle(o))},[o.title?(ut(),kt("div",tc,[Xt("b",ec,Ke(o.title),1),o.sub?(ut(),kt("span",sc,Ke(o.sub),1)):us("",!0)])):us("",!0),o.element?(ut(),kt("div",{key:1,class:"stl-host",ref_for:!0,ref:l=>t.registerHost(o.key,l)},null,512)):(ut(),kt("div",nc,[is(t.$slots,"section-"+o.key)]))],6))),128)),Xt("div",ic,[is(t.$slots,"default")])])])}const oc=ir(ql,[["render",rc],["styles",[Ul]]]),rr="__doxaMapToken",lc="doxa:map-token",or=()=>{if(typeof window>"u")return"";const t=window[rr];return typeof t=="string"?t:""};function cc(t){if(typeof window>"u")return"";const e=typeof t=="string"?t.trim():"";if(!e||e===or())return or();window[rr]=e;try{window.dispatchEvent(new CustomEvent(lc,{detail:e}))}catch{}return e}const fc=Fl(ir({__name:"stack-demo",props:{profileConfig:{type:[String,Object],default:null}},setup(t){const e=(l,c)=>`../../${l}/${c}.js`,s=t,n=Ee(()=>{const l=s.profileConfig;if(!l)return{};if(typeof l=="object")return l;try{return JSON.parse(l)}catch{return{}}}),i=Ee(()=>{var c;const l=(c=n.value)==null?void 0:c.tk;return typeof l=="string"&&l?l:""});i.value&&cc(i.value);const r=Ee(()=>{var c;const l=(c=n.value)==null?void 0:c.provider;return l==="maplibre"||l==="mapbox"?l:""}),o=Ee(()=>[{key:"dashboard",title:"Research Dashboard",sub:"facets · map · charts · table (live)",element:"research-dashboard-map",src:e("research-dashboard","research-dashboard"),attrs:{"profile-config":JSON.stringify({profile:"research-dashboard",dataSource:"pray-tools",instanceId:"stack-demo-research-dashboard",...i.value?{tk:i.value}:{},...r.value?{provider:r.value}:{},assetsBase:"../../assets"})}},{key:"grid",title:"People Groups",sub:"the full searchable list (live)",element:"people-groups-grid",src:e("people-groups-grid","people-groups-grid")}]);return(l,c)=>(ut(),cs(oc,{title:"Stacked view",sections:o.value},{meta:Xn(()=>[...c[0]||(c[0]=[ji("scroll ↓",-1)])]),_:1},8,["sections"]))}},[["styles",[":host{display:block;width:100%}"]]]));typeof customElements<"u"&&(customElements.get("stack-demo")||customElements.define("stack-demo",fc))})();
`,ql=ei({name:"StackLayout",props:{sections:{type:Array,default:()=>[]},title:{type:String,default:""},maxSectionHeight:{type:String,default:""},minSectionHeight:{type:String,default:""}},setup(){$l(zl,"stack-layout")},data(){return{_hosts:{},_mounted:{}}},mounted(){for(const t of this.sections||[])t.element&&this.mountSection(t)},methods:{registerHost(t,e){e&&(this._hosts[t]=e)},sectionStyle(t){const e={},s=t.maxHeight||this.maxSectionHeight,n=t.minHeight||this.minSectionHeight,i=!!(s&&n&&s===n);return s&&(e.maxHeight=s,i||(e.overflow="auto")),n&&(e.minHeight=n),Object.keys(e).length?e:null},hasDefiniteHeight(t){const e=t.maxHeight||this.maxSectionHeight,s=t.minHeight||this.minSectionHeight;return!!(e&&s&&e===s)},mountSection(t){if(this._mounted[t.key])return;this._mounted[t.key]=!0;const e=this._hosts[t.key];e&&Bl(t.src).then(()=>Wl(t.element)).then(()=>{if(!customElements.get(t.element))return;const s=document.createElement(t.element),n=t.attrs||{};for(const i in n){const r=n[i];try{s[i]=r}catch{}try{s.setAttribute(i,r==null?"":String(r))}catch{}}e.innerHTML="",e.appendChild(s)}).catch(s=>{const n=s&&s.message||String(s);console.error('[StackLayout] section "'+t.key+'" failed to mount <'+t.element+">"+(t.src?" from "+t.src:"")+": "+n);try{e.innerHTML="";const i=document.createElement("div");i.setAttribute("role","status"),i.style.cssText="box-sizing:border-box;max-width:100%;padding:16px;font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;color:#6d766e;background:#fff;border:1px solid #d1d4cd;border-radius:8px;margin:12px 0;overflow-wrap:anywhere;word-break:break-word",i.textContent="Could not load <"+t.element+">"+(t.src?" from "+t.src:"")+" — "+n,e.appendChild(i)}catch{}})}}}),Jl={class:"stl"},Gl={key:0,class:"stl-top"},Yl={class:"stl-brand"},Xl={key:0,class:"stl-title"},Zl={class:"stl-meta"},Ql={class:"stl-stack"},tc={key:0,class:"stl-sec-head"},ec={class:"stl-sec-title"},sc={key:0,class:"stl-sec-sub"},nc={key:2,class:"stl-slot"},ic={class:"stl-tail"};function rc(t,e,s,n,i,r){return ut(),kt("div",Jl,[t.$slots.brand||t.$slots.meta||t.title?(ut(),kt("header",Gl,[Xt("span",Yl,[is(t.$slots,"brand")]),t.title?(ut(),kt("b",Xl,Ke(t.title),1)):us("",!0),Xt("span",Zl,[is(t.$slots,"meta")])])):us("",!0),Xt("div",Ql,[(ut(!0),kt(ct,null,So(t.sections,o=>(ut(),kt("section",{key:o.key,class:Ve(["stl-sec",{"stl-sec-fill":t.hasDefiniteHeight(o)}]),style:Le(t.sectionStyle(o))},[o.title?(ut(),kt("div",tc,[Xt("b",ec,Ke(o.title),1),o.sub?(ut(),kt("span",sc,Ke(o.sub),1)):us("",!0)])):us("",!0),o.element?(ut(),kt("div",{key:1,class:"stl-host",ref_for:!0,ref:l=>t.registerHost(o.key,l)},null,512)):(ut(),kt("div",nc,[is(t.$slots,"section-"+o.key)]))],6))),128)),Xt("div",ic,[is(t.$slots,"default")])])])}const oc=ir(ql,[["render",rc],["styles",[Ul]]]),rr="__doxaMapToken",lc="doxa:map-token",or=()=>{if(typeof window>"u")return"";const t=window[rr];return typeof t=="string"?t:""};function cc(t){if(typeof window>"u")return"";const e=typeof t=="string"?t.trim():"";if(!e||e===or())return or();window[rr]=e;try{window.dispatchEvent(new CustomEvent(lc,{detail:e}))}catch{}return e}const fc=Fl(ir(Object.assign({inheritAttrs:!1},{__name:"stack-demo",props:{profileConfig:{type:[String,Object],default:null}},setup(t){const e=(l,c)=>`../../${l}/${c}.js`,s=t,n=Ee(()=>{const l=s.profileConfig;if(!l)return{};if(typeof l=="object")return l;try{return JSON.parse(l)}catch{return{}}}),i=Ee(()=>{var c;const l=(c=n.value)==null?void 0:c.tk;return typeof l=="string"&&l?l:""});i.value&&cc(i.value);const r=Ee(()=>{var c;const l=(c=n.value)==null?void 0:c.provider;return l==="maplibre"||l==="mapbox"?l:""}),o=Ee(()=>[{key:"dashboard",title:"Research Dashboard",sub:"facets · map · charts · table (live)",element:"research-dashboard-map",src:e("research-dashboard","research-dashboard"),attrs:{"profile-config":JSON.stringify({profile:"research-dashboard",dataSource:"pray-tools",instanceId:"stack-demo-research-dashboard",...i.value?{tk:i.value}:{},...r.value?{provider:r.value}:{},assetsBase:"../../assets"})}},{key:"grid",title:"People Groups",sub:"the full searchable list (live)",element:"people-groups-grid",src:e("people-groups-grid","people-groups-grid")}]);return(l,c)=>(ut(),cs(oc,{title:"Stacked view",sections:o.value},{meta:Xn(()=>[...c[0]||(c[0]=[ji("scroll ↓",-1)])]),_:1},8,["sections"]))}}),[["styles",[":host{display:block;width:100%}"]]]));typeof customElements<"u"&&(customElements.get("stack-demo")||customElements.define("stack-demo",fc))})();

View file

@ -37,7 +37,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <stack-demo> custom element. -->
<script src="../stack-demo.js" integrity="sha384-EI3V6JX9ws4fGxKBzMOgwhG5de8MvL6va3zqmB2gTXecd/m0mxNq8eUht/SGzH1B" crossorigin="anonymous"></script>
<script src="../stack-demo.js" integrity="sha384-3Rjk4pZDcTABDfBIAbT2tu+D6J9/U3jx3UJDkiPynH+oeiwzCGFotSX7hbhdT48G" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -37,7 +37,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <stack-demo> custom element. -->
<script src="../../stack-demo.js" integrity="sha384-EI3V6JX9ws4fGxKBzMOgwhG5de8MvL6va3zqmB2gTXecd/m0mxNq8eUht/SGzH1B" crossorigin="anonymous"></script>
<script src="../../stack-demo.js" integrity="sha384-3Rjk4pZDcTABDfBIAbT2tu+D6J9/U3jx3UJDkiPynH+oeiwzCGFotSX7hbhdT48G" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order: