'use client'; import { useState } from 'react'; import type { PointerEvent } from 'react'; type PreviewState = { left: number; top: number; width: number; }; function parseRatio(aspectRatio?: string) { if (!aspectRatio || aspectRatio === 'long') return aspectRatio === 'long' ? 1 / 3 : 1; const [w, h] = aspectRatio.includes('/') ? aspectRatio.split('/').map(part => Number(part.trim())) : aspectRatio.split(':').map(Number); return w && h ? w / h : 1; } function nextPreviewState(event: PointerEvent, aspectRatio?: string): PreviewState { const gap = 18; const margin = 12; const ratio = parseRatio(aspectRatio); const maxWidth = ratio < 0.8 ? 380 : ratio > 1.35 ? 620 : 500; const width = Math.min(maxWidth, Math.max(260, window.innerWidth * 0.38)); const height = Math.min(window.innerHeight * 0.82, width / ratio); let left = event.clientX + gap; let top = event.clientY + gap; if (left + width > window.innerWidth - margin) { left = event.clientX - width - gap; } if (top + height > window.innerHeight - margin) { top = window.innerHeight - height - margin; } return { left: Math.max(margin, left), top: Math.max(margin, top), width, }; } export function HoverImagePreview({ src, alt, imageClassName, aspectRatio, onImageLoad, }: { src: string; alt: string; imageClassName?: string; aspectRatio?: string; onImageLoad?: (image: HTMLImageElement) => void; }) { const [preview, setPreview] = useState(null); return ( <> {alt} { if (event.pointerType === 'touch') return; setPreview(nextPreviewState(event, aspectRatio)); }} onPointerLeave={() => setPreview(null)} onLoad={event => onImageLoad?.(event.currentTarget)} /> {preview && (
)} ); }