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

View File

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

View File

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

View File

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

View File

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

View File

@ -132,7 +132,7 @@ export const generateMetaForRecipe = (
const photoHasRecipe = (photo?: Photo) =>
photo?.film && photo?.recipeData;
export const getPhotoWithRecipeFromPhotos = (
const getPhotoWithRecipeFromPhotos = (
photos: Photo[],
preferredPhoto?: Photo,
) =>
@ -140,6 +140,21 @@ export const getPhotoWithRecipeFromPhotos = (
? preferredPhoto
: 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 = []) =>
recipes.sort((a, b) => a.recipe.localeCompare(b.recipe));

View File

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