portfolio/plugins/motion.js
2023-02-09 20:21:20 +01:00

102 lines
4.1 KiB
JavaScript

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)
})
})
})