diff --git a/app/admin/recipes/[recipe]/edit/page.tsx b/app/admin/recipes/[recipe]/edit/page.tsx index 6f62d74e..4c85519a 100644 --- a/app/admin/recipes/[recipe]/edit/page.tsx +++ b/app/admin/recipes/[recipe]/edit/page.tsx @@ -1,7 +1,7 @@ import AdminChildPage from '@/components/AdminChildPage'; import { redirect } from 'next/navigation'; import { getPhotosCached } from '@/photo/cache'; -import { PATH_ADMIN, PATH_ADMIN_TAGS, pathForRecipe } from '@/app/paths'; +import { PATH_ADMIN, PATH_ADMIN_RECIPES, pathForRecipe } from '@/app/paths'; import PhotoLightbox from '@/photo/PhotoLightbox'; import { getPhotosMeta } from '@/photo/db/query'; import AdminRecipeBadge from '@/admin/AdminRecipeBadge'; @@ -39,8 +39,8 @@ export default async function RecipePageEdit({ return ( } accessory={recipeData && filmSimulation && []); +export default async function AdminRecipesPage() { + const recipes = await getUniqueRecipes().catch(() => []); return ( []); + const tags = await getUniqueTagsHidden().catch(() => []); return ( - {/* Form data: tag to be replaced */} + {/* Form data: recipe to be replaced */} - {/* Form data: updated tag */} + {/* Form data: updated recipe */} ['color'] className?: string }) { const button = @@ -38,7 +41,7 @@ export default function CopyButton({ return ( tooltip - ? + ? {button} : button diff --git a/src/components/primitives/MenuSurface.tsx b/src/components/primitives/MenuSurface.tsx index 9fdb7c88..bf7ad58d 100644 --- a/src/components/primitives/MenuSurface.tsx +++ b/src/components/primitives/MenuSurface.tsx @@ -5,18 +5,22 @@ export default function MenuSurface({ ref, children, className, + color, }: { ref?: RefObject children: ReactNode className?: string + color?: 'light' | 'dark' | 'frosted' }) { return (
['color'] children: ReactNode }) { const refTrigger = useRef(null); @@ -59,7 +61,7 @@ export default function TooltipPrimitive({ {children} } - + {content && - + {content} } diff --git a/src/photo/actions.ts b/src/photo/actions.ts index 3cdf0e2d..8351b47b 100644 --- a/src/photo/actions.ts +++ b/src/photo/actions.ts @@ -10,6 +10,8 @@ import { getPhotos, addTagsToPhotos, getUniqueTags, + deletePhotoRecipeGlobally, + renamePhotoRecipeGlobally, } from '@/photo/db/query'; import { GetPhotosOptions, areOptionsSensitive } from './db'; import { @@ -25,10 +27,12 @@ import { revalidateAllKeysAndPaths, revalidatePhoto, revalidatePhotosKey, + revalidateRecipesKey, revalidateTagsKey, } from '@/photo/cache'; import { PATH_ADMIN_PHOTOS, + PATH_ADMIN_RECIPES, PATH_ADMIN_TAGS, PATH_ROOT, pathForPhoto, @@ -301,6 +305,29 @@ export const renamePhotoTagGloballyAction = async (formData: FormData) => } }); +export const deletePhotoRecipeGloballyAction = async (formData: FormData) => + runAuthenticatedAdminServerAction(async () => { + const recipe = formData.get('recipe') as string; + + await deletePhotoRecipeGlobally(recipe); + + revalidatePhotosKey(); + revalidateAdminPaths(); + }); + +export const renamePhotoRecipeGloballyAction = async (formData: FormData) => + runAuthenticatedAdminServerAction(async () => { + const recipe = formData.get('recipe') as string; + const updatedRecipe = formData.get('updatedRecipe') as string; + + if (recipe && updatedRecipe && recipe !== updatedRecipe) { + await renamePhotoRecipeGlobally(recipe, updatedRecipe); + revalidatePhotosKey(); + revalidateRecipesKey(); + redirect(PATH_ADMIN_RECIPES); + } + }); + export const deleteUploadsAction = async (urls: string[]) => runAuthenticatedAdminServerAction(async () => { await Promise.all(urls.map(url => deleteFile(url))); diff --git a/src/photo/cache.ts b/src/photo/cache.ts index c9e4c03f..eaf175e2 100644 --- a/src/photo/cache.ts +++ b/src/photo/cache.ts @@ -30,6 +30,8 @@ import { PATH_ROOT, PREFIX_CAMERA, PREFIX_FILM_SIMULATION, + PREFIX_FOCAL_LENGTH, + PREFIX_RECIPE, PREFIX_TAG, pathForPhoto, } from '@/app/paths'; @@ -97,17 +99,25 @@ export const revalidatePhotosKey = () => export const revalidateTagsKey = () => revalidateTag(KEY_TAGS); +export const revalidateRecipesKey = () => + revalidateTag(KEY_RECIPES); + export const revalidateCamerasKey = () => revalidateTag(KEY_CAMERAS); export const revalidateFilmSimulationsKey = () => revalidateTag(KEY_FILM_SIMULATIONS); +export const revalidateFocalLengthsKey = () => + revalidateTag(KEY_FOCAL_LENGTHS); + export const revalidateAllKeys = () => { revalidatePhotosKey(); revalidateTagsKey(); revalidateCamerasKey(); revalidateFilmSimulationsKey(); + revalidateRecipesKey(); + revalidateFocalLengthsKey(); }; export const revalidateAdminPaths = () => { @@ -125,6 +135,8 @@ export const revalidatePhoto = (photoId: string) => { revalidateTagsKey(); revalidateCamerasKey(); revalidateFilmSimulationsKey(); + revalidateRecipesKey(); + revalidateFocalLengthsKey(); // Paths revalidatePath(pathForPhoto({ photo: photoId }), 'layout'); revalidatePath(PATH_ROOT, 'layout'); @@ -133,6 +145,8 @@ export const revalidatePhoto = (photoId: string) => { revalidatePath(PREFIX_TAG, 'layout'); revalidatePath(PREFIX_CAMERA, 'layout'); revalidatePath(PREFIX_FILM_SIMULATION, 'layout'); + revalidatePath(PREFIX_RECIPE, 'layout'); + revalidatePath(PREFIX_FOCAL_LENGTH, 'layout'); revalidatePath(PATH_ADMIN, 'layout'); }; diff --git a/src/photo/db/query.ts b/src/photo/db/query.ts index 4ee241ed..3e742f4d 100644 --- a/src/photo/db/query.ts +++ b/src/photo/db/query.ts @@ -265,6 +265,23 @@ export const addTagsToPhotos = (tags: string[], photoIds: string[]) => convertArrayToPostgresString(photoIds), ]), 'addTagsToPhotos'); +export const deletePhotoRecipeGlobally = (recipe: string) => + safelyQueryPhotos(() => sql` + UPDATE photos + SET recipe_title=NULL + WHERE recipe_title=${recipe} + `, 'deletePhotoRecipeGlobally'); + +export const renamePhotoRecipeGlobally = ( + recipe: string, + updatedRecipe: string, +) => + safelyQueryPhotos(() => sql` + UPDATE photos + SET recipe_title=${updatedRecipe} + WHERE recipe_title=${recipe} + `, 'renamePhotoRecipeGlobally'); + export const deletePhoto = (id: string) => safelyQueryPhotos(() => sql` DELETE FROM photos WHERE id=${id} diff --git a/src/recipe/PhotoRecipeOverlay.tsx b/src/recipe/PhotoRecipeOverlay.tsx index 54efd096..b94ddc5c 100644 --- a/src/recipe/PhotoRecipeOverlay.tsx +++ b/src/recipe/PhotoRecipeOverlay.tsx @@ -124,11 +124,12 @@ export default function PhotoRecipeOverlay({ text={generateRecipeText({ recipe, simulation }).join('\n')} iconSize={17} className={clsx( - 'translate-y-[1.5px]', + 'translate-y-[-0.5px]', 'text-black/40 active:text-black/75', 'hover:text-black/40', )} tooltip="Copy recipe text" + tooltipColor="frosted" /> } diff --git a/tailwind.css b/tailwind.css index 564b8471..f2f8f7d5 100644 --- a/tailwind.css +++ b/tailwind.css @@ -324,6 +324,18 @@ @layer components { .component-surface { @apply - bg-content rounded-lg + text-main bg-content rounded-lg + } + .component-surface-light { + @apply + text-dark bg-white rounded-lg + } + .component-surface-dark { + @apply + text-light bg-black rounded-lg + } + .component-surface-frosted { + @apply + text-black bg-neutral-200/95 rounded-lg } }