justin.deal/src/components/common/AnimatedElement.astro

117 lines
3.0 KiB
Plaintext

---
interface Props {
animation: 'fade' | 'scale' | 'slide-up' | 'slide-down' | 'slide-left' | 'slide-right' | 'pulse';
duration?: number; // in milliseconds
delay?: number; // in milliseconds
easing?: string; // CSS easing function
class?: string;
tag?: string; // HTML tag to use
}
const {
animation,
duration = 300,
delay = 0,
easing = 'ease',
class: className = '',
tag: Tag = 'div'
} = Astro.props;
const animationClasses = {
'fade': 'animate-fade',
'scale': 'animate-scale',
'slide-up': 'animate-slide-up',
'slide-down': 'animate-slide-down',
'slide-left': 'animate-slide-left',
'slide-right': 'animate-slide-right',
'pulse': 'animate-pulse'
};
const animationClass = animationClasses[animation] || '';
---
<Tag class:list={[animationClass, className]}>
<style define:vars={{
animationDuration: `${duration}ms`,
animationDelay: `${delay}ms`,
animationEasing: easing
}}>
.animate-fade {
animation: fade var(--animationDuration) var(--animationEasing) var(--animationDelay) both;
}
.animate-scale {
animation: scale var(--animationDuration) var(--animationEasing) var(--animationDelay) both;
}
.animate-slide-up {
animation: slideUp var(--animationDuration) var(--animationEasing) var(--animationDelay) both;
}
.animate-slide-down {
animation: slideDown var(--animationDuration) var(--animationEasing) var(--animationDelay) both;
}
.animate-slide-left {
animation: slideLeft var(--animationDuration) var(--animationEasing) var(--animationDelay) both;
}
.animate-slide-right {
animation: slideRight var(--animationDuration) var(--animationEasing) var(--animationDelay) both;
}
.animate-pulse {
animation: pulse var(--animationDuration) var(--animationEasing) var(--animationDelay) infinite;
}
</style>
<slot />
</Tag>
<style>
@keyframes fade {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes scale {
from { transform: scale(0.95); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
@keyframes slideUp {
from { transform: translateY(20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes slideDown {
from { transform: translateY(-20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes slideLeft {
from { transform: translateX(20px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes slideRight {
from { transform: translateX(-20px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
.animate-fade, .animate-scale, .animate-slide-up,
.animate-slide-down, .animate-slide-left,
.animate-slide-right, .animate-pulse {
animation: none !important;
transition: none !important;
}
}
</style>