Complete Next.js website with Docker containerization: - Next.js 14 with TypeScript and Tailwind CSS - Responsive design with modern UI components - Hero section, features showcase, testimonials - FAQ section with comprehensive content - Contact forms and newsletter signup - Docker production build with Nginx - Health checks and monitoring support - SEO optimization and performance tuning Ready for integration as git submodule in main CHORUS project. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
644 lines
11 KiB
TypeScript
644 lines
11 KiB
TypeScript
import { Variants } from 'framer-motion';
|
|
|
|
/**
|
|
* Common animation variants for Framer Motion
|
|
* Provides consistent animations across the application
|
|
*/
|
|
|
|
export const fadeInUp: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
y: 30,
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
y: 0,
|
|
transition: {
|
|
duration: 0.6,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const fadeInDown: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
y: -30,
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
y: 0,
|
|
transition: {
|
|
duration: 0.6,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const fadeInLeft: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
x: -30,
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
x: 0,
|
|
transition: {
|
|
duration: 0.6,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const fadeInRight: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
x: 30,
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
x: 0,
|
|
transition: {
|
|
duration: 0.6,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const fadeIn: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
transition: {
|
|
duration: 0.6,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const scaleIn: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
scale: 0.8,
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
scale: 1,
|
|
transition: {
|
|
duration: 0.6,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const slideInUp: Variants = {
|
|
hidden: {
|
|
y: '100%',
|
|
opacity: 0,
|
|
},
|
|
visible: {
|
|
y: '0%',
|
|
opacity: 1,
|
|
transition: {
|
|
duration: 0.6,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const slideInDown: Variants = {
|
|
hidden: {
|
|
y: '-100%',
|
|
opacity: 0,
|
|
},
|
|
visible: {
|
|
y: '0%',
|
|
opacity: 1,
|
|
transition: {
|
|
duration: 0.6,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const staggerContainer: Variants = {
|
|
hidden: {},
|
|
visible: {
|
|
transition: {
|
|
staggerChildren: 0.1,
|
|
delayChildren: 0.1,
|
|
},
|
|
},
|
|
};
|
|
|
|
export const staggerFast: Variants = {
|
|
hidden: {},
|
|
visible: {
|
|
transition: {
|
|
staggerChildren: 0.05,
|
|
},
|
|
},
|
|
};
|
|
|
|
export const staggerSlow: Variants = {
|
|
hidden: {},
|
|
visible: {
|
|
transition: {
|
|
staggerChildren: 0.2,
|
|
},
|
|
},
|
|
};
|
|
|
|
// Hover animations
|
|
export const hoverScale: Variants = {
|
|
hover: {
|
|
scale: 1.05,
|
|
transition: {
|
|
duration: 0.2,
|
|
ease: 'easeInOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const hoverLift: Variants = {
|
|
hover: {
|
|
y: -5,
|
|
transition: {
|
|
duration: 0.2,
|
|
ease: 'easeInOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const hoverGlow: Variants = {
|
|
hover: {
|
|
boxShadow: '0 0 30px rgba(0, 122, 255, 0.3)',
|
|
transition: {
|
|
duration: 0.3,
|
|
ease: 'easeInOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
// Specialized animations for CHORUS components
|
|
export const orchestrationFlow: Variants = {
|
|
hidden: {
|
|
pathLength: 0,
|
|
opacity: 0,
|
|
},
|
|
visible: {
|
|
pathLength: 1,
|
|
opacity: 1,
|
|
transition: {
|
|
pathLength: {
|
|
duration: 2,
|
|
ease: 'easeInOut',
|
|
},
|
|
opacity: {
|
|
duration: 0.3,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
export const dataFlow: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
scale: 0,
|
|
},
|
|
visible: (i: number) => ({
|
|
opacity: 1,
|
|
scale: 1,
|
|
transition: {
|
|
delay: i * 0.2,
|
|
duration: 0.5,
|
|
ease: 'easeOut',
|
|
},
|
|
}),
|
|
};
|
|
|
|
export const pulseAnimation: Variants = {
|
|
pulse: {
|
|
scale: [1, 1.1, 1],
|
|
opacity: [1, 0.8, 1],
|
|
transition: {
|
|
duration: 2,
|
|
repeat: Infinity,
|
|
ease: 'easeInOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const rotateAnimation: Variants = {
|
|
rotate: {
|
|
rotate: 360,
|
|
transition: {
|
|
duration: 2,
|
|
repeat: Infinity,
|
|
ease: 'linear',
|
|
},
|
|
},
|
|
};
|
|
|
|
// Page transition animations
|
|
export const pageTransition: Variants = {
|
|
initial: {
|
|
opacity: 0,
|
|
y: 20,
|
|
},
|
|
animate: {
|
|
opacity: 1,
|
|
y: 0,
|
|
transition: {
|
|
duration: 0.4,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
exit: {
|
|
opacity: 0,
|
|
y: -20,
|
|
transition: {
|
|
duration: 0.3,
|
|
ease: 'easeIn',
|
|
},
|
|
},
|
|
};
|
|
|
|
// Modal animations
|
|
export const modalBackdrop: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
transition: {
|
|
duration: 0.3,
|
|
},
|
|
},
|
|
};
|
|
|
|
export const modalContent: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
scale: 0.8,
|
|
y: 50,
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
scale: 1,
|
|
y: 0,
|
|
transition: {
|
|
duration: 0.4,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
// Loading animations
|
|
export const spinnerAnimation: Variants = {
|
|
spin: {
|
|
rotate: 360,
|
|
transition: {
|
|
duration: 1,
|
|
repeat: Infinity,
|
|
ease: 'linear',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const dotsLoading: Variants = {
|
|
loading: {
|
|
scale: [1, 1.2, 1],
|
|
opacity: [1, 0.6, 1],
|
|
transition: {
|
|
duration: 0.8,
|
|
repeat: Infinity,
|
|
ease: 'easeInOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
// Apple-inspired easing curves
|
|
export const appleEasing = [0.21, 1.11, 0.81, 0.99]; // Apple's signature cubic-bezier
|
|
export const appleSpring = {
|
|
type: 'spring',
|
|
stiffness: 400,
|
|
damping: 30,
|
|
mass: 1,
|
|
};
|
|
|
|
// Advanced parallax animations
|
|
export const parallaxSlow: Variants = {
|
|
hidden: { y: 0, opacity: 0 },
|
|
visible: {
|
|
y: 0,
|
|
opacity: 1,
|
|
transition: {
|
|
duration: 1,
|
|
ease: appleEasing,
|
|
},
|
|
},
|
|
};
|
|
|
|
export const parallaxMedium: Variants = {
|
|
hidden: { y: 0, opacity: 0 },
|
|
visible: {
|
|
y: 0,
|
|
opacity: 1,
|
|
transition: {
|
|
duration: 0.8,
|
|
ease: appleEasing,
|
|
},
|
|
},
|
|
};
|
|
|
|
export const parallaxFast: Variants = {
|
|
hidden: { y: 0, opacity: 0 },
|
|
visible: {
|
|
y: 0,
|
|
opacity: 1,
|
|
transition: {
|
|
duration: 0.6,
|
|
ease: appleEasing,
|
|
},
|
|
},
|
|
};
|
|
|
|
// Gradient text animation
|
|
export const gradientTextAnimation: Variants = {
|
|
initial: {
|
|
backgroundPosition: '0% 50%',
|
|
},
|
|
animate: {
|
|
backgroundPosition: ['0% 50%', '100% 50%', '0% 50%'],
|
|
transition: {
|
|
duration: 5,
|
|
repeat: Infinity,
|
|
ease: 'easeInOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
// Advanced button hover states
|
|
export const appleButtonHover: Variants = {
|
|
initial: {
|
|
scale: 1,
|
|
boxShadow: '0 4px 14px 0 rgba(0, 122, 255, 0.25)',
|
|
},
|
|
hover: {
|
|
scale: 1.05,
|
|
boxShadow: '0 8px 25px 0 rgba(0, 122, 255, 0.4)',
|
|
transition: {
|
|
duration: 0.2,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
tap: {
|
|
scale: 0.98,
|
|
transition: {
|
|
duration: 0.1,
|
|
},
|
|
},
|
|
};
|
|
|
|
// Hero entrance animations
|
|
export const heroEntrance: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
y: 60,
|
|
scale: 0.95,
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
y: 0,
|
|
scale: 1,
|
|
transition: {
|
|
duration: 0.8,
|
|
ease: appleEasing,
|
|
},
|
|
},
|
|
};
|
|
|
|
// Staggered hero container
|
|
export const heroStaggerContainer: Variants = {
|
|
hidden: {},
|
|
visible: {
|
|
transition: {
|
|
staggerChildren: 0.2,
|
|
delayChildren: 0.3,
|
|
},
|
|
},
|
|
};
|
|
|
|
// Floating elements animation
|
|
export const floatingAnimation: Variants = {
|
|
initial: {
|
|
y: 0,
|
|
rotate: 0,
|
|
},
|
|
animate: {
|
|
y: [-10, 10, -10],
|
|
rotate: [-2, 2, -2],
|
|
transition: {
|
|
duration: 6,
|
|
repeat: Infinity,
|
|
ease: 'easeInOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
// Geometric shape animations
|
|
export const geometricShapeAnimation: Variants = {
|
|
initial: {
|
|
scale: 1,
|
|
opacity: 0.2,
|
|
rotate: 0,
|
|
},
|
|
animate: {
|
|
scale: [1, 1.5, 1],
|
|
opacity: [0.2, 0.8, 0.2],
|
|
rotate: [0, 360],
|
|
transition: {
|
|
duration: 8,
|
|
repeat: Infinity,
|
|
ease: 'easeInOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
// Interactive hover glow effect
|
|
export const interactiveGlow: Variants = {
|
|
initial: {
|
|
boxShadow: '0 0 0 rgba(0, 122, 255, 0)',
|
|
},
|
|
hover: {
|
|
boxShadow: '0 0 30px rgba(0, 122, 255, 0.3)',
|
|
transition: {
|
|
duration: 0.3,
|
|
ease: 'easeOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
// Advanced scroll-triggered animations
|
|
export const scrollReveal: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
y: 75,
|
|
scale: 0.9,
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
y: 0,
|
|
scale: 1,
|
|
transition: {
|
|
duration: 0.8,
|
|
ease: appleEasing,
|
|
},
|
|
},
|
|
};
|
|
|
|
// Performance-optimized fade variants
|
|
export const performantFade: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
transform: 'translateY(20px) translateZ(0)',
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
transform: 'translateY(0px) translateZ(0)',
|
|
transition: {
|
|
duration: 0.6,
|
|
ease: appleEasing,
|
|
},
|
|
},
|
|
};
|
|
|
|
// Utility functions for animations
|
|
export const createStaggeredAnimation = (
|
|
baseAnimation: Variants,
|
|
staggerDelay: number = 0.1
|
|
): Variants => ({
|
|
...baseAnimation,
|
|
visible: {
|
|
...baseAnimation.visible,
|
|
transition: {
|
|
...baseAnimation.visible?.transition,
|
|
staggerChildren: staggerDelay,
|
|
},
|
|
},
|
|
});
|
|
|
|
export const createDelayedAnimation = (
|
|
baseAnimation: Variants,
|
|
delay: number
|
|
): Variants => ({
|
|
...baseAnimation,
|
|
visible: {
|
|
...baseAnimation.visible,
|
|
transition: {
|
|
...baseAnimation.visible?.transition,
|
|
delay,
|
|
},
|
|
},
|
|
});
|
|
|
|
export const createCustomEasing = (
|
|
baseAnimation: Variants,
|
|
ease: string | number[]
|
|
): Variants => ({
|
|
...baseAnimation,
|
|
visible: {
|
|
...baseAnimation.visible,
|
|
transition: {
|
|
...baseAnimation.visible?.transition,
|
|
ease,
|
|
},
|
|
},
|
|
});
|
|
|
|
// Parallax utility function
|
|
export const createParallaxAnimation = (
|
|
speed: number,
|
|
direction: 'up' | 'down' | 'left' | 'right' = 'up'
|
|
) => {
|
|
const axis = direction === 'left' || direction === 'right' ? 'x' : 'y';
|
|
const multiplier = direction === 'down' || direction === 'right' ? 1 : -1;
|
|
|
|
return {
|
|
[axis]: `${speed * multiplier * 100}px`,
|
|
};
|
|
};
|
|
|
|
// Scroll-based animation utility
|
|
export const createScrollAnimation = (
|
|
element: React.RefObject<HTMLElement>,
|
|
options: {
|
|
start?: number;
|
|
end?: number;
|
|
property: string;
|
|
from: any;
|
|
to: any;
|
|
}
|
|
) => {
|
|
// This would be used with useScroll and useTransform hooks
|
|
return {
|
|
scrollTrigger: {
|
|
trigger: element.current,
|
|
start: options.start || 0,
|
|
end: options.end || 1000,
|
|
scrub: true,
|
|
},
|
|
[options.property]: [options.from, options.to],
|
|
};
|
|
};
|
|
|
|
// Reduced motion variants for accessibility
|
|
export const createReducedMotionVariant = (baseVariant: Variants): Variants => {
|
|
const prefersReducedMotion = typeof window !== 'undefined' &&
|
|
window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
if (prefersReducedMotion) {
|
|
return {
|
|
...baseVariant,
|
|
visible: {
|
|
...baseVariant.visible,
|
|
transition: {
|
|
duration: 0.01, // Nearly instant
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
return baseVariant;
|
|
};
|
|
|
|
// Apple-style elastic animation
|
|
export const elasticAnimation = {
|
|
type: 'spring',
|
|
stiffness: 500,
|
|
damping: 25,
|
|
mass: 0.8,
|
|
};
|
|
|
|
// Magnetic effect for interactive elements
|
|
export const magneticEffect = {
|
|
hover: {
|
|
scale: 1.1,
|
|
transition: {
|
|
type: 'spring',
|
|
stiffness: 400,
|
|
damping: 10,
|
|
},
|
|
},
|
|
tap: {
|
|
scale: 0.95,
|
|
transition: {
|
|
type: 'spring',
|
|
stiffness: 600,
|
|
damping: 15,
|
|
},
|
|
},
|
|
}; |