Deep Research: the header leaves while the gallery is scrolled; the Deeper Research line is small
The Driver, reviewing on a phone: on /deep-research the site header stayed while every other page lets it scroll away, and the "Want Deeper Research?" line under the research map was far too big. /deep-research keeps the verified layout at rest: the page does not scroll, the header shows, and the gallery fills the rest of the screen, its bottom menu button included. The gallery scrolls inside its own main pane, so a finger or a wheel over it never moves the page. Once that pane is scrolled down a little, <html> gets rg-header-hidden: the header hides and the gallery takes the whole screen (100svh). Back at the pane's top, the header returns. One scroller, so nothing fights its momentum. A capture-phase scroll listener on the gallery's shadow root sees the pane; only a scroller at least half the gallery's height counts. Measured with a real finger at 390: the map (703 px) and the open sheet (211 px) never resize, and the header hides once and returns once. /research: the line is 1.2rem, the size of the homepage's "Explore our research maps" link.
This commit is contained in:
parent
90fc8ffd19
commit
03c02a1f18
2 changed files with 54 additions and 4 deletions
|
|
@ -17,6 +17,8 @@
|
|||
import { mapboxTokenIfChosen } from '~/utils/mapProvider'
|
||||
|
||||
// ONE scrollbar: no footer here, and the page itself never scrolls; the gallery's own content does.
|
||||
// The header still leaves as on every other page: it hides while the gallery is scrolled down
|
||||
// (see watchPaneForHeader) and the gallery then takes the whole screen.
|
||||
definePageMeta({ hideFooter: true })
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
|
|
@ -36,6 +38,7 @@ useHead({
|
|||
const host = ref<HTMLElement | null>(null)
|
||||
let gallery: HTMLElement | null = null
|
||||
let resizeObs: ResizeObserver | null = null
|
||||
let unwatchPane: (() => void) | null = null
|
||||
|
||||
// The gallery fills the viewport below the header. The header's height differs between desktop
|
||||
// and phone (and with the language), so it is measured, not assumed.
|
||||
|
|
@ -45,6 +48,31 @@ function fitBelowHeader() {
|
|||
document.documentElement.style.setProperty('--rg-header-h', h + 'px')
|
||||
}
|
||||
|
||||
// The gallery scrolls inside its own main pane, so a finger (or a wheel) over it scrolls that
|
||||
// pane and never the page. The header leaves the way it does on every other page: once the pane
|
||||
// is scrolled down a little, <html> gets rg-header-hidden (the header hides and the gallery takes
|
||||
// the full screen); back at the pane's top, the header returns. One scroller, so nothing fights
|
||||
// the pane's own momentum. Only a scroller at least half the gallery's height counts (its main
|
||||
// pane), not a small list such as a legend sheet's.
|
||||
function watchPaneForHeader(el: HTMLElement, root: ShadowRoot) {
|
||||
const onScroll = (e: Event) => {
|
||||
const pane = e.target
|
||||
if (!(pane instanceof HTMLElement) || pane.clientHeight < el.clientHeight / 2) return
|
||||
const cls = document.documentElement.classList
|
||||
if (pane.scrollTop > 8) cls.add('rg-header-hidden')
|
||||
else if (pane.scrollTop <= 0) cls.remove('rg-header-hidden')
|
||||
}
|
||||
// Scroll events don't bubble, but they do pass the shadow root in the capture phase.
|
||||
root.addEventListener('scroll', onScroll, { capture: true, passive: true })
|
||||
unwatchPane = () => root.removeEventListener('scroll', onScroll, true)
|
||||
}
|
||||
|
||||
// The gallery attaches its shadow root once its script has defined the element.
|
||||
function whenShadowRoot(el: HTMLElement, done: (root: ShadowRoot) => void, tries = 50) {
|
||||
if (el.shadowRoot) done(el.shadowRoot)
|
||||
else if (tries > 0) setTimeout(() => whenShadowRoot(el, done, tries - 1), 100)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fitBelowHeader()
|
||||
// The gallery is sized to the viewport below the header; a sub-pixel header height must not add a
|
||||
|
|
@ -76,6 +104,10 @@ onMounted(() => {
|
|||
gallery.setAttribute('provider', provider)
|
||||
gallery.setAttribute('profile-config', JSON.stringify(galleryConfig))
|
||||
host.value?.appendChild(gallery)
|
||||
customElements.whenDefined('doxa-maps-spa').then(() => {
|
||||
const el = gallery
|
||||
if (el) whenShadowRoot(el, root => watchPaneForHeader(el, root))
|
||||
})
|
||||
})
|
||||
|
||||
watch(locale, (lang) => {
|
||||
|
|
@ -83,9 +115,10 @@ watch(locale, (lang) => {
|
|||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.documentElement.classList.remove('rg-no-page-scroll')
|
||||
document.documentElement.classList.remove('rg-gallery-mounted')
|
||||
document.documentElement.classList.remove('rg-no-page-scroll', 'rg-gallery-mounted', 'rg-header-hidden')
|
||||
resizeObs?.disconnect()
|
||||
unwatchPane?.()
|
||||
unwatchPane = null
|
||||
gallery?.remove()
|
||||
gallery = null
|
||||
})
|
||||
|
|
@ -131,6 +164,15 @@ html.rg-no-page-scroll body {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* While the gallery is scrolled down, the header is away and the gallery takes the whole screen,
|
||||
as the header leaves on every other page. Back at the gallery's top, the header returns. */
|
||||
html.rg-header-hidden #masthead {
|
||||
display: none;
|
||||
}
|
||||
html.rg-header-hidden .research-gallery-page {
|
||||
height: 100svh;
|
||||
}
|
||||
|
||||
/* The site header is z-index 1500 (blocks/_header.scss); the gallery's info dialog is a full-viewport
|
||||
layer at z-index 1000, full-screen on a phone, so the header covered the dialog's title and close
|
||||
button there. While the gallery is shown, the header sits just under the dialog: 999 still keeps it,
|
||||
|
|
|
|||
|
|
@ -51,8 +51,9 @@ useTextHighlight()
|
|||
:profile-config="researchProfileConfig"
|
||||
class="rounded-xlg"
|
||||
/>
|
||||
<!-- Under the map: the way to the full set of research maps, the hidden Deep Research page. -->
|
||||
<p class="text-center">
|
||||
<!-- Under the map: the way to the full set of research maps, the hidden Deep Research page.
|
||||
Small, like the homepage's "Explore our research maps" line under its map. -->
|
||||
<p class="text-center deep-research-line">
|
||||
{{ t('Want Deeper Research?') }}
|
||||
<NuxtLink
|
||||
class="light-link"
|
||||
|
|
@ -70,3 +71,10 @@ useTextHighlight()
|
|||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* The same size as the homepage's link under its map (.research-map-link in pages/index.vue). */
|
||||
.deep-research-line {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in a new issue