Spotix-API / frontend /components /shared /CustomCursor.tsx
Anish
[UI/UX] Features and good animations added
67264dd
"use client";
import React, { useEffect } from 'react';
import { usePathname } from 'next/navigation';
export default function CustomCursor() {
const pathname = usePathname();
useEffect(() => {
const cursor = document.getElementById('global-custom-cursor');
if (!cursor) return;
const handleMouseMove = (e: MouseEvent) => {
// Use translation for better performance on wrapper
cursor.style.transform = `translate3d(${e.clientX}px, ${e.clientY}px, 0)`;
if (!cursor.classList.contains('cursor-visible')) {
cursor.classList.add('cursor-visible');
}
};
const handleMouseOver = (e: MouseEvent) => {
const target = (e.target as HTMLElement).closest('a, button, [role="button"], input, select, textarea, .group, .cursor-pointer, label, .dash-border, .tilt-card, #drop-zone, .menu-link, .recharts-surface, .recharts-wrapper, .recharts-default-tooltip');
if (target) {
cursor.classList.add('cursor-hover');
}
};
const handleMouseOut = (e: MouseEvent) => {
const target = (e.target as HTMLElement).closest('a, button, [role="button"], input, select, textarea, .group, .cursor-pointer, label, .dash-border, .tilt-card, #drop-zone, .menu-link, .recharts-surface, .recharts-wrapper, .recharts-default-tooltip');
if (target) {
cursor.classList.remove('cursor-hover');
}
};
const handleMouseLeave = () => {
cursor.classList.remove('cursor-visible');
};
const handleMouseEnter = () => {
cursor.classList.add('cursor-visible');
};
window.addEventListener('mousemove', handleMouseMove);
document.documentElement.addEventListener('mouseleave', handleMouseLeave);
document.documentElement.addEventListener('mouseenter', handleMouseEnter);
document.addEventListener('mouseover', handleMouseOver);
document.addEventListener('mouseout', handleMouseOut);
// Force cursor re-evaluation on path change
cursor.classList.remove('cursor-hover');
return () => {
window.removeEventListener('mousemove', handleMouseMove);
document.documentElement.removeEventListener('mouseleave', handleMouseLeave);
document.documentElement.removeEventListener('mouseenter', handleMouseEnter);
document.removeEventListener('mouseover', handleMouseOver);
document.removeEventListener('mouseout', handleMouseOut);
};
}, [pathname]);
return (
<>
<style dangerouslySetInnerHTML={{
__html: `
.inverted-cursor-wrapper {
position: fixed; top: 0; left: 0; pointer-events: none; z-index: 99999; mix-blend-mode: difference;
}
.inverted-cursor-inner {
width: 40px; height: 40px; background-color: #fde8d6;;
border-radius: 50%; opacity: 0; transition: opacity 0.3s ease, transform 0.2s cubic-bezier(0.23, 1, 0.32, 1);
transform-origin: center center; margin-top: -20px; margin-left: -20px;
}
.inverted-cursor-wrapper.cursor-visible .inverted-cursor-inner { opacity: 1; }
.inverted-cursor-wrapper.cursor-hover .inverted-cursor-inner { transform: scale(1.5); }
@media (max-width: 768px) {
.inverted-cursor-wrapper { display: none !important; }
}
`
}} />
<div id="global-custom-cursor" className="inverted-cursor-wrapper hidden md:block">
<div className="inverted-cursor-inner"></div>
</div>
</>
);
}