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 <jojow@gmx.net>
Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com>
This commit is contained in:
Ross 2025-08-11 23:17:28 +02:00 committed by GitHub
commit 4b69e5b33a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 59 additions and 13 deletions

View file

@ -673,7 +673,9 @@
"not-linked-ingredients": "Additional Ingredients", "not-linked-ingredients": "Additional Ingredients",
"upload-another-image": "Upload another image", "upload-another-image": "Upload another image",
"upload-images": "Upload images", "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": "Recipe Finder", "recipe-finder": "Recipe Finder",

View file

@ -32,15 +32,30 @@
lg="4" lg="4"
xl="3" xl="3"
> >
<ImageCropper <v-col>
:img="imageUrl" <ImageCropper
cropper-height="100%" :img="imageUrl"
cropper-width="100%" cropper-height="100%"
:submitted="loading" cropper-width="100%"
class="mt-4" :submitted="loading"
@save="(croppedImage) => updateUploadedImage(index, croppedImage)" class="mt-4 mb-2"
@delete="clearImage(index)" @save="(croppedImage) => updateUploadedImage(index, croppedImage)"
/> @delete="clearImage(index)"
/>
<v-btn
v-if="uploadedImages.length > 1"
:disabled="loading || index === 0"
color="primary"
@click="() => setCoverImage(index)"
>
<v-icon start>
{{ index === 0 ? $globals.icons.check : $globals.icons.fileImage }}
</v-icon>
{{ index === 0 ? $t("recipe.cover-image") : $t("recipe.set-as-cover-image") }}
</v-btn>
</v-col>
</v-col> </v-col>
</v-row> </v-row>
</div> </div>
@ -106,11 +121,12 @@ export default defineNuxtComponent({
} }
function clearImage(index: number) { function clearImage(index: number) {
// Revoke _before_ splicing
URL.revokeObjectURL(uploadedImagesPreviewUrls.value[index]); URL.revokeObjectURL(uploadedImagesPreviewUrls.value[index]);
uploadedImages.value = uploadedImages.value.filter((_, i) => i !== index); uploadedImages.value.splice(index, 1);
uploadedImageNames.value = uploadedImageNames.value.filter((_, i) => i !== index); uploadedImageNames.value.splice(index, 1);
uploadedImagesPreviewUrls.value = uploadedImagesPreviewUrls.value.filter((_, i) => i !== index); uploadedImagesPreviewUrls.value.splice(index, 1);
} }
async function createRecipe() { async function createRecipe() {
@ -119,6 +135,7 @@ export default defineNuxtComponent({
} }
state.loading = true; state.loading = true;
const translateLanguage = shouldTranslate.value ? i18n.locale : undefined; const translateLanguage = shouldTranslate.value ? i18n.locale : undefined;
const { data, error } = await api.recipes.createOneFromImages(uploadedImages.value, translateLanguage?.value); const { data, error } = await api.recipes.createOneFromImages(uploadedImages.value, translateLanguage?.value);
if (error || !data) { if (error || !data) {
@ -135,6 +152,32 @@ export default defineNuxtComponent({
uploadedImagesPreviewUrls.value[index] = URL.createObjectURL(croppedImage); 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 { return {
...toRefs(state), ...toRefs(state),
domUrlForm, domUrlForm,
@ -145,6 +188,7 @@ export default defineNuxtComponent({
clearImage, clearImage,
createRecipe, createRecipe,
updateUploadedImage, updateUploadedImage,
setCoverImage,
}; };
}, },
}); });