From c63d92542c6643eccac436499b3d47f317fe5a08 Mon Sep 17 00:00:00 2001
From: doxa-maps-88655c70
<88627970+doxa-maps-88655c70@users.noreply.github.com>
Date: Thu, 24 Sep 2026 14:47:24 +0000
Subject: [PATCH] In the dashboard, "every resource in this language" now
filters the tables below it
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The composite puts the map above its own tables, and the brief's third requirement is
that clicking a pin filters that table. It did not. "Every resource in German, Standard"
was an , which is exactly right when the map is
alone — and inside the dashboard it navigated AWAY, to the standalone tables page. The
filter applied correctly, 6 of 6,498, and the map was gone. Measured: the URL changed
from gospel-dashboard/index.html to data-tables/index.html.
The two halves now talk to each other. The dashboard provides a shared filter; the map
injects it and, when present, turns that link into a button that sets the filter and
scrolls the tables into view; the tables inject it and apply it in place, switching to
the links tab because a language filter means nothing on the others.
PROVIDED, NOT PROPPED, because both children must still work standalone. A child that
finds nothing injected keeps its old behaviour exactly — verified rather than assumed:
on resources-map/index.html the control is still an pointing at
data-tables/index.html?tab=links&iso=deu.
Composed: the control is a BUTTON, the URL stays on gospel-dashboard/index.html, the
table banner reads "Showing 6 of 6,498 resources for German, Standard", and 6 rows with
66 cells render. Arrow changed from → to ↓ because the destination is now down the page
rather than away from it.
My first probe read "12 of 25" here and was wrong. Both halves share ONE shadow root in
the composite, so the map's own "Showing 8 of 25" matched the same pattern as the
table's banner. The probe now matches the table's specific wording and asserts rendered
rows and cells beside it. Same class of mistake as the three already recorded in
AGENT-BRIEF — a pattern that is unambiguous on one page can be ambiguous in a composite.
All five profiles still mount clean; gospel-dashboard 68,459 chars, 54 links, 0 errors.
---
.../gospel-resources/data-tables.vue | 15 +++++++
.../gospel-resources/gospel-dashboard.vue | 14 ++++++
.../gospel-resources/resources-map.vue | 26 ++++++++++-
.../gospel-resources/charts/index.html | 2 +-
.../gospel-resources/data-tables/index.html | 2 +-
.../gospel-dashboard/index.html | 2 +-
.../gospel-resources/gospel-resources.js | 44 +++++++++----------
.../resources-list/index.html | 2 +-
.../gospel-resources/resources-map/index.html | 2 +-
public/doxa-maps/manifest.json | 12 ++---
10 files changed, 86 insertions(+), 35 deletions(-)
diff --git a/plugin-designs/gospel-resources/data-tables.vue b/plugin-designs/gospel-resources/data-tables.vue
index a86c13686..abf92053a 100644
--- a/plugin-designs/gospel-resources/data-tables.vue
+++ b/plugin-designs/gospel-resources/data-tables.vue
@@ -77,6 +77,21 @@ function clearFilter() {
const active = ref(TABS.some((t) => t.id === params.get('tab')) ? params.get('tab') : 'links')
const current = computed(() => TABS.find((t) => t.id === active.value) || TABS[0])
+// ═══ COMPOSED MODE ═══ when these tables are stacked under the map in the dashboard, the
+// map asks them to filter in place instead of linking to this page. Null on the standalone
+// page, where the URL remains the only source of a filter and nothing here changes.
+const composedFilter = inject('composedFilter', null)
+if (composedFilter) {
+ watch(composedFilter, (f) => {
+ if (!f) return
+ fIso.value = String(f.iso || '').trim().toLowerCase()
+ fCountry.value = String(f.country || '').trim().toUpperCase()
+ fLabel.value = String(f.label || '').trim()
+ // The links tab is the one that carries URLs; a filter is meaningless on the others.
+ if (TABS.some((t) => t.id === 'links')) active.value = 'links'
+ })
+}
+
// Fetched at runtime — see the note in cities-internet/data-tables.vue. These two
// tables alone are 2.8MB of JSON; inlining them blocked first paint.
const cache = ref({})
diff --git a/plugin-designs/gospel-resources/gospel-dashboard.vue b/plugin-designs/gospel-resources/gospel-dashboard.vue
index 21b04770d..ccbb72617 100644
--- a/plugin-designs/gospel-resources/gospel-dashboard.vue
+++ b/plugin-designs/gospel-resources/gospel-dashboard.vue
@@ -30,6 +30,20 @@ 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