Vercel/src/photo/PhotoMedium.tsx
2025-08-26 20:36:51 -05:00

88 lines
2.4 KiB
TypeScript

'use client';
import {
Photo,
altTextForPhoto,
doesPhotoNeedBlurCompatibility,
} from '.';
import { PhotoSetCategory } from '../category';
import ImageMedium from '@/components/image/ImageMedium';
import { clsx } from 'clsx/lite';
import { pathForPhoto } from '@/app/path';
import { SHOULD_PREFETCH_ALL_LINKS } from '@/app/config';
import { useRef } from 'react';
import useVisibility from '@/utility/useVisibility';
import LinkWithStatus from '@/components/LinkWithStatus';
import Spinner from '@/components/Spinner';
import PhotoColors from './color/PhotoColors';
export default function PhotoMedium({
photo,
selected,
priority,
prefetch = SHOULD_PREFETCH_ALL_LINKS,
className,
onVisible,
debugColor,
...categories
}: {
photo: Photo
selected?: boolean
priority?: boolean
prefetch?: boolean
className?: string
onVisible?: () => void
debugColor?: boolean
} & PhotoSetCategory) {
const ref = useRef<HTMLAnchorElement>(null);
useVisibility({ ref, onVisible });
return (
<LinkWithStatus
ref={ref}
href={pathForPhoto({ photo, ...categories })}
className={clsx(
'group',
'active:brightness-75',
selected && 'brightness-50',
className,
)}
prefetch={prefetch}
>
{({ isLoading }) =>
<div className="w-full h-full">
{isLoading &&
<div className={clsx(
'absolute inset-0 flex items-center justify-center',
'text-white bg-black/25 backdrop-blur-xs',
'animate-fade-in',
'z-10',
)}>
<Spinner size={20} color="text" />
</div>}
{debugColor && photo.colorData &&
<div className={clsx(
'absolute inset-2 z-10',
'opacity-0 group-hover:opacity-100 transition-opacity',
)}>
<PhotoColors
className="justify-end"
colorData={photo.colorData}
/>
</div>}
<ImageMedium
src={photo.url}
aspectRatio={photo.aspectRatio}
blurDataURL={photo.blurData}
blurCompatibilityMode={doesPhotoNeedBlurCompatibility(photo)}
className="flex object-cover w-full h-full"
classNameImage="object-cover w-full h-full"
alt={altTextForPhoto(photo)}
priority={priority}
/>
</div>}
</LinkWithStatus>
);
};