Merge remote-tracking branch 'origin/development' into upg100/packet-1058
# Conflicts: # public/dx-maps/doxa-maps-spa/manifest.json # public/dx-maps/doxa-research-map/doxa-research-map.js # public/dx-maps/doxa-research-map/research-map/index.html # public/dx-maps/doxa-research-map/research-map/maplibre/index.html # public/dx-maps/manifest.json # public/dx-maps/my-upg-100-list/my-upg-100-list.js # public/dx-maps/my-upg-100-list/poster-wall/index.html # public/dx-maps/my-upg-100-list/upg-100-list/index.html # public/dx-maps/my-upg-100-list/upg-100-mfe/index.html # public/dx-maps/regions-dashboard/region-dashboards/index.html # public/dx-maps/regions-dashboard/regions-dashboard.js # public/dx-maps/regions-dashboard/regions-list/index.html # public/dx-maps/regions-dashboard/regions-mfe/index.html
This commit is contained in:
commit
8efb1b2ae2
14 changed files with 118 additions and 81 deletions
|
|
@ -88,6 +88,8 @@ and a change here can break other maps.
|
|||
`import … from '@map/components/map-controls/ZoomOutButton.vue'`
|
||||
- **RegionCountryMap** — RegionCountryMap.vue — DX-life's CountryMap, rebuilt on the dx-maps map library.
|
||||
`import … from '@map/components/maps/RegionCountryMap.vue'`
|
||||
- **MapPrintProgress** — MapPrintProgress.vue — SHARED. The loading screen of a map print (mapPrintTemplate.js).
|
||||
`import … from '@map/components/poster/MapPrintProgress.vue'`
|
||||
- **PosterDialog** — PosterDialog.vue — modal for previewing + rendering a poster export.
|
||||
`import … from '@map/components/poster/PosterDialog.vue'`
|
||||
- **PosterPreview** — PosterPreview.vue — scaled live preview of the poster composition.
|
||||
|
|
@ -139,6 +141,8 @@ and a change here can break other maps.
|
|||
`import … from '@map/composables/legends/useLegendMapBridge.js'`
|
||||
- **useWagfRegionsLegendData** — useWagfRegionsLegendData — 3-tier WAGF Regions legend for SemanticTreeLegend.
|
||||
`import … from '@map/composables/legends/useWagfRegionsLegendData.js'`
|
||||
- **mapPrintTemplate** — mapPrintTemplate.js — SHARED (@map/composables/poster/mapPrintTemplate.js).
|
||||
`import … from '@map/composables/poster/mapPrintTemplate.js'`
|
||||
- **useMapPoster** — useMapPoster — render a Mapbox GL map to a poster-grade PNG or PDF blob.
|
||||
`import … from '@map/composables/poster/useMapPoster.js'`
|
||||
- **usePosterLayout** — usePosterLayout — slot positioning math for poster compositions.
|
||||
|
|
|
|||
|
|
@ -257,7 +257,8 @@ function measureControl() {
|
|||
shown = r.width > 0 && r.height > 0 && r.bottom > 0 && r.right > 0 && r.top < window.innerHeight && r.left < window.innerWidth
|
||||
if (shown) {
|
||||
const n = placeBeside(r), o = ctlAt.value
|
||||
if (!n || !o || n.side !== o.side || n.top !== o.top || n.left !== o.left || n.right !== o.right) ctlAt.value = n
|
||||
if (n) n.strip = inStrip(c)
|
||||
if (!n || !o || n.side !== o.side || n.top !== o.top || n.left !== o.left || n.right !== o.right || n.strip !== o.strip) ctlAt.value = n
|
||||
}
|
||||
}
|
||||
controlShown.value = shown
|
||||
|
|
@ -268,6 +269,10 @@ function measureControl() {
|
|||
// scrollTop). It goes on the control's physical inner side: a right-to-left map mirrors its column to
|
||||
// the left edge, and that is read from where the control IS, never assumed from the page's direction.
|
||||
const GAP = 10
|
||||
// A control in a tab's HEADER (MapControlButton's rounded-square form, the header-bar button) sits in the
|
||||
// tab's top strip, where the 1200px rule below measured the pointer covering the view switcher, so its
|
||||
// pointer takes that rule again (mi-ctl-strip). A control in a map's own column keeps its pointer at every width.
|
||||
const inStrip = (el) => el.classList.contains('mcb--rounded-square')
|
||||
function placeBeside(r) {
|
||||
const cb = rootEl.value && rootEl.value.offsetParent
|
||||
if (!cb) return null
|
||||
|
|
@ -414,7 +419,8 @@ useShadowStyles(`
|
|||
control's PHYSICAL side, measured, so the page direction must not flip the row, the glyph or the
|
||||
nudge (the span keeps the text's own direction). (0,3,0) so the 1200px rule below does not hide it:
|
||||
that rule measured the floating pointer crossing each tab's top strip, and this one is placed and
|
||||
measured beside one map's own control instead. */
|
||||
measured beside one map's own control instead. A HEADER control is in that strip, so the rule
|
||||
hides its pointer again at (0,4,0) (mi-ctl-strip). */
|
||||
.mi .mi-pointer.mi-ctl{ display:flex; direction:ltr; translate:0 -50%; }
|
||||
.mi .mi-pointer.mi-ctl-left{ flex-direction:row-reverse; animation-name:mi-nudge-left; }
|
||||
.mi .mi-pointer.mi-ctl-right{ animation-name:mi-nudge; }
|
||||
|
|
@ -525,6 +531,7 @@ useShadowStyles(`
|
|||
placement's business; this rule is only about the hint. */
|
||||
@media (max-width:1199.98px){
|
||||
.mi-pointer{ display:none; }
|
||||
.mi .mi-pointer.mi-ctl.mi-ctl-strip{ display:none; }
|
||||
}
|
||||
|
||||
/* A phone gets a BOTTOM SHEET, not a full screen. A full-screen dialog showed a few lines of text at the
|
||||
|
|
@ -573,7 +580,7 @@ useShadowStyles(`
|
|||
</svg>
|
||||
</div>
|
||||
<!-- Control mode: the same pointer, beside the map's own control (placed by measurement, placeBeside). -->
|
||||
<div v-if="pointing && !open && !floatingShown() && ctlAt" class="mi-pointer mi-ctl" :class="'mi-ctl-' + ctlAt.side" :style="ctlStyle()" aria-hidden="true">
|
||||
<div v-if="pointing && !open && !floatingShown() && ctlAt" class="mi-pointer mi-ctl" :class="['mi-ctl-' + ctlAt.side, { 'mi-ctl-strip': ctlAt.strip }]" :style="ctlStyle()" aria-hidden="true">
|
||||
<span :dir="isRtl() ? 'rtl' : 'ltr'">{{ t('mapInfo.pointer') }}</span>
|
||||
<svg viewBox="0 0 16 16" focusable="false">
|
||||
<path v-if="ctlAt.side === 'left'" d="M14 8H3M7 3.5 2.5 8 7 12.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
★ THE SAME HUD THE POSTER WALL SHOWS while it prepares a poster (the same card, bar and phase line), so a
|
||||
map print looks like the posters' prints rather than a button that goes quiet for a minute. It shows the
|
||||
renderer's own progress (useMapPoster's `progress`: percent + message), so a long render says how far along it
|
||||
is. Styles go in through useShadowStyles, because it renders inside the map's shadow root.
|
||||
renderer's own progress (useMapPoster's `progress.percent`), so a long render shows how far along it is. The
|
||||
renderer's phase MESSAGES are English developer strings, so they are not shown. Styles go in through useShadowStyles, because it renders inside the map's shadow root.
|
||||
-->
|
||||
<template>
|
||||
<div v-if="visible" class="mpp-scrim" role="status" aria-live="polite" :aria-label="kind">
|
||||
|
|
@ -12,7 +12,6 @@
|
|||
<div class="mpp-kind">{{ kind }}</div>
|
||||
<div class="mpp-title">{{ title }}</div>
|
||||
<div class="mpp-bar"><div class="mpp-fill" :style="{ width: pct + '%' }"></div></div>
|
||||
<div class="mpp-phase">{{ message }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -30,7 +29,6 @@ const props = defineProps({
|
|||
})
|
||||
// Never an empty bar while the renderer warms up: 3% until it reports.
|
||||
const pct = computed(() => Math.max(3, Math.min(100, Number(props.progress?.percent) || 0)))
|
||||
const message = computed(() => String(props.progress?.message || ''))
|
||||
|
||||
useShadowStyles(
|
||||
'.mpp-scrim{position:fixed;inset:0;z-index:1000;background:rgba(8,12,16,.55);display:grid;place-items:center;padding:22px}' +
|
||||
|
|
@ -40,6 +38,6 @@ useShadowStyles(
|
|||
'.mpp-title{margin:3px 0 14px;font-size:15px;font-weight:700;line-height:1.3}' +
|
||||
'.mpp-bar{height:5px;border-radius:99px;background:rgba(0,0,0,.10);overflow:hidden}' +
|
||||
'.mpp-fill{height:100%;background:#10b981;border-radius:99px;transition:width .25s ease}' +
|
||||
'.mpp-phase{margin-top:10px;font-size:12.5px;font-weight:600;min-height:1.2em}'
|
||||
'@media (prefers-reduced-motion: reduce){.mpp-fill{transition:none}}'
|
||||
)
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ export const TAB_INFO = {
|
|||
pos: { side: '56px', narrow: { placement: 'top-left', side: '8px' } },
|
||||
leadKey: 'mapInfo.tab.regions-dashboard.lead',
|
||||
strategyKey: 'mapStrategy.tab.regions-dashboard',
|
||||
// ⓘ IN THE HEADER, NOT FLOATING (the header rollout, 2026-09-30): the Regions header draws its own rounded-square
|
||||
// ⓘ beside Share (regions-mfe.vue), as Big Picture's does. trigger:'control' hands this MapInfo to it and
|
||||
// suppresses the floating ⓘ while it is on screen; the pos above stays as the fail-open fallback.
|
||||
trigger: 'control',
|
||||
takeawayKey: 'mapInfo.tab.regions-dashboard.takeaway',
|
||||
// The note names India as the one country without prints: no sheet, no geometry, and 855 people
|
||||
// groups, too many to fit one poster legibly (library/data/country-posters.json carries that
|
||||
|
|
|
|||
|
|
@ -499,7 +499,13 @@ import { resolveAssetsBase } from '@map/utils/embedBase.js'
|
|||
// between MapLibre and Mapbox (see openPgDetail).
|
||||
import { readSourceFeatures } from '@map/maps/pin-selection.js'
|
||||
useShadowStyles(
|
||||
'.upg-root{position:absolute;inset:0;background:#0a1410;color:#e5e7eb;' +
|
||||
// ★ isolation:isolate CONFINES THE MAP AREA'S LAYERS (2026-09-30), the containing layer Simple Research's and the
|
||||
// country map's .rm-root already have. Without it the legend sheet's z-index 1000 competed directly with the
|
||||
// gallery's round ☰ (z 15) in the shell's stacking context and painted over it on the Map view. Isolated,
|
||||
// the whole map area stacks as one layer and the ☰ sits above it, sheet included, as on those maps. It is on
|
||||
// the MAP root only: the poster wall's modal scrim lives in the other pane, outside this layer, and keeps
|
||||
// covering the ☰ (raising the ☰ instead would have put it over that modal).
|
||||
'.upg-root{position:absolute;inset:0;background:#0a1410;color:#e5e7eb;isolation:isolate;' +
|
||||
"font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif}" +
|
||||
'.upg-map{position:absolute;inset:0}' +
|
||||
// P3-1 graceful degrade: the map-cell error notice. Centred in the map cell and
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
|||
import { SHADOW_BOX_SIZING_RESET } from './src/shadowReset.js'
|
||||
import ViewSelect from '@map/components/ViewSelect.vue'
|
||||
import ShareButton from '@map/components/map-controls/ShareButton.vue'
|
||||
// The header ⓘ ("What can this map do?"), Big Picture's header recipe: the map-control MapInfoButton in its HEADER
|
||||
// form, whose control bridge hands the tab's MapInfo to it (tabInfo.js trigger:'control').
|
||||
import MapInfoButton from '@map/components/map-controls/MapInfoButton.vue'
|
||||
// The SELECT VIEW strip is one of the sanctioned additions, so DX-life has no equivalent
|
||||
// markup to clone — and until now its labels were hardcoded English, making it the one piece
|
||||
// of chrome that never localised (visible at locale=ar: the panes and every heading go RTL
|
||||
|
|
@ -221,6 +224,16 @@ useShadowStyles(SHADOW_BOX_SIZING_RESET + PANE_GRID_STYLES + '\n' +
|
|||
// POSITIONING is the caller's job — ViewSelect ships its own metrics but no placement, so the
|
||||
// absolute centring lives here exactly as it does in the shell and in upg-100-mfe.
|
||||
'.rmfe .hdr .viewsel{ position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); }' +
|
||||
// ★ HEADER BUTTONS, Big Picture's recipe (design rule, 2026-09-30): the ⓘ and Share as rounded squares at the
|
||||
// vertical tabs' radius, side by side at the header's end. The SHAPE comes from each button's
|
||||
// shape="rounded-square" prop (--vtl-radius); this header only sizes them to 28 px and keeps a 44 px tap target.
|
||||
'.rmfe .hdr .hdr-btns{ display:inline-flex; align-items:center; gap:8px; flex:0 0 auto; }' +
|
||||
'.rmfe .hdr .hdr-btns .mcb{ --map-btn-size:28px; position:relative; }' +
|
||||
'.rmfe .hdr .hdr-btns .mcb svg{ width:16px; height:16px; }' +
|
||||
'.rmfe .hdr .hdr-btns .mcb::after{ content:""; position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); width:44px; height:44px; }' +
|
||||
// ON A PHONE the centred view switcher (about 290 px at 390) leaves no room for two buttons at one end, so the
|
||||
// ⓘ takes the header's START edge, where the floating ⓘ sat before; Share keeps the end.
|
||||
'@media (max-width: 600px){ .rmfe .hdr .hdr-btns > :first-child{ position:absolute; inset-inline-start:12px; top:50%; transform:translateY(-50%); } }' +
|
||||
// Stage: the pane-wrapper column mounts here (its .pane-col is absolute).
|
||||
'.rmfe .stage{ position:relative; flex:1 1 auto; min-height:0; }' +
|
||||
'.pane > .pane-mount > *{ position:absolute; inset:0; width:100%; height:100%; display:block; }',
|
||||
|
|
@ -238,7 +251,10 @@ useShadowStyles(SHADOW_BOX_SIZING_RESET + PANE_GRID_STYLES + '\n' +
|
|||
:label="t('Views')"
|
||||
@select="go"
|
||||
/>
|
||||
<ShareButton :is-dark="isDark" :embed-path="SHARE_EMBED_PATH" />
|
||||
<div class="hdr-btns" data-header-btns>
|
||||
<MapInfoButton :is-dark="isDark" shape="rounded-square" />
|
||||
<ShareButton :is-dark="isDark" :embed-path="SHARE_EMBED_PATH" shape="rounded-square" />
|
||||
</div>
|
||||
</header>
|
||||
<div class="stage" ref="stage"></div>
|
||||
</div>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -67,7 +67,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <doxa-maps-spa> custom element. -->
|
||||
<script src="../../doxa-maps-spa.js" integrity="sha384-LlOSTITtRB23Iy0zIgFPgtc4oaWa/nKGD/HiGhQZtztpK82Qt25djSAbC1QLFlem" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-maps-spa.js" integrity="sha384-7l58VigRUKdP7+n6FJxxOM0uUHwUWFaltIzYdghcUIOGrw9Uo1fjhBz6dQaR2fb0" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <doxa-maps-spa> custom element. -->
|
||||
<script src="../doxa-maps-spa.js" integrity="sha384-LlOSTITtRB23Iy0zIgFPgtc4oaWa/nKGD/HiGhQZtztpK82Qt25djSAbC1QLFlem" crossorigin="anonymous"></script>
|
||||
<script src="../doxa-maps-spa.js" integrity="sha384-7l58VigRUKdP7+n6FJxxOM0uUHwUWFaltIzYdghcUIOGrw9Uo1fjhBz6dQaR2fb0" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -76,7 +76,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <doxa-map> custom element. -->
|
||||
<script src="../../doxa-simple-map.js" integrity="sha384-CFvpV0+z5UkqIULO4kqU36/z39+M3MgofthE1JlixDcUzDYUofQo08bWe/lIkFmo" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-simple-map.js" integrity="sha384-Sx/8ejD+m6K/0dqWtmm8ZcPYpSgYJL5qhhDgFrwREIJoPxgXgScfr6XHlEE+b+g3" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <doxa-map> custom element. -->
|
||||
<script src="../../doxa-simple-map.js" integrity="sha384-CFvpV0+z5UkqIULO4kqU36/z39+M3MgofthE1JlixDcUzDYUofQo08bWe/lIkFmo" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-simple-map.js" integrity="sha384-Sx/8ejD+m6K/0dqWtmm8ZcPYpSgYJL5qhhDgFrwREIJoPxgXgScfr6XHlEE+b+g3" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <doxa-map> custom element. -->
|
||||
<script src="../doxa-simple-map.js" integrity="sha384-CFvpV0+z5UkqIULO4kqU36/z39+M3MgofthE1JlixDcUzDYUofQo08bWe/lIkFmo" crossorigin="anonymous"></script>
|
||||
<script src="../doxa-simple-map.js" integrity="sha384-Sx/8ejD+m6K/0dqWtmm8ZcPYpSgYJL5qhhDgFrwREIJoPxgXgScfr6XHlEE+b+g3" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <doxa-map> custom element. -->
|
||||
<script src="../../doxa-simple-map.js" integrity="sha384-CFvpV0+z5UkqIULO4kqU36/z39+M3MgofthE1JlixDcUzDYUofQo08bWe/lIkFmo" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-simple-map.js" integrity="sha384-Sx/8ejD+m6K/0dqWtmm8ZcPYpSgYJL5qhhDgFrwREIJoPxgXgScfr6XHlEE+b+g3" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
Loading…
Reference in a new issue