diff --git a/src/components/Firework.tsx b/src/components/Firework.tsx new file mode 100644 index 0000000..929b505 --- /dev/null +++ b/src/components/Firework.tsx @@ -0,0 +1,93 @@ +import { useState, useEffect, useCallback } from 'react'; + +interface Particle { + id: number; + angle: number; + color: string; + distance: number; + opacity: number; + x: number; + y: number; +} + +export default function Firework() { + const [particles, setParticles] = useState([]); + + const getRandomPosition = (): { x: number; y: number } => { + // Get container dimensions (in percentage to be responsive) + return { + x: Math.random() * 100, // Random position from 0% to 100% of container width + y: Math.random() * 70 + 15, // Random position from 15% to 85% of container height + }; + }; + + const createParticles = useCallback((): Particle[] => { + const particleCount = 30; + const colors = ['red', 'gold', 'blue', 'green', 'purple', 'pink']; + const position = getRandomPosition(); + + return Array.from({ length: particleCount }, (_, i) => ({ + id: Date.now() + i, + angle: (i * 360) / particleCount, + color: colors[Math.floor(Math.random() * colors.length)], + distance: 0, + opacity: 1, + x: position.x, + y: position.y, + })); + }, []); + + const explode = useCallback(() => { + const newParticles = createParticles(); + setParticles(prev => [...prev, ...newParticles]); + + setTimeout(() => { + setParticles(prev => prev.filter(p => p.id !== newParticles[0].id)); + }, 500); + }, [createParticles]); + + // Automatic firework launcher + useEffect(() => { + const launchInterval = setInterval(() => { + explode(); + }, 2000); // Launch a new firework every 2 seconds + + return () => clearInterval(launchInterval); + }, [explode]); + + // Particle animation + useEffect(() => { + if (particles.length > 0) { + const animationInterval = setInterval(() => { + setParticles(prev => + prev.map(particle => ({ + ...particle, + distance: particle.distance + 2, + opacity: particle.opacity - 0.02 + })) + ); + }, 20); + + return () => clearInterval(animationInterval); + } + }, [particles.length]); + + return ( +
+ {particles.map(particle => ( +
+ ))} +
+ ); +} \ No newline at end of file diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 4aa1037..77d99ef 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -1,6 +1,6 @@ import Header from "./Header" import Footer from "./Footer" -import Snow from "./Snow" +import Firework from "./Firework"; import { useState, useEffect, useCallback } from 'react'; export default function Layout({ @@ -49,7 +49,7 @@ export default function Layout({ return (
- + {children}