40 lines
1.1 KiB
TypeScript
40 lines
1.1 KiB
TypeScript
"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>
|
|
);
|
|
}
|