diff --git a/frontend/app/components/parts/StickyHeader.vue b/frontend/app/components/parts/StickyHeader.vue index ce07c59..cfc5c20 100644 --- a/frontend/app/components/parts/StickyHeader.vue +++ b/frontend/app/components/parts/StickyHeader.vue @@ -3,20 +3,47 @@ import HeaderLinks from './HeaderLinks.vue'; import SiteOptions from './site_options/SiteOptions.vue'; import { ref, onMounted, onUnmounted } from 'vue'; - -const SCROLL_THRESHOLD = 120; // px scrolled before sticky header appears + +const localePath = useLocalePath(); + +const SCROLL_THRESHOLD = 120; // px from top before the bar can appear +const SCROLL_DELTA = 8; // min px movement to register a direction (avoids jitter) const props = defineProps({ alwaysVisible: { type: Boolean, default: false } }); - + const isVisible = ref(props.alwaysVisible); - + +let lastScrollY = 0; + function onScroll() { - isVisible.value = props.alwaysVisible || window.scrollY > SCROLL_THRESHOLD; + const currentY = window.scrollY; + + if (props.alwaysVisible) { + isVisible.value = true; + lastScrollY = currentY; + return; + } + + // Near the top the real header is visible, so keep the bar hidden. + if (currentY <= SCROLL_THRESHOLD) { + isVisible.value = false; + } else if (currentY > lastScrollY + SCROLL_DELTA) { + // scrolling down -> hide + isVisible.value = false; + } else if (currentY < lastScrollY - SCROLL_DELTA) { + // scrolling up -> show + isVisible.value = true; + } + + lastScrollY = currentY; } - -onMounted(() => window.addEventListener('scroll', onScroll, { passive: true })); + +onMounted(() => { + lastScrollY = window.scrollY; + window.addEventListener('scroll', onScroll, { passive: true }); +}); onUnmounted(() => window.removeEventListener('scroll', onScroll)); @@ -25,7 +52,10 @@ onUnmounted(() => window.removeEventListener('scroll', onScroll));