From f7321bd8315d1615e99e4d988ba8d237709e66d3 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Tue, 21 May 2024 12:34:45 -0500 Subject: [PATCH] Build out final focal length views --- src/app/focal/[focal]/[photoId]/layout.tsx | 86 +++++++++++++++++++ src/app/focal/[focal]/[photoId]/page.tsx | 3 + .../focal/[focal]/[photoId]/share/page.tsx | 19 ++++ src/app/focal/[focal]/page.tsx | 4 +- src/app/focal/[focal]/share/page.tsx | 70 +++++++++++++++ src/focal/FocalLengthHeader.tsx | 5 +- src/focal/FocalLengthOGTile.tsx | 50 +++++++++++ src/focal/FocalLengthShareModal.tsx | 26 ++++++ src/focal/data.ts | 2 +- src/focal/index.ts | 2 +- src/photo/PhotoDetailPage.tsx | 18 ++++ src/photo/PhotoLinks.tsx | 2 + src/site/paths.ts | 7 +- 13 files changed, 285 insertions(+), 9 deletions(-) create mode 100644 src/app/focal/[focal]/[photoId]/layout.tsx create mode 100644 src/app/focal/[focal]/[photoId]/page.tsx create mode 100644 src/app/focal/[focal]/[photoId]/share/page.tsx create mode 100644 src/app/focal/[focal]/share/page.tsx create mode 100644 src/focal/FocalLengthOGTile.tsx create mode 100644 src/focal/FocalLengthShareModal.tsx diff --git a/src/app/focal/[focal]/[photoId]/layout.tsx b/src/app/focal/[focal]/[photoId]/layout.tsx new file mode 100644 index 00000000..868d8c4d --- /dev/null +++ b/src/app/focal/[focal]/[photoId]/layout.tsx @@ -0,0 +1,86 @@ +import { + RELATED_GRID_PHOTOS_TO_SHOW, + descriptionForPhoto, + titleForPhoto, +} from '@/photo'; +import { Metadata } from 'next/types'; +import { redirect } from 'next/navigation'; +import { + PATH_ROOT, + absolutePathForPhoto, + absolutePathForPhotoImage, +} from '@/site/paths'; +import PhotoDetailPage from '@/photo/PhotoDetailPage'; +import { getPhotosNearIdCached } from '@/photo/cache'; +import { ReactNode, cache } from 'react'; +import { getPhotosMeta } from '@/photo/db/query'; +import { getFocalLengthFromString } from '@/focal'; + +const getPhotosNearIdCachedCached = cache((photoId: string, focal: number) => + getPhotosNearIdCached( + photoId, + { focal, limit: RELATED_GRID_PHOTOS_TO_SHOW + 2 }, + )); + +interface PhotoFocalLengthProps { + params: { photoId: string, focal: string } +} + +export async function generateMetadata({ + params: { photoId, focal: focalString }, +}: PhotoFocalLengthProps): Promise { + const focal = getFocalLengthFromString(focalString); + + const { photo } = await getPhotosNearIdCachedCached(photoId, focal); + + if (!photo) { return {}; } + + const title = titleForPhoto(photo); + const description = descriptionForPhoto(photo); + const images = absolutePathForPhotoImage(photo); + const url = absolutePathForPhoto({ photo, focal }); + + return { + title, + description, + openGraph: { + title, + images, + description, + url, + }, + twitter: { + title, + description, + images, + card: 'summary_large_image', + }, + }; +} + +export default async function PhotoFocalLengthPage({ + params: { photoId, focal: focalString }, + children, +}: PhotoFocalLengthProps & { children: ReactNode }) { + const focal = getFocalLengthFromString(focalString); + + const { photo, photos, photosGrid, indexNumber } = + await getPhotosNearIdCachedCached(photoId, focal); + + if (!photo) { redirect(PATH_ROOT); } + + const { count, dateRange } = await getPhotosMeta({ focal }); + + return <> + {children} + + ; +} diff --git a/src/app/focal/[focal]/[photoId]/page.tsx b/src/app/focal/[focal]/[photoId]/page.tsx new file mode 100644 index 00000000..67e08591 --- /dev/null +++ b/src/app/focal/[focal]/[photoId]/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return null; +} diff --git a/src/app/focal/[focal]/[photoId]/share/page.tsx b/src/app/focal/[focal]/[photoId]/share/page.tsx new file mode 100644 index 00000000..90702366 --- /dev/null +++ b/src/app/focal/[focal]/[photoId]/share/page.tsx @@ -0,0 +1,19 @@ +import { getFocalLengthFromString } from '@/focal'; +import { getPhotoCached } from '@/photo/cache'; +import PhotoShareModal from '@/photo/PhotoShareModal'; +import { PATH_ROOT } from '@/site/paths'; +import { redirect } from 'next/navigation'; + +export default async function Share({ + params: { photoId, focal: focalString }, +}: { + params: { photoId: string, focal: string } +}) { + const focal = getFocalLengthFromString(focalString); + + const photo = await getPhotoCached(photoId); + + if (!photo) { return redirect(PATH_ROOT); } + + return ; +} diff --git a/src/app/focal/[focal]/page.tsx b/src/app/focal/[focal]/page.tsx index f8b01767..82948194 100644 --- a/src/app/focal/[focal]/page.tsx +++ b/src/app/focal/[focal]/page.tsx @@ -1,6 +1,6 @@ import { generateMetaForFocalLength, getFocalLengthFromString } from '@/focal'; import FocalLengthOverview from '@/focal/FocalLengthOverview'; -import { getPhotosFocalDataCached } from '@/focal/data'; +import { getPhotosFocalLengthDataCached } from '@/focal/data'; import { INFINITE_SCROLL_GRID_PHOTO_INITIAL } from '@/photo'; import { PATH_ROOT } from '@/site/paths'; import type { Metadata } from 'next'; @@ -8,7 +8,7 @@ import { redirect } from 'next/navigation'; import { cache } from 'react'; const getPhotosFocalDataCachedCached = cache((focal: number) => - getPhotosFocalDataCached({ + getPhotosFocalLengthDataCached({ focal, limit: INFINITE_SCROLL_GRID_PHOTO_INITIAL, })); diff --git a/src/app/focal/[focal]/share/page.tsx b/src/app/focal/[focal]/share/page.tsx new file mode 100644 index 00000000..01d7aead --- /dev/null +++ b/src/app/focal/[focal]/share/page.tsx @@ -0,0 +1,70 @@ +import { generateMetaForFocalLength, getFocalLengthFromString } from '@/focal'; +import FocalLengthOverview from '@/focal/FocalLengthOverview'; +import FocalLengthShareModal from '@/focal/FocalLengthShareModal'; +import { getPhotosFocalLengthDataCached } from '@/focal/data'; +import { INFINITE_SCROLL_GRID_PHOTO_INITIAL } from '@/photo'; +import type { Metadata } from 'next'; +import { cache } from 'react'; + +const getPhotosFocalLengthDataCachedCached = cache((focal: number) => + getPhotosFocalLengthDataCached({ + focal, + limit: INFINITE_SCROLL_GRID_PHOTO_INITIAL, + })); + +interface FocalLengthProps { + params: { focal: string } +} + +export async function generateMetadata({ + params: { focal: focalString }, +}: FocalLengthProps): Promise { + const focal = getFocalLengthFromString(focalString); + + const [ + photos, + { count, dateRange }, + ] = await getPhotosFocalLengthDataCachedCached(focal); + + const { + url, + title, + description, + images, + } = generateMetaForFocalLength(focal, photos, count, dateRange); + + return { + title, + openGraph: { + title, + description, + images, + url, + }, + twitter: { + images, + description, + card: 'summary_large_image', + }, + description, + }; +} + +export default async function Share({ + params: { focal: focalString }, +}: FocalLengthProps) { + const focal = getFocalLengthFromString(focalString); + + const [ + photos, + { count, dateRange }, + ] = await getPhotosFocalLengthDataCachedCached(focal); + + return <> + + + ; +} diff --git a/src/focal/FocalLengthHeader.tsx b/src/focal/FocalLengthHeader.tsx index 9babb486..b40f459a 100644 --- a/src/focal/FocalLengthHeader.tsx +++ b/src/focal/FocalLengthHeader.tsx @@ -1,6 +1,6 @@ import { Photo, PhotoDateRange } from '@/photo'; import { descriptionForFocalLengthPhotos } from '.'; -import { pathForFocalLength } from '@/site/paths'; +import { pathForFocalLengthShare } from '@/site/paths'; import PhotoSetHeader from '@/photo/PhotoSetHeader'; import PhotoFocalLength from './PhotoFocalLength'; @@ -22,7 +22,6 @@ export default function FocalLengthHeader({ return ( } - entityVerb="Tagged" entityDescription={descriptionForFocalLengthPhotos( photos, undefined, @@ -30,7 +29,7 @@ export default function FocalLengthHeader({ )} photos={photos} selectedPhoto={selectedPhoto} - sharePath={pathForFocalLength(focal)} + sharePath={pathForFocalLengthShare(focal)} indexNumber={indexNumber} count={count} dateRange={dateRange} diff --git a/src/focal/FocalLengthOGTile.tsx b/src/focal/FocalLengthOGTile.tsx new file mode 100644 index 00000000..29e9af83 --- /dev/null +++ b/src/focal/FocalLengthOGTile.tsx @@ -0,0 +1,50 @@ +import { Photo, PhotoDateRange } from '@/photo'; +import { + absolutePathForFocalLengthImage, + pathForFocalLength, +} from '@/site/paths'; +import OGTile from '@/components/OGTile'; +import { descriptionForFocalLengthPhotos, titleForFocalLength } from '.'; + +export type OGLoadingState = 'unloaded' | 'loading' | 'loaded' | 'failed'; + +export default function FocalLengthOGTile({ + focal, + photos, + loadingState: loadingStateExternal, + riseOnHover, + onLoad, + onFail, + retryTime, + count, + dateRange, +}: { + focal: number + photos: Photo[] + loadingState?: OGLoadingState + onLoad?: () => void + onFail?: () => void + riseOnHover?: boolean + retryTime?: number + count?: number + dateRange?: PhotoDateRange +}) { + return ( + + ); +}; diff --git a/src/focal/FocalLengthShareModal.tsx b/src/focal/FocalLengthShareModal.tsx new file mode 100644 index 00000000..62b02b41 --- /dev/null +++ b/src/focal/FocalLengthShareModal.tsx @@ -0,0 +1,26 @@ +import { absolutePathForFocalLength, pathForFocalLength } from '@/site/paths'; +import { Photo, PhotoDateRange } from '../photo'; +import ShareModal from '@/components/ShareModal'; +import FocalLengthOGTile from './FocalLengthOGTile'; + +export default function FocalLengthShareModal({ + focal, + photos, + count, + dateRange, +}: { + focal: number + photos: Photo[] + count?: number + dateRange?: PhotoDateRange +}) { + return ( + + + + ); +}; diff --git a/src/focal/data.ts b/src/focal/data.ts index be5b539d..3001d7fb 100644 --- a/src/focal/data.ts +++ b/src/focal/data.ts @@ -3,7 +3,7 @@ import { getPhotosMetaCached, } from '@/photo/cache'; -export const getPhotosFocalDataCached = ({ +export const getPhotosFocalLengthDataCached = ({ focal, limit, }: { diff --git a/src/focal/index.ts b/src/focal/index.ts index 9104df94..f3f40bd3 100644 --- a/src/focal/index.ts +++ b/src/focal/index.ts @@ -23,7 +23,7 @@ export const titleForFocalLength = ( photos: Photo[], explicitCount?: number, ) => [ - formatFocalLength(focal), + `${formatFocalLength(focal)} Focal Length`, photoQuantityText(explicitCount ?? photos.length), ].join(' '); diff --git a/src/photo/PhotoDetailPage.tsx b/src/photo/PhotoDetailPage.tsx index 6f95b22a..c96b8bf2 100644 --- a/src/photo/PhotoDetailPage.tsx +++ b/src/photo/PhotoDetailPage.tsx @@ -12,6 +12,7 @@ import { FilmSimulation } from '@/simulation'; import FilmSimulationHeader from '@/simulation/FilmSimulationHeader'; import { TAG_HIDDEN } from '@/tag'; import HiddenHeader from '@/tag/HiddenHeader'; +import FocalLengthHeader from '@/focal/FocalLengthHeader'; export default function PhotoDetailPage({ photo, @@ -20,6 +21,7 @@ export default function PhotoDetailPage({ tag, camera, simulation, + focal, indexNumber, count, dateRange, @@ -30,6 +32,7 @@ export default function PhotoDetailPage({ tag?: string camera?: Camera simulation?: FilmSimulation + focal?: number indexNumber?: number count?: number dateRange?: PhotoDateRange @@ -82,6 +85,19 @@ export default function PhotoDetailPage({ dateRange={dateRange} />} />} + {focal && + } + />} } contentSide={ , ]} diff --git a/src/photo/PhotoLinks.tsx b/src/photo/PhotoLinks.tsx index 6a7a5c1b..b2d86036 100644 --- a/src/photo/PhotoLinks.tsx +++ b/src/photo/PhotoLinks.tsx @@ -101,6 +101,7 @@ export default function PhotoLinks({ tag={tag} camera={camera} simulation={simulation} + focal={focal} scroll={false} prefetch > @@ -112,6 +113,7 @@ export default function PhotoLinks({ tag={tag} camera={camera} simulation={simulation} + focal={focal} scroll={false} prefetch > diff --git a/src/site/paths.ts b/src/site/paths.ts index a04b4335..94a30d3a 100644 --- a/src/site/paths.ts +++ b/src/site/paths.ts @@ -125,11 +125,14 @@ export const pathForCameraShare = (camera: Camera) => export const pathForFilmSimulation = (simulation: FilmSimulation) => `${PREFIX_FILM_SIMULATION}/${simulation}`; +export const pathForFilmSimulationShare = (simulation: FilmSimulation) => + `${pathForFilmSimulation(simulation)}/${SHARE}`; + export const pathForFocalLength = (focal: number) => `${PREFIX_FOCAL_LENGTH}/${focal}mm`; -export const pathForFilmSimulationShare = (simulation: FilmSimulation) => - `${pathForFilmSimulation(simulation)}/${SHARE}`; +export const pathForFocalLengthShare = (focal: number) => + `${pathForFocalLength(focal)}/${SHARE}`;; export const absolutePathForPhoto = (params: PhotoPathParams) => `${BASE_URL}${pathForPhoto(params)}`;