40 lines
1.0 KiB
TypeScript
40 lines
1.0 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
interface MeteorItem {
|
|
id: number;
|
|
left: string;
|
|
delay: string;
|
|
duration: string;
|
|
}
|
|
|
|
export function Meteors({ number = 15 }: { number?: number }) {
|
|
const [items, setItems] = useState<MeteorItem[]>([]);
|
|
|
|
useEffect(() => {
|
|
setItems(
|
|
Array.from({ length: number }, (_, i) => ({
|
|
id: i,
|
|
left: `${Math.random() * 100}%`,
|
|
delay: `${(Math.random() * 3).toFixed(2)}s`,
|
|
duration: `${(Math.random() * 6 + 4).toFixed(1)}s`,
|
|
}))
|
|
);
|
|
}, [number]);
|
|
|
|
return (
|
|
<>
|
|
{items.map((m) => (
|
|
<span
|
|
key={m.id}
|
|
className="pointer-events-none absolute top-0 size-px rotate-[215deg] animate-meteor rounded-full bg-white/70 shadow-[0_0_0_1px_rgba(255,255,255,0.08)]"
|
|
style={{ left: m.left, animationDelay: m.delay, animationDuration: m.duration }}
|
|
>
|
|
<span className="absolute top-1/2 left-0 -translate-y-1/2 h-px w-20 bg-gradient-to-r from-white/60 to-transparent" />
|
|
</span>
|
|
))}
|
|
</>
|
|
);
|
|
}
|