Make photo header animations consistent
This commit is contained in:
parent
bb1cf04218
commit
f1aa761221
@ -1,6 +1,6 @@
|
||||
import { Photo, PhotoDateRange } from '@/photo';
|
||||
import { pathForCameraShare } from '@/site/paths';
|
||||
import PhotoHeader from '@/photo/PhotoHeader';
|
||||
import PhotoSetHeader from '@/photo/PhotoSetHeader';
|
||||
import { Camera, cameraFromPhoto } from '.';
|
||||
import PhotoCamera from './PhotoCamera';
|
||||
import { descriptionForCameraPhotos } from './meta';
|
||||
@ -20,7 +20,7 @@ export default function CameraHeader({
|
||||
}) {
|
||||
const camera = cameraFromPhoto(photos[0], cameraProp);
|
||||
return (
|
||||
<PhotoHeader
|
||||
<PhotoSetHeader
|
||||
entity={<PhotoCamera {...{ camera }} />}
|
||||
entityVerb="Photo"
|
||||
entityDescription={
|
||||
|
||||
@ -1,59 +0,0 @@
|
||||
import { cc } from '@/utility/css';
|
||||
import { Photo, PhotoDateRange, dateRangeForPhotos } from '.';
|
||||
import ShareButton from '@/components/ShareButton';
|
||||
|
||||
export default function PhotoHeader({
|
||||
entity,
|
||||
entityVerb,
|
||||
entityDescription,
|
||||
photos,
|
||||
selectedPhoto,
|
||||
sharePath,
|
||||
count,
|
||||
dateRange,
|
||||
}: {
|
||||
entity: JSX.Element
|
||||
entityVerb: string
|
||||
entityDescription: string
|
||||
photos: Photo[]
|
||||
selectedPhoto?: Photo
|
||||
sharePath: string
|
||||
count?: number
|
||||
dateRange?: PhotoDateRange
|
||||
}) {
|
||||
const { start, end } = dateRangeForPhotos(photos, dateRange);
|
||||
|
||||
const selectedPhotoIndex = selectedPhoto
|
||||
? photos.findIndex(photo => photo.id === selectedPhoto.id)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<div className={cc(
|
||||
'flex flex-col gap-y-0.5',
|
||||
'xs:grid grid-cols-2 sm:grid-cols-4 md:grid-cols-3 lg:grid-cols-4',
|
||||
)}>
|
||||
{entity}
|
||||
<span className={cc(
|
||||
'inline-flex gap-2 items-center self-start',
|
||||
'uppercase text-dim',
|
||||
'sm:col-span-2 md:col-span-1 lg:col-span-2',
|
||||
)}>
|
||||
{selectedPhotoIndex !== undefined
|
||||
// eslint-disable-next-line max-len
|
||||
? `${entityVerb} ${selectedPhotoIndex + 1} of ${count ?? photos.length}`
|
||||
: entityDescription}
|
||||
{selectedPhotoIndex === undefined &&
|
||||
<ShareButton path={sharePath} dim />}
|
||||
</span>
|
||||
<span className={cc(
|
||||
'hidden sm:inline-block',
|
||||
'text-right uppercase',
|
||||
'text-dim',
|
||||
)}>
|
||||
{start === end
|
||||
? start
|
||||
: <>{start}<br />– {end}</>}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
68
src/photo/PhotoSetHeader.tsx
Normal file
68
src/photo/PhotoSetHeader.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import { cc } from '@/utility/css';
|
||||
import { Photo, PhotoDateRange, dateRangeForPhotos } from '.';
|
||||
import ShareButton from '@/components/ShareButton';
|
||||
import AnimateItems from '@/components/AnimateItems';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export default function PhotoSetHeader({
|
||||
entity,
|
||||
entityVerb,
|
||||
entityDescription,
|
||||
photos,
|
||||
selectedPhoto,
|
||||
sharePath,
|
||||
count,
|
||||
dateRange,
|
||||
}: {
|
||||
entity: ReactNode
|
||||
entityVerb: string
|
||||
entityDescription: string
|
||||
photos: Photo[]
|
||||
selectedPhoto?: Photo
|
||||
sharePath: string
|
||||
count?: number
|
||||
dateRange?: PhotoDateRange
|
||||
}) {
|
||||
const { start, end } = dateRangeForPhotos(photos, dateRange);
|
||||
|
||||
const selectedPhotoIndex = selectedPhoto
|
||||
? photos.findIndex(photo => photo.id === selectedPhoto.id)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<AnimateItems
|
||||
type="bottom"
|
||||
distanceOffset={10}
|
||||
animateOnFirstLoadOnly
|
||||
items={[<div
|
||||
key="PhotosHeader"
|
||||
className={cc(
|
||||
'flex flex-col gap-y-0.5',
|
||||
'xs:grid grid-cols-2 sm:grid-cols-4 md:grid-cols-3 lg:grid-cols-4',
|
||||
)}>
|
||||
{entity}
|
||||
<span className={cc(
|
||||
'inline-flex gap-2 items-center self-start',
|
||||
'uppercase text-dim',
|
||||
'sm:col-span-2 md:col-span-1 lg:col-span-2',
|
||||
)}>
|
||||
{selectedPhotoIndex !== undefined
|
||||
// eslint-disable-next-line max-len
|
||||
? `${entityVerb} ${selectedPhotoIndex + 1} of ${count ?? photos.length}`
|
||||
: entityDescription}
|
||||
{selectedPhotoIndex === undefined &&
|
||||
<ShareButton path={sharePath} dim />}
|
||||
</span>
|
||||
<span className={cc(
|
||||
'hidden sm:inline-block',
|
||||
'text-right uppercase',
|
||||
'text-dim',
|
||||
)}>
|
||||
{start === end
|
||||
? start
|
||||
: <>{start}<br />– {end}</>}
|
||||
</span>
|
||||
</div>]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -1,8 +1,7 @@
|
||||
import { Photo, PhotoDateRange } from '@/photo';
|
||||
import { FilmSimulation, descriptionForFilmSimulationPhotos } from '.';
|
||||
import { pathForFilmSimulationShare } from '@/site/paths';
|
||||
import PhotoHeader from '@/photo/PhotoHeader';
|
||||
import AnimateItems from '@/components/AnimateItems';
|
||||
import PhotoSetHeader from '@/photo/PhotoSetHeader';
|
||||
import PhotoFilmSimulation from
|
||||
'@/simulation/PhotoFilmSimulation';
|
||||
|
||||
@ -20,21 +19,16 @@ export default function FilmSimulationHeader({
|
||||
dateRange?: PhotoDateRange
|
||||
}) {
|
||||
return (
|
||||
<AnimateItems
|
||||
type="bottom"
|
||||
distanceOffset={10}
|
||||
items={[<PhotoHeader
|
||||
key="PhotoHeader"
|
||||
entity={<PhotoFilmSimulation {...{ simulation }} />}
|
||||
entityVerb="Photo"
|
||||
entityDescription={descriptionForFilmSimulationPhotos(
|
||||
photos, undefined, count, dateRange)}
|
||||
photos={photos}
|
||||
selectedPhoto={selectedPhoto}
|
||||
sharePath={pathForFilmSimulationShare(simulation)}
|
||||
count={count}
|
||||
dateRange={dateRange}
|
||||
/>]}
|
||||
<PhotoSetHeader
|
||||
entity={<PhotoFilmSimulation {...{ simulation }} />}
|
||||
entityVerb="Photo"
|
||||
entityDescription={descriptionForFilmSimulationPhotos(
|
||||
photos, undefined, count, dateRange)}
|
||||
photos={photos}
|
||||
selectedPhoto={selectedPhoto}
|
||||
sharePath={pathForFilmSimulationShare(simulation)}
|
||||
count={count}
|
||||
dateRange={dateRange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,8 +2,7 @@ import { Photo } from '@/photo';
|
||||
import PhotoTag from './PhotoTag';
|
||||
import { descriptionForTaggedPhotos } from '.';
|
||||
import { pathForTagShare } from '@/site/paths';
|
||||
import PhotoHeader from '@/photo/PhotoHeader';
|
||||
import AnimateItems from '@/components/AnimateItems';
|
||||
import PhotoSetHeader from '@/photo/PhotoSetHeader';
|
||||
|
||||
export default function TagHeader({
|
||||
tag,
|
||||
@ -17,19 +16,14 @@ export default function TagHeader({
|
||||
count?: number
|
||||
}) {
|
||||
return (
|
||||
<AnimateItems
|
||||
type="bottom"
|
||||
distanceOffset={10}
|
||||
items={[<PhotoHeader
|
||||
key="PhotoHeader"
|
||||
entity={<PhotoTag tag={tag} />}
|
||||
entityVerb="Tagged"
|
||||
entityDescription={descriptionForTaggedPhotos(photos, undefined, count)}
|
||||
photos={photos}
|
||||
selectedPhoto={selectedPhoto}
|
||||
sharePath={pathForTagShare(tag)}
|
||||
count={count}
|
||||
/>]}
|
||||
<PhotoSetHeader
|
||||
entity={<PhotoTag tag={tag} />}
|
||||
entityVerb="Tagged"
|
||||
entityDescription={descriptionForTaggedPhotos(photos, undefined, count)}
|
||||
photos={photos}
|
||||
selectedPhoto={selectedPhoto}
|
||||
sharePath={pathForTagShare(tag)}
|
||||
count={count}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user