import { motion, useMotionValue, useSpring } from 'motion/react'; import { useRef, useState } from 'react'; const springValues = { damping: 30, stiffness: 100, mass: 2, }; export interface HoverTiltedCardProps { imageSrc: string altText?: string captionText?: string containerHeight?: string containerWidth?: string imageHeight?: string imageWidth?: string scaleOnHover?: number rotateAmplitude?: number showTooltip?: boolean overlayContent?: React.ReactNode displayOverlayContent?: boolean } export default function HoverTiltedCard ({ imageSrc, altText = 'NapCat', captionText = 'NapCat', containerHeight = '200px', containerWidth = '100%', imageHeight = '200px', imageWidth = '200px', scaleOnHover = 1.1, rotateAmplitude = 14, showTooltip = false, overlayContent = (
NapCat
), displayOverlayContent = true, }: HoverTiltedCardProps) { const ref = useRef(null); const x = useMotionValue(0); const y = useMotionValue(0); const rotateX = useSpring(useMotionValue(0), springValues); const rotateY = useSpring(useMotionValue(0), springValues); const scale = useSpring(1, springValues); const opacity = useSpring(0); const rotateFigcaption = useSpring(0, { stiffness: 350, damping: 30, mass: 1, }); const [lastY, setLastY] = useState(0); function handleMouse (e: React.MouseEvent) { if (!ref.current) return; const rect = ref.current.getBoundingClientRect(); const offsetX = e.clientX - rect.left - rect.width / 2; const offsetY = e.clientY - rect.top - rect.height / 2; const rotationX = (offsetY / (rect.height / 2)) * -rotateAmplitude; const rotationY = (offsetX / (rect.width / 2)) * rotateAmplitude; rotateX.set(rotationX); rotateY.set(rotationY); x.set(e.clientX - rect.left); y.set(e.clientY - rect.top); const velocityY = offsetY - lastY; rotateFigcaption.set(-velocityY * 0.6); setLastY(offsetY); } function handleMouseEnter () { scale.set(scaleOnHover); opacity.set(1); } function handleMouseLeave () { opacity.set(0); scale.set(1); rotateX.set(0); rotateY.set(0); rotateFigcaption.set(0); } return (
{displayOverlayContent && overlayContent && ( {overlayContent} )} {showTooltip && ( {captionText} )}
); }