export default defineNuxtPlugin((NuxtApp) => { NuxtApp.vueApp.directive('animate', (el, binding) => { el.classList.add('animate') el.setAttribute('data-animate-duration', binding.value.duration || 250 ) el.setAttribute('data-animate-delay', binding.value.delay || 200 ) el.setAttribute('data-animate-preset', binding.value.preset || 'fade' ) el.setAttribute('data-animate-stagger', binding.value.stagger || false ) el.setAttribute('data-animate-stagger-delay', binding.value.staggerDelay || 100 ) }) NuxtApp.hook('page:finish', () => { const applyClasses = (el, type) => { const initialClasses = JSON.parse(el.getAttribute('data-animate-initial')) const animateClasses = JSON.parse(el.getAttribute('data-animate-animate')) if (type === 'initial') { Object.keys(initialClasses).forEach(x => { el.style[x] = initialClasses[x] }) el.style['transition-property'] = 'none' } if (type === 'animate') { Object.keys(animateClasses).forEach(x => { el.style[x] = animateClasses[x] }) el.style['transition-property'] = 'all' } } const callback = (entries) => { entries.forEach(entry => { if (entry.isIntersecting) { applyClasses(entry.target, 'animate') } else { applyClasses(entry.target, 'initial') } }) } // Configure staggering animations let targets = document.querySelectorAll('.animate') targets.forEach((target) => { if (target.getAttribute('data-animate-stagger') === 'true') { target.classList.remove('animate') const collection = target.children Object.values(collection).forEach((child, index) => { child.setAttribute('data-animate-preset', target.getAttribute('data-animate-preset') ) child.setAttribute('data-animate-duration', target.getAttribute('data-animate-duration') ) child.style.transitionDelay = Number(target.getAttribute('data-animate-delay')) + index * Number(target.getAttribute('data-animate-stagger-delay')) + 'ms' child.classList.add('animate') }) } else { target.style.transitionDelay = target.getAttribute('data-animate-delay') + 'ms' } }) // Configure presets const observer = new IntersectionObserver(callback) targets = document.querySelectorAll('.animate') targets.forEach(target => { const preset = target.getAttribute('data-animate-preset') if (preset === 'fade') { target.setAttribute('data-animate-initial', JSON.stringify({ opacity: 0 })) target.setAttribute('data-animate-animate', JSON.stringify({ opacity: 100 })) } else if (preset === 'slide-left') { target.setAttribute('data-animate-initial', JSON.stringify({ opacity: 0, transform: 'translateX(-6em)', filter: 'blur(5px)' })) target.setAttribute('data-animate-animate', JSON.stringify({ opacity: 100, transform: 'translateX(0)', filter: 'blur(0)' })) } else if (preset === 'slide-right') { target.setAttribute('data-animate-initial', JSON.stringify({ opacity: 0, transform: 'translateX(6em)', filter: 'blur(5px)' })) target.setAttribute('data-animate-animate', JSON.stringify({ opacity: 100, transform: 'translateX(0)', filter: 'blur(0px)' })) } else if (preset === 'slide-up') { target.setAttribute('data-animate-initial', JSON.stringify({ opacity: 0, transform: 'translateY(-2em)', filter: 'blur(5px)' })) target.setAttribute('data-animate-animate', JSON.stringify({ opacity: 100, transform: 'translateY(0)', filter: 'blur(0px)' })) } else if (preset === 'slide-down') { target.setAttribute('data-animate-initial', JSON.stringify({ opacity: 0, transform: 'translateY(2em)', filter: 'blur(5px)' })) target.setAttribute('data-animate-animate', JSON.stringify({ opacity: 100, transform: 'translateY(0)', filter: 'blur(0px)' })) } applyClasses(target, 'initial') target.classList.add('transition-all') target.style['transition-duration'] = target.getAttribute('data-animate-duration') + 'ms' observer.observe(target) }) }) })