Show recipe data when viewing film set

This commit is contained in:
Sam Becker 2025-04-16 09:24:53 -05:00
parent 9c14051236
commit dfbe3151ca
7 changed files with 49 additions and 34 deletions

View File

@ -5,7 +5,7 @@ import { PATH_ADMIN, PATH_ADMIN_RECIPES, pathForRecipe } from '@/app/paths';
import PhotoLightbox from '@/photo/PhotoLightbox'; import PhotoLightbox from '@/photo/PhotoLightbox';
import AdminRecipeBadge from '@/admin/AdminRecipeBadge'; import AdminRecipeBadge from '@/admin/AdminRecipeBadge';
import AdminRecipeForm from '@/admin/AdminRecipeForm'; import AdminRecipeForm from '@/admin/AdminRecipeForm';
import { getPhotoWithRecipeFromPhotos } from '@/recipe'; import { getRecipePropsFromPhotos } from '@/recipe';
import AdminShowRecipeButton from '@/admin/AdminShowRecipeButton'; import AdminShowRecipeButton from '@/admin/AdminShowRecipeButton';
const MAX_PHOTO_TO_SHOW = 6; const MAX_PHOTO_TO_SHOW = 6;
@ -29,10 +29,7 @@ export default async function RecipePageEdit({
getPhotosCached({ recipe, limit: MAX_PHOTO_TO_SHOW }), getPhotosCached({ recipe, limit: MAX_PHOTO_TO_SHOW }),
]); ]);
const { const { data, film } = getRecipePropsFromPhotos(photos) ?? {};
recipeData,
film,
} = getPhotoWithRecipeFromPhotos(photos) ?? {};
if (count === 0) { redirect(PATH_ADMIN); } if (count === 0) { redirect(PATH_ADMIN); }
@ -41,10 +38,10 @@ export default async function RecipePageEdit({
backPath={PATH_ADMIN_RECIPES} backPath={PATH_ADMIN_RECIPES}
backLabel="Recipes" backLabel="Recipes"
breadcrumb={<AdminRecipeBadge {...{ recipe, count, hideBadge: true }} />} breadcrumb={<AdminRecipeBadge {...{ recipe, count, hideBadge: true }} />}
accessory={recipeData && film && accessory={data && film &&
<AdminShowRecipeButton <AdminShowRecipeButton
title={recipe} title={recipe}
data={recipeData} data={data}
film={film} film={film}
/> />
} }

View File

@ -1,7 +1,11 @@
'use client';
import { Photo, PhotoDateRange } from '@/photo'; import { Photo, PhotoDateRange } from '@/photo';
import { descriptionForFilmPhotos } from '.'; import { descriptionForFilmPhotos } from '.';
import PhotoHeader from '@/photo/PhotoHeader'; import PhotoHeader from '@/photo/PhotoHeader';
import PhotoFilm from '@/film/PhotoFilm'; import PhotoFilm from '@/film/PhotoFilm';
import { getRecipePropsFromPhotos } from '@/recipe';
import { useAppState } from '@/state/AppState';
export default function FilmHeader({ export default function FilmHeader({
film, film,
@ -18,10 +22,23 @@ export default function FilmHeader({
count?: number count?: number
dateRange?: PhotoDateRange dateRange?: PhotoDateRange
}) { }) {
const { recipeModalProps, setRecipeModalProps } = useAppState();
// Only show recipe button when viewing individual photos
const recipeProps = selectedPhoto
? getRecipePropsFromPhotos(photos, selectedPhoto)
: undefined;
return ( return (
<PhotoHeader <PhotoHeader
film={film} film={film}
entity={<PhotoFilm {...{ film }} />} entity={<PhotoFilm
film={film}
isShowingRecipeOverlay={Boolean(recipeModalProps)}
toggleRecipeOverlay={recipeProps
? () => setRecipeModalProps?.(recipeProps)
: undefined}
/>}
entityDescription={descriptionForFilmPhotos( entityDescription={descriptionForFilmPhotos(
photos, undefined, count, dateRange)} photos, undefined, count, dateRange)}
photos={photos} photos={photos}

View File

@ -1,6 +1,5 @@
import PhotoFilmIcon from './PhotoFilmIcon'; import PhotoFilmIcon from './PhotoFilmIcon';
import { pathForFilm } from '@/app/paths'; import { pathForFilm } from '@/app/paths';
import { FujifilmRecipe } from '@/platforms/fujifilm/recipe';
import EntityLink, { import EntityLink, {
EntityLinkExternalProps, EntityLinkExternalProps,
} from '@/components/primitives/EntityLink'; } from '@/components/primitives/EntityLink';
@ -22,7 +21,6 @@ export default function PhotoFilm({
}: { }: {
film: string film: string
countOnHover?: number countOnHover?: number
recipe?: FujifilmRecipe
} & Partial<ComponentProps<typeof PhotoRecipeOverlayButton>> } & Partial<ComponentProps<typeof PhotoRecipeOverlayButton>>
& EntityLinkExternalProps) { & EntityLinkExternalProps) {
const { small, medium, large } = labelForFilm(film); const { small, medium, large } = labelForFilm(film);

View File

@ -4,7 +4,7 @@ import ImagePhotoGrid from './components/ImagePhotoGrid';
import ImageContainer from './components/ImageContainer'; import ImageContainer from './components/ImageContainer';
import type { NextImageSize } from '@/platforms/next-image'; import type { NextImageSize } from '@/platforms/next-image';
import { formatTag } from '@/tag'; import { formatTag } from '@/tag';
import { generateRecipeText, getPhotoWithRecipeFromPhotos } from '@/recipe'; import { generateRecipeText, getRecipePropsFromPhotos } from '@/recipe';
import PhotoFilmIcon from '@/film/PhotoFilmIcon'; import PhotoFilmIcon from '@/film/PhotoFilmIcon';
import { import {
isStringFujifilmSimulationLabel, isStringFujifilmSimulationLabel,
@ -27,16 +27,10 @@ export default function RecipeImageResponse({
fontFamily: string fontFamily: string
smallText?: boolean smallText?: boolean
}) { }) {
const { const { data, film } = getRecipePropsFromPhotos(photos) ?? {};
recipeData,
film,
} = getPhotoWithRecipeFromPhotos(photos) ?? {};
let recipeLines = recipeData && film let recipeLines = data && film
? generateRecipeText({ ? generateRecipeText({ data, film }, true)
data: recipeData,
film,
}, true)
: []; : [];
if (recipeLines && recipeLines.length > MAX_RECIPE_LINES) { if (recipeLines && recipeLines.length > MAX_RECIPE_LINES) {
@ -75,7 +69,7 @@ export default function RecipeImageResponse({
/>, />,
title: formatTag(recipe).toLocaleUpperCase(), title: formatTag(recipe).toLocaleUpperCase(),
}}> }}>
{recipeData && {data &&
<div <div
// tw="opacity-70" // tw="opacity-70"
style={{ style={{

View File

@ -4,7 +4,7 @@ import { Photo, PhotoDateRange } from '@/photo';
import PhotoHeader from '@/photo/PhotoHeader'; import PhotoHeader from '@/photo/PhotoHeader';
import PhotoRecipe from './PhotoRecipe'; import PhotoRecipe from './PhotoRecipe';
import { useAppState } from '@/state/AppState'; import { useAppState } from '@/state/AppState';
import { descriptionForRecipePhotos, getPhotoWithRecipeFromPhotos } from '.'; import { descriptionForRecipePhotos, getRecipePropsFromPhotos } from '.';
export default function RecipeHeader({ export default function RecipeHeader({
recipe, recipe,
@ -23,7 +23,7 @@ export default function RecipeHeader({
}) { }) {
const { recipeModalProps, setRecipeModalProps } = useAppState(); const { recipeModalProps, setRecipeModalProps } = useAppState();
const photo = getPhotoWithRecipeFromPhotos(photos, selectedPhoto); const recipeProps = getRecipePropsFromPhotos(photos, selectedPhoto);
return ( return (
<PhotoHeader <PhotoHeader
@ -32,16 +32,8 @@ export default function RecipeHeader({
recipe={recipe} recipe={recipe}
contrast="high" contrast="high"
isShowingRecipeOverlay={Boolean(recipeModalProps)} isShowingRecipeOverlay={Boolean(recipeModalProps)}
toggleRecipeOverlay={() => ( toggleRecipeOverlay={recipeProps
photo?.recipeData && ? () => setRecipeModalProps?.(recipeProps)
photo?.film
) ? setRecipeModalProps?.({
title: photo.recipeTitle,
data: photo.recipeData,
film: photo.film,
iso: photo.isoFormatted,
exposure: photo.exposureTimeFormatted,
})
: undefined} : undefined}
/>} />}
entityDescription={descriptionForRecipePhotos(photos, undefined, count)} entityDescription={descriptionForRecipePhotos(photos, undefined, count)}

View File

@ -132,7 +132,7 @@ export const generateMetaForRecipe = (
const photoHasRecipe = (photo?: Photo) => const photoHasRecipe = (photo?: Photo) =>
photo?.film && photo?.recipeData; photo?.film && photo?.recipeData;
export const getPhotoWithRecipeFromPhotos = ( const getPhotoWithRecipeFromPhotos = (
photos: Photo[], photos: Photo[],
preferredPhoto?: Photo, preferredPhoto?: Photo,
) => ) =>
@ -140,6 +140,21 @@ export const getPhotoWithRecipeFromPhotos = (
? preferredPhoto ? preferredPhoto
: photos.find(photoHasRecipe); : photos.find(photoHasRecipe);
export const getRecipePropsFromPhotos = (
...args: Parameters<typeof getPhotoWithRecipeFromPhotos>
): RecipeProps | undefined => {
const photo = getPhotoWithRecipeFromPhotos(...args);
return photo?.recipeData && photo?.film
? {
title: photo.recipeTitle,
data: photo.recipeData,
film: photo.film,
iso: photo.isoFormatted,
exposure: photo.exposureTimeFormatted,
}
: undefined;
};
export const sortRecipes = (recipes: Recipes = []) => export const sortRecipes = (recipes: Recipes = []) =>
recipes.sort((a, b) => a.recipe.localeCompare(b.recipe)); recipes.sort((a, b) => a.recipe.localeCompare(b.recipe));

View File

@ -1,3 +1,5 @@
'use client';
import { import {
Dispatch, Dispatch,
SetStateAction, SetStateAction,