| import { useEffect, useState } from 'react'; |
| import { motion, useSpring, useMotionValue } from 'motion/react'; |
|
|
| export default function MouseFollower() { |
| const mouseX = useMotionValue(0); |
| const mouseY = useMotionValue(0); |
|
|
| const springConfig = { damping: 25, stiffness: 150 }; |
| const cursorX = useSpring(mouseX, springConfig); |
| const cursorY = useSpring(mouseY, springConfig); |
|
|
| const [isVisible, setIsVisible] = useState(false); |
| const [isMobile, setIsMobile] = useState(true); |
|
|
| useEffect(() => { |
| const checkMobile = () => { |
| const isTouch = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0); |
| setIsMobile(isTouch || window.innerWidth < 768); |
| }; |
| checkMobile(); |
| window.addEventListener('resize', checkMobile); |
|
|
| const handleMouseMove = (e: MouseEvent) => { |
| if (isMobile) return; |
| mouseX.set(e.clientX); |
| mouseY.set(e.clientY); |
| if (!isVisible) setIsVisible(true); |
| }; |
|
|
| const handleMouseLeave = () => { |
| setIsVisible(false); |
| }; |
|
|
| const handleMouseEnter = () => { |
| setIsVisible(true); |
| }; |
|
|
| window.addEventListener('mousemove', handleMouseMove); |
| document.addEventListener('mouseleave', handleMouseLeave); |
| document.addEventListener('mouseenter', handleMouseEnter); |
|
|
| return () => { |
| window.removeEventListener('resize', checkMobile); |
| window.removeEventListener('mousemove', handleMouseMove); |
| document.removeEventListener('mouseleave', handleMouseLeave); |
| document.removeEventListener('mouseenter', handleMouseEnter); |
| }; |
| }, [mouseX, mouseY, isVisible, isMobile]); |
|
|
| if (isMobile) return null; |
|
|
| return ( |
| <> |
| <motion.div |
| className="fixed top-0 left-0 w-8 h-8 rounded-full border border-primary/30 pointer-events-none z-[9999] mix-blend-difference" |
| style={{ |
| x: cursorX, |
| y: cursorY, |
| translateX: '-50%', |
| translateY: '-50%', |
| opacity: isVisible ? 1 : 0, |
| }} |
| /> |
| <motion.div |
| className="fixed top-0 left-0 w-1.5 h-1.5 rounded-full bg-primary pointer-events-none z-[9999]" |
| style={{ |
| x: mouseX, |
| y: mouseY, |
| translateX: '-50%', |
| translateY: '-50%', |
| opacity: isVisible ? 1 : 0, |
| }} |
| /> |
| </> |
| ); |
| } |
|
|