Switch film chooser to tag input

This commit is contained in:
Sam Becker 2025-03-31 00:25:25 -05:00
parent 09d7a07722
commit 5f992788f2
7 changed files with 45 additions and 24 deletions

View File

@ -1,6 +1,7 @@
import { redirect } from 'next/navigation';
import {
getPhotoNoStore,
getUniqueFilmsCached,
getUniqueRecipesCached,
getUniqueTagsCached,
} from '@/photo/cache';
@ -10,7 +11,6 @@ import {
AI_TEXT_GENERATION_ENABLED,
BLUR_ENABLED,
IS_PREVIEW,
SHOW_RECIPES,
} from '@/app/config';
import { blurImageFromUrl, resizeImageFromUrl } from '@/photo/server';
import { getNextImageUrlForManipulation } from '@/platforms/next-image';
@ -26,11 +26,15 @@ export default async function PhotoEditPage({
if (!photo) { redirect(PATH_ADMIN); }
const uniqueTags = await getUniqueTagsCached();
const uniqueRecipes = SHOW_RECIPES
? await getUniqueRecipesCached()
: [];
const [
uniqueTags,
uniqueRecipes,
uniqueFilms,
] = await Promise.all([
getUniqueTagsCached(),
getUniqueRecipesCached(),
getUniqueFilmsCached(),
]);
const hasAiTextGeneration = AI_TEXT_GENERATION_ENABLED;
@ -52,6 +56,7 @@ export default async function PhotoEditPage({
photo,
uniqueTags,
uniqueRecipes,
uniqueFilms,
hasAiTextGeneration,
imageThumbnailBase64,
blurData,

View File

@ -1,7 +1,11 @@
import { PATH_ADMIN } from '@/app/paths';
import { extractImageDataFromBlobPath } from '@/photo/server';
import { redirect } from 'next/navigation';
import { getUniqueRecipesCached, getUniqueTagsCached } from '@/photo/cache';
import {
getUniqueFilmsCached,
getUniqueRecipesCached,
getUniqueTagsCached,
} from '@/photo/cache';
import UploadPageClient from '@/photo/UploadPageClient';
import {
AI_TEXT_AUTO_GENERATED_FIELDS,
@ -45,10 +49,12 @@ export default async function UploadPage({ params }: Params) {
const [
uniqueTags,
uniqueRecipes,
uniqueFilms,
recipeTitle,
] = await Promise.all([
getUniqueTagsCached(),
getUniqueRecipesCached(),
getUniqueFilmsCached(),
formDataFromExif?.recipeData && formDataFromExif.film
? getRecipeTitleForData(
formDataFromExif.recipeData,
@ -72,6 +78,7 @@ export default async function UploadPage({ params }: Params) {
formDataFromExif,
uniqueTags,
uniqueRecipes,
uniqueFilms,
hasAiTextGeneration,
textFieldsToAutoGenerate,
imageThumbnailBase64,

View File

@ -12,6 +12,8 @@ import {
FujifilmSimulation,
labelForFilm,
} from '@/platforms/fujifilm/simulation';
import { formatCount } from '@/utility/string';
import { formatCountDescriptive } from '@/utility/string';
export type FilmSimulation = FujifilmSimulation;
@ -82,3 +84,11 @@ export const generateMetaForFilm = (
export const photoHasFilmData = (photo: Photo) =>
Boolean(photo.film);
export const convertFilmsForForm = (films: Films = []) =>
sortFilms(films)
.map(({ film, count }) => ({
value: film,
annotation: formatCount(count),
annotationAria: formatCountDescriptive(count),
}));

View File

@ -11,11 +11,13 @@ import usePhotoFormParent from './form/usePhotoFormParent';
import ExifCaptureButton from '@/admin/ExifCaptureButton';
import { useState } from 'react';
import { Recipes } from '@/recipe';
import { Films } from '@/film';
export default function PhotoEditPageClient({
photo,
uniqueTags,
uniqueRecipes,
uniqueFilms,
hasAiTextGeneration,
imageThumbnailBase64,
blurData,
@ -23,6 +25,7 @@ export default function PhotoEditPageClient({
photo: Photo
uniqueTags: Tags
uniqueRecipes: Recipes
uniqueFilms: Films
hasAiTextGeneration: boolean
imageThumbnailBase64: string
blurData: string
@ -71,6 +74,7 @@ export default function PhotoEditPageClient({
updatedBlurData={blurData}
uniqueTags={uniqueTags}
uniqueRecipes={uniqueRecipes}
uniqueFilms={uniqueFilms}
aiContent={hasAiTextGeneration ? aiContent : undefined}
onTitleChange={setUpdatedTitle}
onTextContentChange={setHasTextContent}

View File

@ -10,12 +10,14 @@ import AiButton from './ai/AiButton';
import { AiAutoGeneratedField } from './ai';
import { useMemo } from 'react';
import { Recipes } from '@/recipe';
import { Films } from '@/film';
export default function UploadPageClient({
blobId,
formDataFromExif,
uniqueTags,
uniqueRecipes,
uniqueFilms,
hasAiTextGeneration,
textFieldsToAutoGenerate,
imageThumbnailBase64,
@ -25,6 +27,7 @@ export default function UploadPageClient({
formDataFromExif: Partial<PhotoFormData>
uniqueTags: Tags
uniqueRecipes: Recipes
uniqueFilms: Films
hasAiTextGeneration?: boolean
textFieldsToAutoGenerate?: AiAutoGeneratedField[],
imageThumbnailBase64?: string
@ -65,6 +68,7 @@ export default function UploadPageClient({
initialPhotoForm={initialPhotoForm}
uniqueTags={uniqueTags}
uniqueRecipes={uniqueRecipes}
uniqueFilms={uniqueFilms}
aiContent={hasAiTextGeneration ? aiContent : undefined}
shouldStripGpsData={shouldStripGpsData}
onTitleChange={setUpdatedTitle}

View File

@ -41,13 +41,9 @@ import ErrorNote from '@/components/ErrorNote';
import { convertRecipesForForm, Recipes } from '@/recipe';
import deepEqual from 'fast-deep-equal/es6/react';
import ApplyRecipeTitleGloballyCheckbox from './ApplyRecipesGloballyCheckbox';
import { FilmSimulation } from '@/film';
import { convertFilmsForForm, Films, FilmSimulation } from '@/film';
import IconFavs from '@/components/icons/IconFavs';
import IconHidden from '@/components/icons/IconHidden';
import { MAKE_FUJIFILM } from '@/platforms/fujifilm';
import {
FILM_SIMULATION_FORM_INPUT_OPTIONS,
} from '@/platforms/fujifilm/simulation';
const THUMBNAIL_SIZE = 300;
@ -58,6 +54,7 @@ export default function PhotoForm({
updatedBlurData,
uniqueTags,
uniqueRecipes,
uniqueFilms,
aiContent,
shouldStripGpsData,
onTitleChange,
@ -70,6 +67,7 @@ export default function PhotoForm({
updatedBlurData?: string
uniqueTags?: Tags
uniqueRecipes?: Recipes
uniqueFilms?: Films
aiContent?: AiContent
shouldStripGpsData?: boolean
onTitleChange?: (updatedTitle: string) => void
@ -330,6 +328,7 @@ export default function PhotoForm({
{FORM_METADATA_ENTRIES(
convertTagsForForm(uniqueTags),
convertRecipesForForm(uniqueRecipes),
convertFilmsForForm(uniqueFilms),
aiContent !== undefined,
shouldStripGpsData,
)
@ -412,18 +411,6 @@ export default function PhotoForm({
};
switch (key) {
case 'film':
return formData.make === MAKE_FUJIFILM
? <FieldSetWithStatus
key={key}
{...fieldProps}
selectOptions={FILM_SIMULATION_FORM_INPUT_OPTIONS}
selectOptionsDefaultLabel="Unknown"
/>
: <FieldSetWithStatus
key={key}
{...fieldProps}
/>;
case 'applyRecipeTitleGlobally':
return <ApplyRecipeTitleGloballyCheckbox
key={key}

View File

@ -80,6 +80,7 @@ const STRING_MAX_LENGTH_LONG = 1000;
const FORM_METADATA = (
tagOptions?: AnnotatedTag[],
recipeOptions?: AnnotatedTag[],
filmOptions?: AnnotatedTag[],
aiTextGeneration?: boolean,
shouldStripGpsData?: boolean,
): Record<keyof PhotoFormData, FormMeta> => ({
@ -121,6 +122,9 @@ const FORM_METADATA = (
label: 'film',
note: 'Intended for Fujifilm simulations and analog scans',
noteShort: 'Fujifilm simulations / analog scans',
tagOptions: filmOptions,
tagOptionsLimitValidationMessage: 'Photos can only have one film',
tagOptionsLimit: 1,
shouldNotOverwriteWithNullDataOnSync: true,
},
recipeTitle: {