From 4b69e5b33a1ece4e80e95a74fe972c48a0760a10 Mon Sep 17 00:00:00 2001 From: Ross <70717676+SkepticMystic@users.noreply.github.com> Date: Mon, 11 Aug 2025 23:17:28 +0200 Subject: [PATCH] feat: Button to select recipe cover image when creating recipe from multiple images (#5647) Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com> Co-authored-by: Kuchenpirat Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com> --- frontend/lang/messages/en-US.json | 4 +- .../pages/g/[groupSlug]/r/create/image.vue | 68 +++++++++++++++---- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/frontend/lang/messages/en-US.json b/frontend/lang/messages/en-US.json index 53ef08f83..85588bddd 100644 --- a/frontend/lang/messages/en-US.json +++ b/frontend/lang/messages/en-US.json @@ -673,7 +673,9 @@ "not-linked-ingredients": "Additional Ingredients", "upload-another-image": "Upload another image", "upload-images": "Upload images", - "upload-more-images": "Upload more images" + "upload-more-images": "Upload more images", + "set-as-cover-image": "Set as recipe cover image", + "cover-image": "Cover image" }, "recipe-finder": { "recipe-finder": "Recipe Finder", diff --git a/frontend/pages/g/[groupSlug]/r/create/image.vue b/frontend/pages/g/[groupSlug]/r/create/image.vue index 17c38489e..14cbcf4a5 100644 --- a/frontend/pages/g/[groupSlug]/r/create/image.vue +++ b/frontend/pages/g/[groupSlug]/r/create/image.vue @@ -32,15 +32,30 @@ lg="4" xl="3" > - + + + + + + {{ index === 0 ? $globals.icons.check : $globals.icons.fileImage }} + + + {{ index === 0 ? $t("recipe.cover-image") : $t("recipe.set-as-cover-image") }} + + @@ -106,11 +121,12 @@ export default defineNuxtComponent({ } function clearImage(index: number) { + // Revoke _before_ splicing URL.revokeObjectURL(uploadedImagesPreviewUrls.value[index]); - uploadedImages.value = uploadedImages.value.filter((_, i) => i !== index); - uploadedImageNames.value = uploadedImageNames.value.filter((_, i) => i !== index); - uploadedImagesPreviewUrls.value = uploadedImagesPreviewUrls.value.filter((_, i) => i !== index); + uploadedImages.value.splice(index, 1); + uploadedImageNames.value.splice(index, 1); + uploadedImagesPreviewUrls.value.splice(index, 1); } async function createRecipe() { @@ -119,6 +135,7 @@ export default defineNuxtComponent({ } state.loading = true; + const translateLanguage = shouldTranslate.value ? i18n.locale : undefined; const { data, error } = await api.recipes.createOneFromImages(uploadedImages.value, translateLanguage?.value); if (error || !data) { @@ -135,6 +152,32 @@ export default defineNuxtComponent({ uploadedImagesPreviewUrls.value[index] = URL.createObjectURL(croppedImage); } + function swapItem(array: any[], i: number, j: number) { + if (i < 0 || j < 0 || i >= array.length || j >= array.length) { + return; + } + + const temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + + function swapImages(i: number, j: number) { + swapItem(uploadedImages.value, i, j); + swapItem(uploadedImageNames.value, i, j); + swapItem(uploadedImagesPreviewUrls.value, i, j); + } + + // Put the intended cover image at the start of the array + // The backend currently sets the first image as the cover image + function setCoverImage(index: number) { + if (index < 0 || index >= uploadedImages.value.length || index === 0) { + return; + } + + swapImages(0, index); + } + return { ...toRefs(state), domUrlForm, @@ -145,6 +188,7 @@ export default defineNuxtComponent({ clearImage, createRecipe, updateUploadedImage, + setCoverImage, }; }, });