2026-07-14 14:31:41 +05:30

87 lines
2.6 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { motion, useMotionValue, useSpring } from "framer-motion";
export default function CustomCursor() {
const [isHovered, setIsHovered] = useState(false);
// Motion values for smooth cursor tracking
const cursorX = useMotionValue(-100);
const cursorY = useMotionValue(-100);
// Spring physics for trailing effect on the outer circle
const springConfig = { damping: 30, stiffness: 220, mass: 0.6 };
const cursorXSpring = useSpring(cursorX, springConfig);
const cursorYSpring = useSpring(cursorY, springConfig);
useEffect(() => {
const moveCursor = (e: MouseEvent) => {
cursorX.set(e.clientX);
cursorY.set(e.clientY);
};
const handleMouseOver = (e: MouseEvent) => {
const target = e.target as HTMLElement;
if (
target.tagName === "A" ||
target.tagName === "BUTTON" ||
target.closest("a") ||
target.closest("button") ||
target.classList.contains("clickable") ||
target.closest(".clickable")
) {
setIsHovered(true);
} else {
setIsHovered(false);
}
};
window.addEventListener("mousemove", moveCursor);
window.addEventListener("mouseover", handleMouseOver);
return () => {
window.removeEventListener("mousemove", moveCursor);
window.removeEventListener("mouseover", handleMouseOver);
};
}, [cursorX, cursorY]);
return (
<div className="custom-cursor-container pointer-events-none fixed inset-0 z-[9999] hidden lg:block">
{/* Outer Spring Ring */}
<motion.div
className="custom-cursor pointer-events-none fixed left-0 top-0"
style={{
x: cursorXSpring,
y: cursorYSpring,
translateX: "-50%",
translateY: "-50%",
}}
animate={{
width: isHovered ? 64 : 24,
height: isHovered ? 64 : 24,
backgroundColor: isHovered ? "rgba(212, 175, 55, 0.15)" : "rgba(212, 175, 55, 0)",
borderColor: isHovered ? "#F3E5AB" : "#D4AF37",
boxShadow: isHovered ? "0 0 20px rgba(225, 177, 44, 0.4)" : "none",
}}
transition={{ type: "tween", ease: "backOut", duration: 0.2 }}
/>
{/* Inner Pinpoint Dot */}
<motion.div
className="custom-cursor-dot pointer-events-none fixed left-0 top-0"
style={{
x: cursorX,
y: cursorY,
translateX: "-50%",
translateY: "-50%",
}}
animate={{
scale: isHovered ? 0 : 1,
backgroundColor: isHovered ? "#F3E5AB" : "#D4AF37",
}}
transition={{ duration: 0.1 }}
/>
</div>
);
}