diff --git a/plugin-designs/gospel-internet/board.vue b/plugin-designs/gospel-internet/board.vue index a66d3a059..fa67bff25 100644 --- a/plugin-designs/gospel-internet/board.vue +++ b/plugin-designs/gospel-internet/board.vue @@ -39,6 +39,7 @@ import GiDrawer from './src/components/GiDrawer.vue' import GiTree from './src/components/GiTree.vue' import GiResources from './src/components/GiResources.vue' import GiCombos from './src/components/GiCombos.vue' +import { isNarrowWidth } from './src/breakpoints.js' const T = useGiT() const board = useBoard() @@ -76,7 +77,7 @@ board.readUrl() // partner's address bar is never rewritten. facetKeys is explicit: its default reads nothing on a cold load. useShareableView(bus, { mode: 'query', write: board.profileConfig.value?.urlState === 'query', facetKeys: SHARE_FACETS }) -// ── responsive: one panel at a time under 760px (ResizeObserver on the shell, not @container: a +// ── responsive: one panel at a time under the shared breakpoint (ResizeObserver on the shell, not @container: a // container query cannot target the container itself, which is unreliable inside a shadow root) ────── const shell = ref(null) const isNarrow = ref(false) @@ -84,7 +85,7 @@ const mobilePanel = ref('map') let ro = null onMounted(() => { if (shell.value && typeof ResizeObserver !== 'undefined') { - ro = new ResizeObserver(([e]) => { isNarrow.value = e.contentRect.width < 760 }) + ro = new ResizeObserver(([e]) => { isNarrow.value = isNarrowWidth(e.contentRect.width) }) ro.observe(shell.value) } board.load() diff --git a/plugin-designs/gospel-internet/src/breakpoints.js b/plugin-designs/gospel-internet/src/breakpoints.js new file mode 100644 index 000000000..61bdaefc2 --- /dev/null +++ b/plugin-designs/gospel-internet/src/breakpoints.js @@ -0,0 +1,18 @@ +/** + * breakpoints.js — the one width at which this dashboard stops being a three-column board. + * + * ★ IT IS A CONSTANT BECAUSE IT WAS TWO NUMBERS. board.vue collapsed to a single panel below + * 760px; the set charts stacked their legend below 900px. Between those two widths the board + * still held three columns while a chart inside it had already given up on having room — at + * 768 the centre column was about 145px, so the bounded figure was crushed to 124px and the + * centered figure's own minimum made it spill UNDER the right-hand panel. + * + * Neither number was wrong on its own. The defect was that they were separate, and nothing + * connected the width at which a chart needs room to the width at which the board gives it any. + */ +export const NARROW_MAX = 900 + +/** True when the shell is too narrow for side panels beside the centre column. */ +export function isNarrowWidth(px) { + return Number(px) < NARROW_MAX +} diff --git a/plugin-designs/gospel-internet/src/components/GiCenteredSet.vue b/plugin-designs/gospel-internet/src/components/GiCenteredSet.vue index 357037f7c..6dacd7a40 100644 --- a/plugin-designs/gospel-internet/src/components/GiCenteredSet.vue +++ b/plugin-designs/gospel-internet/src/components/GiCenteredSet.vue @@ -28,6 +28,7 @@ import { layoutCenteredSet, ringTally, inwardArrow, ringRadii } from '@map/compo import GiRingLegend from './GiRingLegend.vue' import GiCenteredSetMap from './GiCenteredSetMap.vue' import FullscreenButton from '@map/components/map-controls/FullscreenButton.vue' +import { NARROW_MAX } from '../breakpoints.js' const T = useGiT() const board = useBoardState() @@ -70,7 +71,10 @@ function applyWidth(m) { function setLegendOpen(v) { chosen = v; legendOpen.value = v } onMounted(() => { try { - mq = window.matchMedia('(max-width: 900px)') + // The same width the BOARD collapses at (NARROW_MAX). If these two ever disagree again, + // the board keeps its side panels while the chart has already given up on room — which is + // exactly the 768px failure. + mq = window.matchMedia(`(max-width: ${NARROW_MAX - 1}px)`) applyWidth(mq) mq.addEventListener?.('change', applyWidth) } catch (_) { /* no matchMedia: stay wide, which is the layout that always fits */ }