79 lines
2.3 KiB
TypeScript
79 lines
2.3 KiB
TypeScript
"use client";
|
|
|
|
import { useRef, useEffect, FC, useState } from "react";
|
|
import gsap from "gsap";
|
|
|
|
const GSAPCursor: FC = () => {
|
|
const cursorRef = useRef<HTMLDivElement>(null);
|
|
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
const [isHoveringLink, setIsHoveringLink] = useState(false);
|
|
|
|
// For touch devices, return null
|
|
if (typeof window !== "undefined" && "ontouchstart" in window) return null;
|
|
|
|
useEffect(() => {
|
|
// Initialize GSAP animation
|
|
let xTo = gsap.quickTo(cursorRef.current, "x", {
|
|
duration: 2,
|
|
ease: "power2.out",
|
|
});
|
|
let yTo = gsap.quickTo(cursorRef.current, "y", {
|
|
duration: 2,
|
|
ease: "power2.out",
|
|
});
|
|
|
|
const onMouseMove = (e: MouseEvent) => {
|
|
xTo(e.clientX);
|
|
yTo(e.clientY);
|
|
};
|
|
|
|
window.addEventListener("mousemove", onMouseMove);
|
|
|
|
const handleMouseOver = () => setIsHoveringLink(true);
|
|
const handleMouseOut = () => setIsHoveringLink(false);
|
|
|
|
const links = document.querySelectorAll('a');
|
|
links.forEach(link => {
|
|
link.addEventListener('mouseover', handleMouseOver);
|
|
link.addEventListener('mouseout', handleMouseOut);
|
|
});
|
|
|
|
return () => {
|
|
links.forEach(link => {
|
|
link.removeEventListener('mouseover', handleMouseOver);
|
|
link.removeEventListener('mouseout', handleMouseOut);
|
|
});
|
|
window.removeEventListener("mousemove", onMouseMove);
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const handleMouseMove = (e: MouseEvent) => {
|
|
setPosition({ x: e.clientX, y: e.clientY });
|
|
};
|
|
window.addEventListener("mousemove", handleMouseMove);
|
|
return () => window.removeEventListener("mousemove", handleMouseMove);
|
|
}, []);
|
|
|
|
return (
|
|
<div>
|
|
<div
|
|
ref={cursorRef}
|
|
className={`fixed w-8 h-8 ${isHoveringLink ? 'rounded-none' : 'rounded-full'} border-2 border-dotted border-red-500 bg-transparent pointer-events-none z-60`}
|
|
style={{
|
|
transform: "translate(-50%, -50%)",
|
|
}}
|
|
/>
|
|
<div
|
|
className="fixed w-2 h-2 rounded-full bg-black dark:bg-white pointer-events-none z-60"
|
|
style={{
|
|
left: `${position.x}px`,
|
|
top: `${position.y}px`,
|
|
transform: "translate(-50%, -50%)", // Centers the dot on the cursor
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default GSAPCursor;
|