| 485 | * ``` |
| 486 | */ |
| 487 | const Preview = ({ src, alt = '', width = 240, height, loop = true, className }: PreviewProps) => { |
| 488 | const pathname = src.toLowerCase().split('?')[0].split('#')[0] |
| 489 | const isVideo = VIDEO_EXTENSIONS.some((ext) => pathname.endsWith(ext)) |
| 490 | const [isReady, setIsReady] = React.useState(!isVideo) |
| 491 | |
| 492 | return ( |
| 493 | <div className={cn('-mx-[6px] -mb-[1.5px] mt-1.5 overflow-hidden rounded-[4px]', className)}> |
| 494 | {isVideo ? ( |
| 495 | <div className='relative'> |
| 496 | {!isReady && ( |
| 497 | <div |
| 498 | className='animate-pulse bg-white/5' |
| 499 | style={{ aspectRatio: height ? `${width}/${height}` : '16/9' }} |
| 500 | /> |
| 501 | )} |
| 502 | <video |
| 503 | src={src} |
| 504 | width={width} |
| 505 | height={height} |
| 506 | className={cn( |
| 507 | 'block w-full transition-opacity duration-200', |
| 508 | isReady ? 'opacity-100' : 'absolute inset-0 opacity-0' |
| 509 | )} |
| 510 | autoPlay |
| 511 | loop={loop} |
| 512 | muted |
| 513 | playsInline |
| 514 | preload='auto' |
| 515 | aria-label={alt} |
| 516 | onCanPlay={() => setIsReady(true)} |
| 517 | /> |
| 518 | </div> |
| 519 | ) : ( |
| 520 | <img |
| 521 | src={src} |
| 522 | alt={alt} |
| 523 | width={width} |
| 524 | height={height} |
| 525 | className='block w-full' |
| 526 | loading='lazy' |
| 527 | /> |
| 528 | )} |
| 529 | </div> |
| 530 | ) |
| 531 | } |
| 532 | Preview.displayName = 'Tooltip.Preview' |
| 533 | |
| 534 | export const Tooltip = { |