Spaces:
Running
Running
| "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> | |
| </> | |
| ); | |
| } | |