49 lines
1.5 KiB
TypeScript
49 lines
1.5 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useRef } from "react";
|
|
import { gsap } from "gsap";
|
|
|
|
export default function Cursor() {
|
|
const dot = useRef<HTMLDivElement>(null);
|
|
const ring = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
if (window.matchMedia("(pointer: coarse)").matches) return;
|
|
if (!dot.current || !ring.current) return;
|
|
|
|
const xD = gsap.quickTo(dot.current, "x", { duration: 0.15, ease: "power3" });
|
|
const yD = gsap.quickTo(dot.current, "y", { duration: 0.15, ease: "power3" });
|
|
const xR = gsap.quickTo(ring.current, "x", { duration: 0.5, ease: "power3" });
|
|
const yR = gsap.quickTo(ring.current, "y", { duration: 0.5, ease: "power3" });
|
|
|
|
const move = (e: MouseEvent) => {
|
|
xD(e.clientX);
|
|
yD(e.clientY);
|
|
xR(e.clientX);
|
|
yR(e.clientY);
|
|
};
|
|
|
|
const over = (e: Event) => {
|
|
if ((e.target as HTMLElement).closest("a,button,.hoverable")) {
|
|
ring.current?.classList.add("cursor-ring--big");
|
|
}
|
|
};
|
|
const out = () => ring.current?.classList.remove("cursor-ring--big");
|
|
|
|
window.addEventListener("mousemove", move);
|
|
document.addEventListener("mouseover", over);
|
|
document.addEventListener("mouseout", out);
|
|
return () => {
|
|
window.removeEventListener("mousemove", move);
|
|
document.removeEventListener("mouseover", over);
|
|
document.removeEventListener("mouseout", out);
|
|
};
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<div ref={ring} className="cursor-ring" aria-hidden />
|
|
<div ref={dot} className="cursor-dot" aria-hidden />
|
|
</>
|
|
);
|
|
}
|