diff --git a/app/pages/deep-research/index.vue b/app/pages/deep-research/index.vue index 7a10cb82..8319c455 100644 --- a/app/pages/deep-research/index.vue +++ b/app/pages/deep-research/index.vue @@ -57,11 +57,19 @@ function fitBelowHeader() { function watchPaneForHeader(el: HTMLElement, root: ShadowRoot) { const cls = document.documentElement.classList const large = (n: HTMLElement) => n.clientHeight >= el.clientHeight / 2 + // The scroller whose scroll hid the header. + let hider: HTMLElement | null = null const onScroll = (e: Event) => { const pane = e.target if (!(pane instanceof HTMLElement) || !large(pane)) return - if (pane.scrollTop > 8) cls.add('rg-header-hidden') - else if (pane.scrollTop <= 0) cls.remove('rg-header-hidden') + if (pane.scrollTop > 8) { + hider = pane + cls.add('rg-header-hidden') + } + else if (pane.scrollTop <= 0) { + hider = null + cls.remove('rg-header-hidden') + } } // Scroll events don't bubble, but they do pass the gallery's shadow root in the capture phase. root.addEventListener('scroll', onScroll, { capture: true, passive: true }) @@ -84,10 +92,29 @@ function watchPaneForHeader(el: HTMLElement, root: ShadowRoot) { } el.addEventListener('touchmove', discover, { passive: true }) el.addEventListener('wheel', discover, { passive: true }) + // Switching tabs hides the old tab's pane (or removes its map) without any scroll event. If + // that takes away the scroller that hid the header, the header comes back: a map-only tab has + // nothing to scroll back to the top, so it could never bring the header back itself. + let pending = false + const recheck = () => { + pending = false + if (!cls.contains('rg-header-hidden')) return + if (hider && hider.isConnected && hider.getClientRects().length > 0 && hider.scrollTop > 0) return + hider = null + cls.remove('rg-header-hidden') + } + const tabSwitch = new MutationObserver(() => { + if (!pending) { + pending = true + requestAnimationFrame(recheck) + } + }) + tabSwitch.observe(root, { subtree: true, childList: true, attributes: true, attributeFilter: ['hidden'] }) unwatchPane = () => { root.removeEventListener('scroll', onScroll, true) el.removeEventListener('touchmove', discover) el.removeEventListener('wheel', discover) + tabSwitch.disconnect() } }