feat: initialize reactjs project using vite
This commit is contained in:
74
src/components/layout/CustomCursor.tsx
Normal file
74
src/components/layout/CustomCursor.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import styles from './CustomCursor.module.css';
|
||||
|
||||
export function CustomCursor() {
|
||||
const [position, setPosition] = useState({ x: 0, y: 0 });
|
||||
const [isPointer, setIsPointer] = useState(false);
|
||||
const [isHidden, setIsHidden] = useState(true);
|
||||
const [isClicking, setIsClicking] = useState(false);
|
||||
|
||||
const handleMouseMove = useCallback((e: MouseEvent) => {
|
||||
setPosition({ x: e.clientX, y: e.clientY });
|
||||
setIsHidden(false);
|
||||
|
||||
const target = e.target as HTMLElement;
|
||||
const isClickable =
|
||||
target.tagName === 'A' ||
|
||||
target.tagName === 'BUTTON' ||
|
||||
!!target.closest('a') ||
|
||||
!!target.closest('button') ||
|
||||
window.getComputedStyle(target).cursor === 'pointer';
|
||||
|
||||
setIsPointer(isClickable);
|
||||
}, []);
|
||||
|
||||
const handleMouseDown = useCallback(() => setIsClicking(true), []);
|
||||
const handleMouseUp = useCallback(() => setIsClicking(false), []);
|
||||
const handleMouseLeave = useCallback(() => setIsHidden(true), []);
|
||||
const handleMouseEnter = useCallback(() => setIsHidden(false), []);
|
||||
|
||||
useEffect(() => {
|
||||
// Don't show custom cursor on touch devices
|
||||
if (window.matchMedia('(hover: none)').matches) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mousedown', handleMouseDown);
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
document.addEventListener('mouseleave', handleMouseLeave);
|
||||
document.addEventListener('mouseenter', handleMouseEnter);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mousedown', handleMouseDown);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
document.removeEventListener('mouseleave', handleMouseLeave);
|
||||
document.removeEventListener('mouseenter', handleMouseEnter);
|
||||
};
|
||||
}, [handleMouseMove, handleMouseDown, handleMouseUp, handleMouseLeave, handleMouseEnter]);
|
||||
|
||||
// Don't render on touch devices
|
||||
if (typeof window !== 'undefined' && window.matchMedia('(hover: none)').matches) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`${styles.cursor} ${isPointer ? styles.pointer : ''} ${isHidden ? styles.hidden : ''} ${isClicking ? styles.clicking : ''}`}
|
||||
style={{
|
||||
left: position.x,
|
||||
top: position.y,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className={`${styles.cursorDot} ${isHidden ? styles.hidden : ''}`}
|
||||
style={{
|
||||
left: position.x,
|
||||
top: position.y,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user