import { useEffect, useState } from 'react'; import { useSpring, animated } from '@react-spring/web'; /** * Decorative shape component to be placed near specific UI elements * Position it relative to a parent container with position: relative */ export default function DecorativeShape({ color = '#FF9500', size = 80, top, left, right, bottom, type = 'circle', // circle, square, ring, dot rotation = 0, opacity = 0.12, floatRange = 6, floatSpeed = 5000, scrollFactor = 0.03, zIndex = 0, }) { const [floatOffset, setFloatOffset] = useState(0); const [scrollY, setScrollY] = useState(0); // Floating animation loop useEffect(() => { let startTime = Date.now(); let animationFrame; const animate = () => { const elapsed = Date.now() - startTime; const offset = Math.sin((elapsed / floatSpeed) * Math.PI * 2) * floatRange; setFloatOffset(offset); animationFrame = requestAnimationFrame(animate); }; animationFrame = requestAnimationFrame(animate); return () => cancelAnimationFrame(animationFrame); }, [floatSpeed, floatRange]); // Scroll listener useEffect(() => { const handleScroll = () => { setScrollY(window.scrollY); }; window.addEventListener('scroll', handleScroll, { passive: true }); return () => window.removeEventListener('scroll', handleScroll); }, []); // Spring animation for smooth movement const springProps = useSpring({ transform: `translateY(${floatOffset + scrollY * scrollFactor}px) rotate(${rotation}deg)`, config: { mass: 2, tension: 120, friction: 30, }, }); const baseStyles = { position: 'absolute', top, left, right, bottom, width: size, height: size, pointerEvents: 'none', zIndex, }; // Shape variants const shapeStyles = { circle: { borderRadius: '50%', background: color, opacity, }, ring: { borderRadius: '50%', background: 'transparent', border: `2px solid ${color}`, opacity: opacity * 1.5, }, square: { borderRadius: size * 0.15, background: color, opacity, }, squareOutline: { borderRadius: size * 0.15, background: 'transparent', border: `2px solid ${color}`, opacity: opacity * 1.5, }, dot: { borderRadius: '50%', background: color, opacity: opacity * 2, }, }; return ( ); } // Pre-configured shape combinations for common use cases export function ShapeCluster({ position = 'topRight', colors = ['#FF9500', '#764ba2'] }) { const positions = { topRight: { top: -20, right: -30 }, topLeft: { top: -20, left: -30 }, bottomRight: { bottom: -20, right: -30 }, bottomLeft: { bottom: -20, left: -30 }, }; const pos = positions[position]; return ( <> ); }