/** * Composable for home page hero scroll behavior * Linear: hero shrinks 1:1 with scroll, from full screen to fixed header */ export const useHeroScroll = () => { const scrollY = ref(0) // Hero height = viewport height minus some space const heroBaseHeight = ref(0) const collapsedHeight = 100 // Fixed header height when collapsed // Calculate hero height based on viewport const updateHeroHeight = () => { if (import.meta.client) { heroBaseHeight.value = window.innerHeight - 80 } } // Linear: height = base - scroll, clamped to min const heroHeight = computed(() => { return Math.max(collapsedHeight, heroBaseHeight.value - scrollY.value) }) // Linear progress 0..1 const collapseProgress = computed(() => { const maxScroll = heroBaseHeight.value - collapsedHeight if (maxScroll <= 0) return 1 return Math.min(1, Math.max(0, scrollY.value / maxScroll)) }) // Is fully collapsed? const isCollapsed = computed(() => heroHeight.value <= collapsedHeight) const onScroll = () => { if (import.meta.client) { scrollY.value = window.scrollY } } const onResize = () => { updateHeroHeight() } onMounted(() => { if (import.meta.client) { updateHeroHeight() window.addEventListener('scroll', onScroll, { passive: true }) window.addEventListener('resize', onResize, { passive: true }) onScroll() } }) onUnmounted(() => { if (import.meta.client) { window.removeEventListener('scroll', onScroll) window.removeEventListener('resize', onResize) } }) return { scrollY: readonly(scrollY), heroBaseHeight: readonly(heroBaseHeight), heroHeight, collapseProgress, isCollapsed, collapsedHeight } }