Introduce loading status to thumbnails

This commit is contained in:
Sam Becker 2025-01-20 13:11:27 -06:00
parent e1055e0c79
commit c7576b43ac
2 changed files with 15 additions and 6 deletions

View File

@ -17,10 +17,15 @@ const FLICKER_THRESHOLD = 400;
// Clear loading status after long duration
const MAX_LOADING_DURATION = 15_000;
export type LinkWithStatusProps = ComponentProps<typeof Link> & {
export type LinkWithStatusProps = Omit<
ComponentProps<typeof Link>, 'children'
> & {
loadingElement?: ReactNode
loadingClassName?: string
contentClassName?: string
children: ReactNode | ((props: {
isLoading: boolean
}) => ReactNode)
}
export default function LinkWithStatus({
@ -44,6 +49,8 @@ export default function LinkWithStatus({
const stopLoadingTimeout = useRef<NodeJS.Timeout | undefined>(undefined);
const maxLoadingTimeout = useRef<NodeJS.Timeout | undefined>(undefined);
const isControlled = typeof children === 'function';
const clearTimeouts = useCallback(() => {
[startLoadingTimeout, stopLoadingTimeout, maxLoadingTimeout]
.forEach(timeout => {
@ -114,11 +121,13 @@ export default function LinkWithStatus({
contentClassName,
loadingElement
? isLoading ? 'opacity-0' : 'opacity-100'
: loadingClassName
: (loadingClassName || isControlled)
? 'opacity-100'
: isLoading ? 'opacity-50' : 'opacity-100',
)}>
{children}
{typeof children === 'function'
? children({ isLoading })
: children}
</span>
{isLoading && loadingElement && <span className={clsx(
'absolute inset-0',

View File

@ -7,12 +7,12 @@ import {
doesPhotoNeedBlurCompatibility,
} from '.';
import ImageMedium from '@/components/image/ImageMedium';
import Link from 'next/link';
import { clsx } from 'clsx/lite';
import { pathForPhoto } from '@/site/paths';
import { SHOULD_PREFETCH_ALL_LINKS } from '@/site/config';
import { useRef } from 'react';
import useOnVisible from '@/utility/useOnVisible';
import LinkWithStatus from '@/components/LinkWithStatus';
export default function PhotoMedium({
photo,
@ -38,7 +38,7 @@ export default function PhotoMedium({
useOnVisible(ref, onVisible);
return (
<Link
<LinkWithStatus
ref={ref}
href={pathForPhoto({ photo, tag, camera, simulation, focal })}
className={clsx(
@ -58,6 +58,6 @@ export default function PhotoMedium({
alt={altTextForPhoto(photo)}
priority={priority}
/>
</Link>
</LinkWithStatus>
);
};