Simple Research: "What can this map do?" becomes the map's top round control

The research map draws the ⓘ as the first button of its own control column (MapInfoButton), and the
gallery's Simple Research row switches to trigger: 'control' in the same commit, so the tab never
shows two ⓘ, and never shows none. At mount the map tells the gallery that its control is coming, so
the floating ⓘ does not flash while a slow phone loads. A failure or an unmount withdraws that
promise, and the floating ⓘ comes back at once. On a page with no gallery nothing answers, and the
map is unchanged.
This commit is contained in:
Doxa Maps 2026-09-30 04:48:20 +00:00
parent 3d462ec308
commit 6b05bd242c
2 changed files with 31 additions and 0 deletions

View file

@ -96,6 +96,7 @@ export const TAB_INFO = {
},
'research-map-plus-grid': {
storageKey: 'research-map-plus-grid',
trigger: 'control',
pos: { top: '56px', side: '56px' },
leadKey: 'mapInfo.tab.research-map-plus-grid.lead',
takeawayKey: 'mapInfo.tab.research-map-plus-grid.takeaway',

View file

@ -177,6 +177,9 @@ import HamburgerButton from '@map/components/map-controls/HamburgerButton.vue'
import GeocoderComponent from '@map/components/map-controls/GeocoderComponent.vue'
import ShareButton from '@map/components/map-controls/ShareButton.vue'
import MapControlButton from '@map/components/map-controls/MapControlButton.vue'
// "What can this map do?", as the top control. By path like the rest: the map-controls barrel would pull
// the whole 'mapInfo' catalogue area into this bundle.
import MapInfoButton from '@map/components/map-controls/MapInfoButton.vue'
// PERF: SideMenuDrawer is unused in the current research-map template (the
// ResearchMapSideMenu sibling renders the actual menu). Removed entirely from
@ -3002,6 +3005,29 @@ function applyContainerScale(width) {
}
}
// ★ THE ⓘ CONTROL IS COMING, SO SAY SO BEFORE THE GALLERY DRAWS ITS FLOATING ONE. The control column
// renders only at appReady, after the style AND the people-group data, and a slow phone gets there late.
// At mount this map tells the gallery's MapInfo that a control is on its way, and the MapInfo waits for
// the map rather than flashing its floating ⓘ and swapping it out. A failure (mapError) or an unmount
// withdraws the promise, so the floating ⓘ shows at once and the popup can always be opened. With no
// MapInfo (a standalone page) nothing answers and nothing changes. This is Prayer Progress's contract.
function announceInfoPending(pending) {
const el = rmRoot.value
if (!el) return
try { el.dispatchEvent(new CustomEvent('dxmaps:mapinfo-pending', { bubbles: true, composed: true, detail: { pending } })) } catch { /* no CustomEvent */ }
}
// A MapInfo that mounted after this map asked into the void; it announces itself, and we answer again.
const reannounceInfoPending = () => { if (!appReady.value && !mapError.value) announceInfoPending(true) }
watch(mapError, (e) => { if (e) announceInfoPending(false) })
onMounted(() => {
announceInfoPending(true)
window.addEventListener('dxmaps:mapinfo-host', reannounceInfoPending)
})
onBeforeUnmount(() => {
window.removeEventListener('dxmaps:mapinfo-host', reannounceInfoPending)
if (!appReady.value) announceInfoPending(false)
})
onMounted(async () => {
// uiStore.init() registers the page-level ResizeObserver that drives
// updateBreakpoint() — without this, breakpoint stays at default 'desktop'
@ -3202,6 +3228,10 @@ onBeforeUnmount(() => {
<!-- Map toolbar (right rail) — canonical button set + ordering. -->
<MapToolbar v-if="appReady && map" :has-geocoder="hasGeocoder">
<!-- The TOP control is "What can this map do?". It opens the gallery's MapInfo for this tab, which
then hides its own floating button. It renders only where a MapInfo answers it, so a standalone
page (DX Life's research page, the leaf) has no dead button. -->
<MapInfoButton :is-dark="isDark" />
<ZoomInButton :map="map" :is-dark="isDark" />
<ZoomOutButton :map="map" :is-dark="isDark" />
<LocationButton :map="map" :is-dark="isDark" />