Portfolio / src /components /MouseFollower.tsx
teganmosi
Initial commit of portfolio
4dd77d6
Raw
History Blame Contribute Delete
2.3 kB
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,
}}
/>
</>
);
}