Files
website/apps/website/composables/useIntersectionAnimations.js
matt ec72c5d62b
Some checks failed
build-website / build (push) Failing after 1m2s
Initial import of HarborSmith website
2025-09-18 22:20:01 +02:00

96 lines
2.4 KiB
JavaScript

import { ref, onMounted, onBeforeUnmount } from 'vue'
export const useIntersectionAnimations = (threshold = 0.1) => {
const elements = ref([])
let observer = null
const observerOptions = {
threshold,
rootMargin: '0px 0px -100px 0px'
}
const animateElement = (entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-in')
entry.target.style.opacity = '1'
entry.target.style.transform = 'translateY(0)'
// Unobserve after animation to improve performance
if (observer) {
observer.unobserve(entry.target)
}
}
}
const observeElements = () => {
// Check for reduced motion preference
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
if (prefersReducedMotion) {
// Skip animations for users who prefer reduced motion
document.querySelectorAll('[data-animate]').forEach(el => {
el.style.opacity = '1'
el.style.transform = 'none'
})
return
}
observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
animateElement(entry)
})
}, observerOptions)
// Find all elements with data-animate attribute
document.querySelectorAll('[data-animate]').forEach(el => {
// Set initial state
el.style.opacity = '0'
el.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)'
const animationType = el.dataset.animate
switch (animationType) {
case 'fade-up':
el.style.transform = 'translateY(30px)'
break
case 'fade-in':
// Just opacity, no transform
break
case 'scale-in':
el.style.transform = 'scale(0.95)'
break
case 'slide-left':
el.style.transform = 'translateX(50px)'
break
case 'slide-right':
el.style.transform = 'translateX(-50px)'
break
default:
el.style.transform = 'translateY(20px)'
}
// Add delay if specified
if (el.dataset.animateDelay) {
el.style.transitionDelay = el.dataset.animateDelay
}
observer.observe(el)
elements.value.push(el)
})
}
onMounted(() => {
// Wait for DOM to be ready
setTimeout(observeElements, 100)
})
onBeforeUnmount(() => {
if (observer) {
observer.disconnect()
}
})
return {
elements
}
}