diff --git a/app/pages/package/[[org]]/[name].vue b/app/pages/package/[[org]]/[name].vue index 3ade232d3..cddc7a70c 100644 --- a/app/pages/package/[[org]]/[name].vue +++ b/app/pages/package/[[org]]/[name].vue @@ -28,6 +28,8 @@ const router = useRouter() const header = useTemplateRef('header') const isHeaderPinned = shallowRef(false) +const navExtraOffset = shallowRef(0) +const isMobile = useMediaQuery('(max-width: 639.9px)') function checkHeaderPosition() { const el = header.value @@ -43,10 +45,51 @@ function checkHeaderPosition() { useEventListener('scroll', checkHeaderPosition, { passive: true }) useEventListener('resize', checkHeaderPosition) +const footerTarget = ref(null) +const footerThresholds = Array.from({ length: 11 }, (_, i) => i / 10) + +const { pause: pauseFooterObserver, resume: resumeFooterObserver } = useIntersectionObserver( + footerTarget, + ([entry]) => { + if (!entry) return + + navExtraOffset.value = entry.isIntersecting ? entry.intersectionRect.height : 0 + }, + { + threshold: footerThresholds, + immediate: false, + }, +) + +function initFooterObserver() { + footerTarget.value = document.querySelector('footer') + if (!footerTarget.value) return + + pauseFooterObserver() + + watch( + isMobile, + value => { + if (value) { + resumeFooterObserver() + } else { + pauseFooterObserver() + navExtraOffset.value = 0 + } + }, + { immediate: true }, + ) +} + onMounted(() => { checkHeaderPosition() + initFooterObserver() }) +const navExtraOffsetStyle = computed(() => ({ + '--package-nav-extra': `${navExtraOffset.value}px`, +})) + const { packageName, requestedVersion, orgName } = usePackageRoute() const selectedPM = useSelectedPackageManager() const activePmId = computed(() => selectedPM.value ?? 'npm') @@ -647,6 +690,7 @@ onKeyStroke( as="nav" :aria-label="$t('package.navigation')" class="hidden sm:flex max-sm:flex max-sm:fixed max-sm:z-40 max-sm:inset-is-1/2 max-sm:-translate-x-1/2 max-sm:rtl:translate-x-1/2 max-sm:bg-[--bg]/90 max-sm:backdrop-blur-md max-sm:border max-sm:border-border max-sm:rounded-md max-sm:shadow-md" + :style="navExtraOffsetStyle" :class="$style.packageNav" > :global(a kbd) {