From c4044801a1d316be1848ae3364a75b6a06b540a6 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sat, 9 Sep 2023 18:17:11 -0500 Subject: [PATCH] Make photo titles optional --- src/app/(auth-state)/admin/photos/page.tsx | 7 +++++-- src/app/(isr)/photos/[photoId]/layout.tsx | 8 ++++++-- src/photo/PhotoForm.tsx | 5 ++--- src/photo/PhotoLarge.tsx | 6 +++--- src/photo/PhotoOGTile.tsx | 9 +++++++-- src/photo/PhotoSmall.tsx | 4 ++-- src/photo/PhotoTiny.tsx | 4 ++-- src/photo/form.ts | 4 ++-- src/photo/image-response/PhotoGridImageResponse.tsx | 4 ++-- src/photo/image-response/PhotoOGImageResponse.tsx | 4 ++-- src/photo/index.ts | 3 +++ 11 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/app/(auth-state)/admin/photos/page.tsx b/src/app/(auth-state)/admin/photos/page.tsx index a6655231..937bff95 100644 --- a/src/app/(auth-state)/admin/photos/page.tsx +++ b/src/app/(auth-state)/admin/photos/page.tsx @@ -63,7 +63,10 @@ export default async function AdminPage() { href={routeForPhoto(photo)} className="grow flex items-center gap-2" > - {photo.title} + {photo.title || + + Untitled + } {photo.priorityOrder !== null && + return
{title}
diff --git a/src/app/(isr)/photos/[photoId]/layout.tsx b/src/app/(isr)/photos/[photoId]/layout.tsx index 87b37fe3..d835a2e6 100644 --- a/src/app/(isr)/photos/[photoId]/layout.tsx +++ b/src/app/(isr)/photos/[photoId]/layout.tsx @@ -2,7 +2,11 @@ import { PropsWithChildren } from 'react'; import AnimateItems from '@/components/AnimateItems'; import PhotoLinks from '@/photo/PhotoLinks'; import SiteGrid from '@/components/SiteGrid'; -import { ogImageDescriptionForPhoto, ogImageUrlForPhoto } from '@/photo'; +import { + ogImageDescriptionForPhoto, + ogImageUrlForPhoto, + titleForPhoto, +} from '@/photo'; import PhotoGrid from '@/photo/PhotoGrid'; import PhotoLarge from '@/photo/PhotoLarge'; import { cc } from '@/utility/css'; @@ -24,7 +28,7 @@ export async function generateMetadata( if (!photo) { return {}; } - const title = photo.title; + const title = titleForPhoto(photo); const description = ogImageDescriptionForPhoto(photo); const images = ogImageUrlForPhoto(photo); diff --git a/src/photo/PhotoForm.tsx b/src/photo/PhotoForm.tsx index d049ee68..f68b5e60 100644 --- a/src/photo/PhotoForm.tsx +++ b/src/photo/PhotoForm.tsx @@ -72,9 +72,8 @@ export default function PhotoForm({ }; }, [url, type]); - const isFormValid = - Boolean(formData.blurData) && - Boolean(formData.title); + const isFormValid = FORM_METADATA_ENTRIES.every(([key, { required }]) => + !required || Boolean(formData[key])); return (
diff --git a/src/photo/PhotoLarge.tsx b/src/photo/PhotoLarge.tsx index c4f258b1..16cb1032 100644 --- a/src/photo/PhotoLarge.tsx +++ b/src/photo/PhotoLarge.tsx @@ -1,4 +1,4 @@ -import { Photo } from '.'; +import { Photo, titleForPhoto } from '.'; import SiteGrid from '@/components/SiteGrid'; import ImageLarge from '@/components/ImageLarge'; import { cc } from '@/utility/css'; @@ -30,7 +30,7 @@ export default function PhotoLarge({ contentMain={ - {photo.title} + {titleForPhoto(photo)}
{photo.make} {photo.model} diff --git a/src/photo/PhotoOGTile.tsx b/src/photo/PhotoOGTile.tsx index 91c510d4..78c9858e 100644 --- a/src/photo/PhotoOGTile.tsx +++ b/src/photo/PhotoOGTile.tsx @@ -1,7 +1,12 @@ 'use client'; import { useEffect, useState } from 'react'; -import { Photo, ogImageDescriptionForPhoto, ogImageUrlForPhoto } from '@/photo'; +import { + Photo, + ogImageDescriptionForPhoto, + ogImageUrlForPhoto, + titleForPhoto, +} from '@/photo'; import { cc } from '@/utility/css'; import Link from 'next/link'; import { BiError } from 'react-icons/bi'; @@ -111,7 +116,7 @@ export default function PhotoOGTile({ 'border-t border-gray-200 dark:border-gray-800', )}>
- {photo.title} + {titleForPhoto(photo)}
{ogImageDescriptionForPhoto(photo)} diff --git a/src/photo/PhotoSmall.tsx b/src/photo/PhotoSmall.tsx index 2241ab7f..90c75219 100644 --- a/src/photo/PhotoSmall.tsx +++ b/src/photo/PhotoSmall.tsx @@ -1,4 +1,4 @@ -import { Photo } from '.'; +import { Photo, titleForPhoto } from '.'; import ImageSmall from '@/components/ImageSmall'; import Link from 'next/link'; import { cc } from '@/utility/css'; @@ -24,7 +24,7 @@ export default function PhotoSmall({ aspectRatio={photo.aspectRatio} blurData={photo.blurData} className="w-full" - alt={photo.title ?? 'Photo'} + alt={titleForPhoto(photo)} /> ); diff --git a/src/photo/PhotoTiny.tsx b/src/photo/PhotoTiny.tsx index 080eef48..49d282d6 100644 --- a/src/photo/PhotoTiny.tsx +++ b/src/photo/PhotoTiny.tsx @@ -1,4 +1,4 @@ -import { Photo } from '.'; +import { Photo, titleForPhoto } from '.'; import ImageTiny from '@/components/ImageTiny'; import Link from 'next/link'; import { cc } from '@/utility/css'; @@ -27,7 +27,7 @@ export default function PhotoTiny({ src={photo.url} aspectRatio={photo.aspectRatio} blurData={photo.blurData} - alt={photo.title ?? 'Photo'} + alt={titleForPhoto(photo)} /> ); diff --git a/src/photo/form.ts b/src/photo/form.ts index 141061c7..cba347ba 100644 --- a/src/photo/form.ts +++ b/src/photo/form.ts @@ -18,13 +18,13 @@ type FormMeta = { }; const FORM_METADATA: Record = { - title: { label: 'title', required: true }, + title: { label: 'title' }, id: { label: 'id', readOnly: true, hideIfEmpty: true }, idShort: { label: 'short id', readOnly: true, hideIfEmpty: true }, url: { label: 'url', readOnly: true }, extension: { label: 'extension', readOnly: true }, aspectRatio: { label: 'aspect ratio', readOnly: true }, - blurData: { label: 'blur data', readOnly: true }, + blurData: { label: 'blur data', readOnly: true, required: true }, make: { label: 'camera make' }, model: { label: 'camera model' }, focalLength: { label: 'focal length' }, diff --git a/src/photo/image-response/PhotoGridImageResponse.tsx b/src/photo/image-response/PhotoGridImageResponse.tsx index 92c6abc8..fbcab83e 100644 --- a/src/photo/image-response/PhotoGridImageResponse.tsx +++ b/src/photo/image-response/PhotoGridImageResponse.tsx @@ -1,5 +1,5 @@ import { getNextImageUrlForRequest } from '@/utility/image'; -import { Photo } from '..'; +import { Photo, titleForPhoto } from '..'; const IMAGE_WIDTH = 400; @@ -38,7 +38,7 @@ export default function PhotoGridImageResponse({ request, IMAGE_WIDTH, )} - alt={photo.title} + alt={titleForPhoto(photo)} width={IMAGE_WIDTH} height={IMAGE_WIDTH / photo.aspectRatio} style={{ diff --git a/src/photo/image-response/PhotoOGImageResponse.tsx b/src/photo/image-response/PhotoOGImageResponse.tsx index 9178239d..c615fc89 100644 --- a/src/photo/image-response/PhotoOGImageResponse.tsx +++ b/src/photo/image-response/PhotoOGImageResponse.tsx @@ -1,4 +1,4 @@ -import { Photo } from '..'; +import { Photo, titleForPhoto } from '..'; import { getNextImageUrlForRequest } from '@/utility/image'; import { formatModelShort } from '@/utility/exif'; import { AiFillApple } from 'react-icons/ai'; @@ -34,7 +34,7 @@ export default function PhotoOGImageResponse({ )} width={width} height={width / photo.aspectRatio} - alt={photo.title} + alt={titleForPhoto(photo)} />
{ const id = PHOTO_ID_FORWARDING_TABLE[shortId] || shortId; return id.length === 22 ? translator.toUUID(id) : id; }; + +export const titleForPhoto = (photo: Photo) => + photo.title || 'Untitled';