jeffemmett-website-redesign/components/cursor-effect.tsx

102 lines
2.7 KiB
TypeScript

'use client'
import { useEffect, useState } from 'react'
export function CursorEffect() {
const [position, setPosition] = useState({ x: -100, y: -100 })
const [isHovering, setIsHovering] = useState(false)
const [isVisible, setIsVisible] = useState(false)
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
setPosition({ x: e.clientX, y: e.clientY })
setIsVisible(true)
const target = e.target as HTMLElement
const isInteractive = target.closest('a, button, [role="button"], input, textarea')
setIsHovering(!!isInteractive)
}
const handleMouseLeave = () => {
setIsVisible(false)
}
window.addEventListener('mousemove', handleMouseMove)
document.addEventListener('mouseleave', handleMouseLeave)
return () => {
window.removeEventListener('mousemove', handleMouseMove)
document.removeEventListener('mouseleave', handleMouseLeave)
}
}, [])
if (!isVisible) return null
return (
<>
{/* Simple crosshair cursor */}
<div
className="pointer-events-none fixed z-[9999] mix-blend-difference"
style={{
left: position.x,
top: position.y,
transform: 'translate(-50%, -50%)',
}}
>
{/* Crosshair */}
<svg
width={isHovering ? 32 : 24}
height={isHovering ? 32 : 24}
viewBox="0 0 24 24"
className="transition-all duration-150"
style={{ opacity: 0.7 }}
>
{/* Horizontal line */}
<line
x1="4" y1="12" x2="10" y2="12"
stroke="currentColor"
strokeWidth="1.5"
className="text-blue-900"
/>
<line
x1="14" y1="12" x2="20" y2="12"
stroke="currentColor"
strokeWidth="1.5"
className="text-blue-900"
/>
{/* Vertical line */}
<line
x1="12" y1="4" x2="12" y2="10"
stroke="currentColor"
strokeWidth="1.5"
className="text-blue-900"
/>
<line
x1="12" y1="14" x2="12" y2="20"
stroke="currentColor"
strokeWidth="1.5"
className="text-blue-900"
/>
{/* Center dot */}
<circle
cx="12" cy="12" r="2"
fill="currentColor"
className="text-blue-900"
/>
</svg>
</div>
{/* Subtle trailing dot */}
<div
className="pointer-events-none fixed z-[9998] w-1 h-1 rounded-full bg-blue-400/30"
style={{
left: position.x,
top: position.y,
transform: 'translate(-50%, -50%)',
transition: 'left 0.15s ease-out, top 0.15s ease-out',
}}
/>
</>
)
}