Switch film chooser to tag input
This commit is contained in:
parent
09d7a07722
commit
5f992788f2
@ -1,6 +1,7 @@
|
|||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
import {
|
import {
|
||||||
getPhotoNoStore,
|
getPhotoNoStore,
|
||||||
|
getUniqueFilmsCached,
|
||||||
getUniqueRecipesCached,
|
getUniqueRecipesCached,
|
||||||
getUniqueTagsCached,
|
getUniqueTagsCached,
|
||||||
} from '@/photo/cache';
|
} from '@/photo/cache';
|
||||||
@ -10,7 +11,6 @@ import {
|
|||||||
AI_TEXT_GENERATION_ENABLED,
|
AI_TEXT_GENERATION_ENABLED,
|
||||||
BLUR_ENABLED,
|
BLUR_ENABLED,
|
||||||
IS_PREVIEW,
|
IS_PREVIEW,
|
||||||
SHOW_RECIPES,
|
|
||||||
} from '@/app/config';
|
} from '@/app/config';
|
||||||
import { blurImageFromUrl, resizeImageFromUrl } from '@/photo/server';
|
import { blurImageFromUrl, resizeImageFromUrl } from '@/photo/server';
|
||||||
import { getNextImageUrlForManipulation } from '@/platforms/next-image';
|
import { getNextImageUrlForManipulation } from '@/platforms/next-image';
|
||||||
@ -26,11 +26,15 @@ export default async function PhotoEditPage({
|
|||||||
|
|
||||||
if (!photo) { redirect(PATH_ADMIN); }
|
if (!photo) { redirect(PATH_ADMIN); }
|
||||||
|
|
||||||
const uniqueTags = await getUniqueTagsCached();
|
const [
|
||||||
|
uniqueTags,
|
||||||
const uniqueRecipes = SHOW_RECIPES
|
uniqueRecipes,
|
||||||
? await getUniqueRecipesCached()
|
uniqueFilms,
|
||||||
: [];
|
] = await Promise.all([
|
||||||
|
getUniqueTagsCached(),
|
||||||
|
getUniqueRecipesCached(),
|
||||||
|
getUniqueFilmsCached(),
|
||||||
|
]);
|
||||||
|
|
||||||
const hasAiTextGeneration = AI_TEXT_GENERATION_ENABLED;
|
const hasAiTextGeneration = AI_TEXT_GENERATION_ENABLED;
|
||||||
|
|
||||||
@ -52,6 +56,7 @@ export default async function PhotoEditPage({
|
|||||||
photo,
|
photo,
|
||||||
uniqueTags,
|
uniqueTags,
|
||||||
uniqueRecipes,
|
uniqueRecipes,
|
||||||
|
uniqueFilms,
|
||||||
hasAiTextGeneration,
|
hasAiTextGeneration,
|
||||||
imageThumbnailBase64,
|
imageThumbnailBase64,
|
||||||
blurData,
|
blurData,
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
import { PATH_ADMIN } from '@/app/paths';
|
import { PATH_ADMIN } from '@/app/paths';
|
||||||
import { extractImageDataFromBlobPath } from '@/photo/server';
|
import { extractImageDataFromBlobPath } from '@/photo/server';
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
import { getUniqueRecipesCached, getUniqueTagsCached } from '@/photo/cache';
|
import {
|
||||||
|
getUniqueFilmsCached,
|
||||||
|
getUniqueRecipesCached,
|
||||||
|
getUniqueTagsCached,
|
||||||
|
} from '@/photo/cache';
|
||||||
import UploadPageClient from '@/photo/UploadPageClient';
|
import UploadPageClient from '@/photo/UploadPageClient';
|
||||||
import {
|
import {
|
||||||
AI_TEXT_AUTO_GENERATED_FIELDS,
|
AI_TEXT_AUTO_GENERATED_FIELDS,
|
||||||
@ -45,10 +49,12 @@ export default async function UploadPage({ params }: Params) {
|
|||||||
const [
|
const [
|
||||||
uniqueTags,
|
uniqueTags,
|
||||||
uniqueRecipes,
|
uniqueRecipes,
|
||||||
|
uniqueFilms,
|
||||||
recipeTitle,
|
recipeTitle,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
getUniqueTagsCached(),
|
getUniqueTagsCached(),
|
||||||
getUniqueRecipesCached(),
|
getUniqueRecipesCached(),
|
||||||
|
getUniqueFilmsCached(),
|
||||||
formDataFromExif?.recipeData && formDataFromExif.film
|
formDataFromExif?.recipeData && formDataFromExif.film
|
||||||
? getRecipeTitleForData(
|
? getRecipeTitleForData(
|
||||||
formDataFromExif.recipeData,
|
formDataFromExif.recipeData,
|
||||||
@ -72,6 +78,7 @@ export default async function UploadPage({ params }: Params) {
|
|||||||
formDataFromExif,
|
formDataFromExif,
|
||||||
uniqueTags,
|
uniqueTags,
|
||||||
uniqueRecipes,
|
uniqueRecipes,
|
||||||
|
uniqueFilms,
|
||||||
hasAiTextGeneration,
|
hasAiTextGeneration,
|
||||||
textFieldsToAutoGenerate,
|
textFieldsToAutoGenerate,
|
||||||
imageThumbnailBase64,
|
imageThumbnailBase64,
|
||||||
|
|||||||
@ -12,6 +12,8 @@ import {
|
|||||||
FujifilmSimulation,
|
FujifilmSimulation,
|
||||||
labelForFilm,
|
labelForFilm,
|
||||||
} from '@/platforms/fujifilm/simulation';
|
} from '@/platforms/fujifilm/simulation';
|
||||||
|
import { formatCount } from '@/utility/string';
|
||||||
|
import { formatCountDescriptive } from '@/utility/string';
|
||||||
|
|
||||||
export type FilmSimulation = FujifilmSimulation;
|
export type FilmSimulation = FujifilmSimulation;
|
||||||
|
|
||||||
@ -82,3 +84,11 @@ export const generateMetaForFilm = (
|
|||||||
|
|
||||||
export const photoHasFilmData = (photo: Photo) =>
|
export const photoHasFilmData = (photo: Photo) =>
|
||||||
Boolean(photo.film);
|
Boolean(photo.film);
|
||||||
|
|
||||||
|
export const convertFilmsForForm = (films: Films = []) =>
|
||||||
|
sortFilms(films)
|
||||||
|
.map(({ film, count }) => ({
|
||||||
|
value: film,
|
||||||
|
annotation: formatCount(count),
|
||||||
|
annotationAria: formatCountDescriptive(count),
|
||||||
|
}));
|
||||||
|
|||||||
@ -11,11 +11,13 @@ import usePhotoFormParent from './form/usePhotoFormParent';
|
|||||||
import ExifCaptureButton from '@/admin/ExifCaptureButton';
|
import ExifCaptureButton from '@/admin/ExifCaptureButton';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Recipes } from '@/recipe';
|
import { Recipes } from '@/recipe';
|
||||||
|
import { Films } from '@/film';
|
||||||
|
|
||||||
export default function PhotoEditPageClient({
|
export default function PhotoEditPageClient({
|
||||||
photo,
|
photo,
|
||||||
uniqueTags,
|
uniqueTags,
|
||||||
uniqueRecipes,
|
uniqueRecipes,
|
||||||
|
uniqueFilms,
|
||||||
hasAiTextGeneration,
|
hasAiTextGeneration,
|
||||||
imageThumbnailBase64,
|
imageThumbnailBase64,
|
||||||
blurData,
|
blurData,
|
||||||
@ -23,6 +25,7 @@ export default function PhotoEditPageClient({
|
|||||||
photo: Photo
|
photo: Photo
|
||||||
uniqueTags: Tags
|
uniqueTags: Tags
|
||||||
uniqueRecipes: Recipes
|
uniqueRecipes: Recipes
|
||||||
|
uniqueFilms: Films
|
||||||
hasAiTextGeneration: boolean
|
hasAiTextGeneration: boolean
|
||||||
imageThumbnailBase64: string
|
imageThumbnailBase64: string
|
||||||
blurData: string
|
blurData: string
|
||||||
@ -71,6 +74,7 @@ export default function PhotoEditPageClient({
|
|||||||
updatedBlurData={blurData}
|
updatedBlurData={blurData}
|
||||||
uniqueTags={uniqueTags}
|
uniqueTags={uniqueTags}
|
||||||
uniqueRecipes={uniqueRecipes}
|
uniqueRecipes={uniqueRecipes}
|
||||||
|
uniqueFilms={uniqueFilms}
|
||||||
aiContent={hasAiTextGeneration ? aiContent : undefined}
|
aiContent={hasAiTextGeneration ? aiContent : undefined}
|
||||||
onTitleChange={setUpdatedTitle}
|
onTitleChange={setUpdatedTitle}
|
||||||
onTextContentChange={setHasTextContent}
|
onTextContentChange={setHasTextContent}
|
||||||
|
|||||||
@ -10,12 +10,14 @@ import AiButton from './ai/AiButton';
|
|||||||
import { AiAutoGeneratedField } from './ai';
|
import { AiAutoGeneratedField } from './ai';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { Recipes } from '@/recipe';
|
import { Recipes } from '@/recipe';
|
||||||
|
import { Films } from '@/film';
|
||||||
|
|
||||||
export default function UploadPageClient({
|
export default function UploadPageClient({
|
||||||
blobId,
|
blobId,
|
||||||
formDataFromExif,
|
formDataFromExif,
|
||||||
uniqueTags,
|
uniqueTags,
|
||||||
uniqueRecipes,
|
uniqueRecipes,
|
||||||
|
uniqueFilms,
|
||||||
hasAiTextGeneration,
|
hasAiTextGeneration,
|
||||||
textFieldsToAutoGenerate,
|
textFieldsToAutoGenerate,
|
||||||
imageThumbnailBase64,
|
imageThumbnailBase64,
|
||||||
@ -25,6 +27,7 @@ export default function UploadPageClient({
|
|||||||
formDataFromExif: Partial<PhotoFormData>
|
formDataFromExif: Partial<PhotoFormData>
|
||||||
uniqueTags: Tags
|
uniqueTags: Tags
|
||||||
uniqueRecipes: Recipes
|
uniqueRecipes: Recipes
|
||||||
|
uniqueFilms: Films
|
||||||
hasAiTextGeneration?: boolean
|
hasAiTextGeneration?: boolean
|
||||||
textFieldsToAutoGenerate?: AiAutoGeneratedField[],
|
textFieldsToAutoGenerate?: AiAutoGeneratedField[],
|
||||||
imageThumbnailBase64?: string
|
imageThumbnailBase64?: string
|
||||||
@ -65,6 +68,7 @@ export default function UploadPageClient({
|
|||||||
initialPhotoForm={initialPhotoForm}
|
initialPhotoForm={initialPhotoForm}
|
||||||
uniqueTags={uniqueTags}
|
uniqueTags={uniqueTags}
|
||||||
uniqueRecipes={uniqueRecipes}
|
uniqueRecipes={uniqueRecipes}
|
||||||
|
uniqueFilms={uniqueFilms}
|
||||||
aiContent={hasAiTextGeneration ? aiContent : undefined}
|
aiContent={hasAiTextGeneration ? aiContent : undefined}
|
||||||
shouldStripGpsData={shouldStripGpsData}
|
shouldStripGpsData={shouldStripGpsData}
|
||||||
onTitleChange={setUpdatedTitle}
|
onTitleChange={setUpdatedTitle}
|
||||||
|
|||||||
@ -41,13 +41,9 @@ import ErrorNote from '@/components/ErrorNote';
|
|||||||
import { convertRecipesForForm, Recipes } from '@/recipe';
|
import { convertRecipesForForm, Recipes } from '@/recipe';
|
||||||
import deepEqual from 'fast-deep-equal/es6/react';
|
import deepEqual from 'fast-deep-equal/es6/react';
|
||||||
import ApplyRecipeTitleGloballyCheckbox from './ApplyRecipesGloballyCheckbox';
|
import ApplyRecipeTitleGloballyCheckbox from './ApplyRecipesGloballyCheckbox';
|
||||||
import { FilmSimulation } from '@/film';
|
import { convertFilmsForForm, Films, FilmSimulation } from '@/film';
|
||||||
import IconFavs from '@/components/icons/IconFavs';
|
import IconFavs from '@/components/icons/IconFavs';
|
||||||
import IconHidden from '@/components/icons/IconHidden';
|
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;
|
const THUMBNAIL_SIZE = 300;
|
||||||
|
|
||||||
@ -58,6 +54,7 @@ export default function PhotoForm({
|
|||||||
updatedBlurData,
|
updatedBlurData,
|
||||||
uniqueTags,
|
uniqueTags,
|
||||||
uniqueRecipes,
|
uniqueRecipes,
|
||||||
|
uniqueFilms,
|
||||||
aiContent,
|
aiContent,
|
||||||
shouldStripGpsData,
|
shouldStripGpsData,
|
||||||
onTitleChange,
|
onTitleChange,
|
||||||
@ -70,6 +67,7 @@ export default function PhotoForm({
|
|||||||
updatedBlurData?: string
|
updatedBlurData?: string
|
||||||
uniqueTags?: Tags
|
uniqueTags?: Tags
|
||||||
uniqueRecipes?: Recipes
|
uniqueRecipes?: Recipes
|
||||||
|
uniqueFilms?: Films
|
||||||
aiContent?: AiContent
|
aiContent?: AiContent
|
||||||
shouldStripGpsData?: boolean
|
shouldStripGpsData?: boolean
|
||||||
onTitleChange?: (updatedTitle: string) => void
|
onTitleChange?: (updatedTitle: string) => void
|
||||||
@ -330,6 +328,7 @@ export default function PhotoForm({
|
|||||||
{FORM_METADATA_ENTRIES(
|
{FORM_METADATA_ENTRIES(
|
||||||
convertTagsForForm(uniqueTags),
|
convertTagsForForm(uniqueTags),
|
||||||
convertRecipesForForm(uniqueRecipes),
|
convertRecipesForForm(uniqueRecipes),
|
||||||
|
convertFilmsForForm(uniqueFilms),
|
||||||
aiContent !== undefined,
|
aiContent !== undefined,
|
||||||
shouldStripGpsData,
|
shouldStripGpsData,
|
||||||
)
|
)
|
||||||
@ -412,18 +411,6 @@ export default function PhotoForm({
|
|||||||
};
|
};
|
||||||
|
|
||||||
switch (key) {
|
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':
|
case 'applyRecipeTitleGlobally':
|
||||||
return <ApplyRecipeTitleGloballyCheckbox
|
return <ApplyRecipeTitleGloballyCheckbox
|
||||||
key={key}
|
key={key}
|
||||||
|
|||||||
@ -80,6 +80,7 @@ const STRING_MAX_LENGTH_LONG = 1000;
|
|||||||
const FORM_METADATA = (
|
const FORM_METADATA = (
|
||||||
tagOptions?: AnnotatedTag[],
|
tagOptions?: AnnotatedTag[],
|
||||||
recipeOptions?: AnnotatedTag[],
|
recipeOptions?: AnnotatedTag[],
|
||||||
|
filmOptions?: AnnotatedTag[],
|
||||||
aiTextGeneration?: boolean,
|
aiTextGeneration?: boolean,
|
||||||
shouldStripGpsData?: boolean,
|
shouldStripGpsData?: boolean,
|
||||||
): Record<keyof PhotoFormData, FormMeta> => ({
|
): Record<keyof PhotoFormData, FormMeta> => ({
|
||||||
@ -121,6 +122,9 @@ const FORM_METADATA = (
|
|||||||
label: 'film',
|
label: 'film',
|
||||||
note: 'Intended for Fujifilm simulations and analog scans',
|
note: 'Intended for Fujifilm simulations and analog scans',
|
||||||
noteShort: 'Fujifilm simulations / analog scans',
|
noteShort: 'Fujifilm simulations / analog scans',
|
||||||
|
tagOptions: filmOptions,
|
||||||
|
tagOptionsLimitValidationMessage: 'Photos can only have one film',
|
||||||
|
tagOptionsLimit: 1,
|
||||||
shouldNotOverwriteWithNullDataOnSync: true,
|
shouldNotOverwriteWithNullDataOnSync: true,
|
||||||
},
|
},
|
||||||
recipeTitle: {
|
recipeTitle: {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user