Create navigation-based photo header

This commit is contained in:
Sam Becker 2024-08-26 09:19:14 -05:00
parent 76c02ee015
commit 6be23effc7
3 changed files with 72 additions and 35 deletions

View File

@ -3,8 +3,7 @@ import { Photo, PhotoDateRange } from '.';
import PhotoLarge from './PhotoLarge';
import SiteGrid from '@/components/SiteGrid';
import PhotoGrid from './PhotoGrid';
import { clsx } from 'clsx/lite';
import PhotoLinks from './PhotoLinks';
import PhotoNav from './PhotoNav';
import TagHeader from '@/tag/TagHeader';
import { Camera } from '@/camera';
import CameraHeader from '@/camera/CameraHeader';
@ -102,6 +101,24 @@ export default function PhotoDetailPage({
dateRange={dateRange}
/>}
/>}
<AnimateItems
animateOnFirstLoadOnly
items={[
<SiteGrid
key="photo-nav"
className="mb-4"
contentMain={<PhotoNav {...{
photo,
photos,
className: 'border-t border-gray-100 pt-4',
tag,
camera,
simulation,
focal,
}} />}
/>,
]}
/>
<AnimateItems
className="md:mb-8"
animateFromAppState
@ -112,6 +129,7 @@ export default function PhotoDetailPage({
primaryTag={tag}
priority
prefetchRelatedLinks
showTitle={false}
showCamera={!camera}
showSimulation={!simulation}
shouldShare={shouldShare}
@ -134,30 +152,6 @@ export default function PhotoDetailPage({
focal={focal}
animateOnFirstLoadOnly
/>}
contentSide={<AnimateItems
animateOnFirstLoadOnly
type="bottom"
items={[
<div
key="PhotoLinks"
className={clsx(
'grid grid-cols-2',
'gap-0.5 sm:gap-1',
'md:flex md:gap-4',
'user-select-none',
)}
>
<PhotoLinks {...{
photo,
photos,
tag,
camera,
simulation,
focal,
}} />
</div>,
]}
/>}
/>
</div>
);

View File

@ -38,11 +38,13 @@ import { useAppState } from '@/state/AppState';
export default function PhotoLarge({
photo,
className,
primaryTag,
priority,
prefetch = SHOULD_PREFETCH_ALL_LINKS,
prefetchRelatedLinks = SHOULD_PREFETCH_ALL_LINKS,
revalidatePhoto,
showTitle = true,
showCamera = true,
showSimulation = true,
shouldShare = true,
@ -55,11 +57,13 @@ export default function PhotoLarge({
onVisible,
}: {
photo: Photo
className?: string
primaryTag?: string
priority?: boolean
prefetch?: boolean
prefetchRelatedLinks?: boolean
revalidatePhoto?: RevalidatePhoto
showTitle?: boolean
showCamera?: boolean
showSimulation?: boolean
shouldShare?: boolean
@ -85,10 +89,14 @@ export default function PhotoLarge({
const { arePhotosMatted, isUserSignedIn } = useAppState();
const hasTitle = showTitle && (
Boolean(photo.title) ||
SHOW_PHOTO_TITLE_FALLBACK_TEXT
);
const hasTitleContent =
photo.title ||
SHOW_PHOTO_TITLE_FALLBACK_TEXT ||
photo.caption;
hasTitle ||
Boolean(photo.caption);
const hasMetaContent =
showCameraContent ||
@ -102,6 +110,7 @@ export default function PhotoLarge({
return (
<SiteGrid
containerRef={ref}
className={className}
contentMain={
<Link
href={pathForPhoto({ photo })}
@ -141,7 +150,7 @@ export default function PhotoLarge({
{/* Meta */}
<div className="pr-2 md:pr-0">
<div className="md:relative flex gap-2 items-start">
{(photo.title || SHOW_PHOTO_TITLE_FALLBACK_TEXT) &&
{hasTitle &&
<PhotoLink
photo={photo}
className="font-bold uppercase flex-grow"

View File

@ -9,26 +9,33 @@ import { useAppState } from '@/state/AppState';
import { AnimationConfig } from '@/components/AnimateItems';
import { Camera } from '@/camera';
import { FilmSimulation } from '@/simulation';
import { SHOW_PHOTO_TITLE_FALLBACK_TEXT } from '@/site/config';
import { BiChevronLeft, BiChevronRight } from 'react-icons/bi';
import { clsx } from 'clsx/lite';
const LISTENER_KEYUP = 'keyup';
const ANIMATION_LEFT: AnimationConfig = { type: 'left', duration: 0.3 };
const ANIMATION_RIGHT: AnimationConfig = { type: 'right', duration: 0.3 };
export default function PhotoLinks({
export default function PhotoNav({
photo,
photos,
className,
tag,
camera,
simulation,
focal,
prefetch,
}: {
photo: Photo
photos: Photo[]
className?: string
tag?: string
camera?: Camera
simulation?: FilmSimulation
focal?: number
prefetch?: boolean
}) {
const router = useRouter();
@ -94,7 +101,10 @@ export default function PhotoLinks({
]);
return (
<>
<div className={clsx(
'flex items-center',
className,
)}>
<PhotoLink
photo={previousPhoto}
nextPhotoAnimation={ANIMATION_RIGHT}
@ -105,8 +115,24 @@ export default function PhotoLinks({
scroll={false}
prefetch
>
PREV
<span className="group inline-flex gap-1 items-center">
<BiChevronLeft
className={clsx(
'text-[1.25rem] transition-transform',
'group-hover:-translate-x-1',
)}
/>
PREV
</span>
</PhotoLink>
<div className="grow text-center">
{(photo.title || SHOW_PHOTO_TITLE_FALLBACK_TEXT) &&
<PhotoLink
photo={photo}
className="uppercase font-bold"
prefetch={prefetch}
/>}
</div>
<PhotoLink
photo={nextPhoto}
nextPhotoAnimation={ANIMATION_LEFT}
@ -117,8 +143,16 @@ export default function PhotoLinks({
scroll={false}
prefetch
>
NEXT
<span className="group inline-flex gap-1 items-center">
NEXT
<BiChevronRight
className={clsx(
'text-[1.25rem] transition-transform',
'group-hover:translate-x-1',
)}
/>
</span>
</PhotoLink>
</>
</div>
);
};