first commit

This commit is contained in:
mstfyldz
2026-06-03 04:27:40 +03:00
parent dcfaf2723c
commit 48277fe8d2
22 changed files with 1610 additions and 117 deletions
+39
View File
@@ -0,0 +1,39 @@
"use client";
import { useCallback, useRef, useState } from "react";
interface MagicCardProps {
children: React.ReactNode;
className?: string;
}
export function MagicCard({ children, className = "" }: MagicCardProps) {
const ref = useRef<HTMLDivElement>(null);
const [pos, setPos] = useState({ x: -999, y: -999 });
const [hovered, setHovered] = useState(false);
const onMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
if (!ref.current) return;
const rect = ref.current.getBoundingClientRect();
setPos({ x: e.clientX - rect.left, y: e.clientY - rect.top });
}, []);
return (
<div
ref={ref}
onMouseMove={onMouseMove}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => { setHovered(false); setPos({ x: -999, y: -999 }); }}
className={className}
>
{children}
<div
className="pointer-events-none absolute inset-0 z-20 transition-opacity duration-500"
style={{
opacity: hovered ? 1 : 0,
background: `radial-gradient(350px circle at ${pos.x}px ${pos.y}px, rgba(200,133,58,0.10), transparent 60%)`,
}}
/>
</div>
);
}
+39
View File
@@ -0,0 +1,39 @@
"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>
))}
</>
);
}