Make photo titles optional

This commit is contained in:
Sam Becker 2023-09-09 18:17:11 -05:00
parent 8f984e69ef
commit c4044801a1
11 changed files with 36 additions and 22 deletions

View File

@ -63,7 +63,10 @@ export default async function AdminPage() {
href={routeForPhoto(photo)} href={routeForPhoto(photo)}
className="grow flex items-center gap-2" className="grow flex items-center gap-2"
> >
{photo.title} {photo.title ||
<span className="text-gray-400 dark:text-gray-500">
Untitled
</span>}
{photo.priorityOrder !== null && {photo.priorityOrder !== null &&
<span className={cc( <span className={cc(
'text-xs leading-none px-1.5 py-1 rounded-sm', 'text-xs leading-none px-1.5 py-1 rounded-sm',
@ -101,7 +104,7 @@ function AdminGrid ({
title: string, title: string,
children: ReactNode, children: ReactNode,
}) { }) {
return <div className="space-y-2"> return <div className="space-y-4">
<div className="font-bold"> <div className="font-bold">
{title} {title}
</div> </div>

View File

@ -2,7 +2,11 @@ import { PropsWithChildren } from 'react';
import AnimateItems from '@/components/AnimateItems'; import AnimateItems from '@/components/AnimateItems';
import PhotoLinks from '@/photo/PhotoLinks'; import PhotoLinks from '@/photo/PhotoLinks';
import SiteGrid from '@/components/SiteGrid'; import SiteGrid from '@/components/SiteGrid';
import { ogImageDescriptionForPhoto, ogImageUrlForPhoto } from '@/photo'; import {
ogImageDescriptionForPhoto,
ogImageUrlForPhoto,
titleForPhoto,
} from '@/photo';
import PhotoGrid from '@/photo/PhotoGrid'; import PhotoGrid from '@/photo/PhotoGrid';
import PhotoLarge from '@/photo/PhotoLarge'; import PhotoLarge from '@/photo/PhotoLarge';
import { cc } from '@/utility/css'; import { cc } from '@/utility/css';
@ -24,7 +28,7 @@ export async function generateMetadata(
if (!photo) { return {}; } if (!photo) { return {}; }
const title = photo.title; const title = titleForPhoto(photo);
const description = ogImageDescriptionForPhoto(photo); const description = ogImageDescriptionForPhoto(photo);
const images = ogImageUrlForPhoto(photo); const images = ogImageUrlForPhoto(photo);

View File

@ -72,9 +72,8 @@ export default function PhotoForm({
}; };
}, [url, type]); }, [url, type]);
const isFormValid = const isFormValid = FORM_METADATA_ENTRIES.every(([key, { required }]) =>
Boolean(formData.blurData) && !required || Boolean(formData[key]));
Boolean(formData.title);
return ( return (
<div className="space-y-8 max-w-[38rem]"> <div className="space-y-8 max-w-[38rem]">

View File

@ -1,4 +1,4 @@
import { Photo } from '.'; import { Photo, titleForPhoto } from '.';
import SiteGrid from '@/components/SiteGrid'; import SiteGrid from '@/components/SiteGrid';
import ImageLarge from '@/components/ImageLarge'; import ImageLarge from '@/components/ImageLarge';
import { cc } from '@/utility/css'; import { cc } from '@/utility/css';
@ -30,7 +30,7 @@ export default function PhotoLarge({
contentMain={ contentMain={
<ImageLarge <ImageLarge
className="w-full" className="w-full"
alt={photo.title ?? 'Photo'} alt={titleForPhoto(photo)}
href={routeForPhoto(photo)} href={routeForPhoto(photo)}
src={photo.url} src={photo.url}
aspectRatio={photo.aspectRatio} aspectRatio={photo.aspectRatio}
@ -50,7 +50,7 @@ export default function PhotoLarge({
href={routeForPhoto(photo)} href={routeForPhoto(photo)}
className="font-bold uppercase" className="font-bold uppercase"
> >
{photo.title} {titleForPhoto(photo)}
</Link> </Link>
<div className="uppercase"> <div className="uppercase">
{photo.make} {photo.model} {photo.make} {photo.model}

View File

@ -1,7 +1,12 @@
'use client'; 'use client';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Photo, ogImageDescriptionForPhoto, ogImageUrlForPhoto } from '@/photo'; import {
Photo,
ogImageDescriptionForPhoto,
ogImageUrlForPhoto,
titleForPhoto,
} from '@/photo';
import { cc } from '@/utility/css'; import { cc } from '@/utility/css';
import Link from 'next/link'; import Link from 'next/link';
import { BiError } from 'react-icons/bi'; import { BiError } from 'react-icons/bi';
@ -111,7 +116,7 @@ export default function PhotoOGTile({
'border-t border-gray-200 dark:border-gray-800', 'border-t border-gray-200 dark:border-gray-800',
)}> )}>
<div className="text-gray-800 dark:text-white font-medium"> <div className="text-gray-800 dark:text-white font-medium">
{photo.title} {titleForPhoto(photo)}
</div> </div>
<div className="text-gray-500"> <div className="text-gray-500">
{ogImageDescriptionForPhoto(photo)} {ogImageDescriptionForPhoto(photo)}

View File

@ -1,4 +1,4 @@
import { Photo } from '.'; import { Photo, titleForPhoto } from '.';
import ImageSmall from '@/components/ImageSmall'; import ImageSmall from '@/components/ImageSmall';
import Link from 'next/link'; import Link from 'next/link';
import { cc } from '@/utility/css'; import { cc } from '@/utility/css';
@ -24,7 +24,7 @@ export default function PhotoSmall({
aspectRatio={photo.aspectRatio} aspectRatio={photo.aspectRatio}
blurData={photo.blurData} blurData={photo.blurData}
className="w-full" className="w-full"
alt={photo.title ?? 'Photo'} alt={titleForPhoto(photo)}
/> />
</Link> </Link>
); );

View File

@ -1,4 +1,4 @@
import { Photo } from '.'; import { Photo, titleForPhoto } from '.';
import ImageTiny from '@/components/ImageTiny'; import ImageTiny from '@/components/ImageTiny';
import Link from 'next/link'; import Link from 'next/link';
import { cc } from '@/utility/css'; import { cc } from '@/utility/css';
@ -27,7 +27,7 @@ export default function PhotoTiny({
src={photo.url} src={photo.url}
aspectRatio={photo.aspectRatio} aspectRatio={photo.aspectRatio}
blurData={photo.blurData} blurData={photo.blurData}
alt={photo.title ?? 'Photo'} alt={titleForPhoto(photo)}
/> />
</Link> </Link>
); );

View File

@ -18,13 +18,13 @@ type FormMeta = {
}; };
const FORM_METADATA: Record<keyof PhotoFormData, FormMeta> = { const FORM_METADATA: Record<keyof PhotoFormData, FormMeta> = {
title: { label: 'title', required: true }, title: { label: 'title' },
id: { label: 'id', readOnly: true, hideIfEmpty: true }, id: { label: 'id', readOnly: true, hideIfEmpty: true },
idShort: { label: 'short id', readOnly: true, hideIfEmpty: true }, idShort: { label: 'short id', readOnly: true, hideIfEmpty: true },
url: { label: 'url', readOnly: true }, url: { label: 'url', readOnly: true },
extension: { label: 'extension', readOnly: true }, extension: { label: 'extension', readOnly: true },
aspectRatio: { label: 'aspect ratio', 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' }, make: { label: 'camera make' },
model: { label: 'camera model' }, model: { label: 'camera model' },
focalLength: { label: 'focal length' }, focalLength: { label: 'focal length' },

View File

@ -1,5 +1,5 @@
import { getNextImageUrlForRequest } from '@/utility/image'; import { getNextImageUrlForRequest } from '@/utility/image';
import { Photo } from '..'; import { Photo, titleForPhoto } from '..';
const IMAGE_WIDTH = 400; const IMAGE_WIDTH = 400;
@ -38,7 +38,7 @@ export default function PhotoGridImageResponse({
request, request,
IMAGE_WIDTH, IMAGE_WIDTH,
)} )}
alt={photo.title} alt={titleForPhoto(photo)}
width={IMAGE_WIDTH} width={IMAGE_WIDTH}
height={IMAGE_WIDTH / photo.aspectRatio} height={IMAGE_WIDTH / photo.aspectRatio}
style={{ style={{

View File

@ -1,4 +1,4 @@
import { Photo } from '..'; import { Photo, titleForPhoto } from '..';
import { getNextImageUrlForRequest } from '@/utility/image'; import { getNextImageUrlForRequest } from '@/utility/image';
import { formatModelShort } from '@/utility/exif'; import { formatModelShort } from '@/utility/exif';
import { AiFillApple } from 'react-icons/ai'; import { AiFillApple } from 'react-icons/ai';
@ -34,7 +34,7 @@ export default function PhotoOGImageResponse({
)} )}
width={width} width={width}
height={width / photo.aspectRatio} height={width / photo.aspectRatio}
alt={photo.title} alt={titleForPhoto(photo)}
/> />
<div style={{ <div style={{
display: 'flex', display: 'flex',

View File

@ -140,3 +140,6 @@ export const translatePhotoId = (shortId: string) => {
const id = PHOTO_ID_FORWARDING_TABLE[shortId] || shortId; const id = PHOTO_ID_FORWARDING_TABLE[shortId] || shortId;
return id.length === 22 ? translator.toUUID(id) : id; return id.length === 22 ? translator.toUUID(id) : id;
}; };
export const titleForPhoto = (photo: Photo) =>
photo.title || 'Untitled';