doxa-maps/plugin-designs/gospel-resources/gospel-dashboard.vue
Doxa Maps e19697673d
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Doxa Maps — the map bundler, 7 production plugins and the Experimental shelf
2026-09-25 20:07:59 +00:00

98 lines
5.4 KiB
Vue

<script setup>
/**
* gospel-dashboard.vue — Capability-4 composite: the gospel map above its own tables.
*
* @element gospel-resources-map
*
* ★ THE TAG IS THE BUNDLE'S, NOT THE PROFILE'S. This said gospel-resources-dashboard, a tag
* nothing defines: index.js registers exactly one element and every profile is selected
* through its profile-config, which is why all five generated leaves embed
* <gospel-resources-map>. The manifest reads this line, so it published an element name a
* consumer could copy into a page and get nothing at all — invisible in dev, where the leaf
* HTML is what gets loaded, and only findable on a built tree.
* @description The gospel map and its tables as one scrolling element: 12,379 people-group pins with the real Scripture, film and Bible-story links for each group's own language, above every resource with its URL and the 1,613 groups where nothing was found, exportable as CSV.
*
* WHY A COMPOSITE AND NOT A THIRD DATASET. The agent asked for "a gospel resources
* dashboard if possible", and the two halves already existed as separate profiles that a
* reader had to know to visit separately: the map answers "where", the tables answer
* "what exactly, and give me the list". Neither is improved by being rebuilt; they are
* improved by being in one place.
*
* IMPORTED DIRECTLY, like dashboard-plus-grid, not injected at runtime like stack-demo.
* Both children live in THIS bundle, so composing them adds no second script to load and
* no cross-bundle version skew — the tables a reader scrolls to are built from the same
* pin index the map above them is drawing.
*
* NO TOP BAR: StackLayout omits its own header when neither `title` nor #meta is used, so
* the composite shows only the children's own chrome. A second header here would repeat
* the map's legend and push the map down for nothing — the same defect the
* dashboard-plus-grid header notes were written about.
*
* THE MAP KEEPS ITS OWN HEIGHT. It is absolutely positioned inside its section rather
* than height:auto, because a map with no height renders a zero-pixel canvas that reads
* as "the map did not load" — which is the failure this repo has diagnosed falsely more
* than once.
*/
import StackLayout from '@map/layouts/StackLayout.vue'
import ResourcesMap from './resources-map.vue'
import DataTables from './data-tables.vue'
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
import { ref, provide } from 'vue'
// ═══ THE TWO HALVES TALK TO EACH OTHER ═══════════════════════════════════════════════
// "Every resource in <language>" is a LINK to the standalone tables page, which is right
// when the map is alone. Inside this composite the tables are already on screen, directly
// below, so following that link navigated AWAY from the dashboard — the filter applied
// correctly (6 of 6,498 for German) but the map was gone and the composite destroyed.
// Measured: the URL changed from gospel-dashboard/index.html to data-tables/index.html.
//
// Provided rather than propped because the two children are separate profiles that must
// each still work standalone: a child that finds nothing injected keeps its old behaviour
// exactly, so nothing changes for resources-map or data-tables on their own pages.
const composedFilter = ref(null)
provide('composedFilter', composedFilter)
const sections = [
{ key: 'map', title: '' },
{ key: 'tables', title: '' },
]
useShadowStyles(
':host{display:block;width:100%}' +
// The map is absolutely positioned inside its own profile, so its section needs a real
// height to render into. 80svh rather than a fixed px: on a phone a 600px map leaves no
// room for anything else, and svh follows the visible viewport rather than the
// URL-bar-inclusive one.
// THE MAP keeps a real height because it is absolutely positioned inside its own
// profile: a map with no height renders a zero-pixel canvas that reads as "the map did
// not load", a false diagnosis this repo has paid for more than once. 80svh rather than
// a fixed px — on a phone a 600px map leaves no room for anything beneath it.
'.gd-map{position:relative;width:100%;height:80svh;min-height:420px}' +
'.gd-tables{position:relative;width:100%;background:#f3f3f1}' +
// ★ THE TABLES MUST FLOW, NOT FILL. data-tables is .gt{position:absolute;inset:0}, built
// to fill a positioned parent when it is the whole page. Stacked, that gives it no
// intrinsic height, so the section collapsed and the host clamped to exactly 100dvh:
// MEASURED docScrollHeight 900 against clientHeight 900, scrollTo and a real wheel
// gesture both moving 0px. The tables were in the DOM and unreachable, which is the
// worst of both — rendered, counted by a probe, and invisible to a person.
// Made static here so the section takes its natural height and the PAGE scrolls. One
// scroll container, not a scroller inside a scroller: this repo has already fixed the
// nested-scroll version of this twice.
'.gd-tables .gt{position:static;inset:auto;height:auto;overflow:visible}'
)
</script>
<template>
<StackLayout :sections="sections">
<template #section-map>
<div class="gd-map"><ResourcesMap /></div>
</template>
<template #section-tables>
<div class="gd-tables"><DataTables /></div>
</template>
</StackLayout>
</template>
<style>
:host { display:block; width:100%; }
</style>