{text}
- {isStringFilmSimulation(text) &&
+ {isStringFilmSimulation(text) && filmSimulation &&
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
}
}