75 lines
1.8 KiB
TypeScript
75 lines
1.8 KiB
TypeScript
"use client";
|
|
|
|
import { motion } from "framer-motion";
|
|
import { useMemo } from "react";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface SparklesCoreProps {
|
|
id?: string;
|
|
background?: string;
|
|
minSize?: number;
|
|
maxSize?: number;
|
|
speed?: number;
|
|
particleColor?: string;
|
|
particleDensity?: number;
|
|
className?: string;
|
|
}
|
|
|
|
const SparklesCore = ({
|
|
id,
|
|
background = "transparent",
|
|
minSize = 0.4,
|
|
maxSize = 1,
|
|
speed = 1,
|
|
particleColor = "#FFFFFF",
|
|
particleDensity = 500,
|
|
className,
|
|
}: SparklesCoreProps) => {
|
|
const particles = useMemo(() => {
|
|
const count = Math.min(particleDensity, 200);
|
|
return Array.from({ length: count }, (_, i) => ({
|
|
id: i,
|
|
x: Math.random() * 100,
|
|
y: Math.random() * 100,
|
|
size: minSize + Math.random() * (maxSize - minSize),
|
|
duration: 2 + Math.random() * 4,
|
|
delay: Math.random() * 2,
|
|
}));
|
|
}, [particleDensity, minSize, maxSize]);
|
|
|
|
return (
|
|
<div
|
|
id={id}
|
|
className={cn("absolute inset-0 h-full w-full", className)}
|
|
style={{ background }}
|
|
>
|
|
{particles.map((particle) => (
|
|
<motion.div
|
|
key={particle.id}
|
|
className="absolute rounded-full"
|
|
style={{
|
|
left: `${particle.x}%`,
|
|
top: `${particle.y}%`,
|
|
width: particle.size * 4,
|
|
height: particle.size * 4,
|
|
backgroundColor: particleColor,
|
|
boxShadow: `0 0 ${particle.size * 6}px ${particleColor}`,
|
|
}}
|
|
animate={{
|
|
opacity: [0, 1, 0],
|
|
scale: [0, 1, 0],
|
|
}}
|
|
transition={{
|
|
duration: particle.duration / speed,
|
|
repeat: Infinity,
|
|
delay: particle.delay,
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export { SparklesCore };
|