diff --git a/src/components/images/ImagePickerDialog.vue b/src/components/images/ImagePickerDialog.vue index 77dc7154910a223d9245aafa8fe5721b37f84741..78becbf26f74b63c1276f6d19d934446ea798830 100644 --- a/src/components/images/ImagePickerDialog.vue +++ b/src/components/images/ImagePickerDialog.vue @@ -5,46 +5,48 @@ :title="t('imagePicker.title')" class="tw-w-screen md:tw-w-[700px]" > - <div - v-if="!selectedImage && !showBrowser" - class="tw-flex tw-flex-wrap tw-items-center tw-gap-3" - > - <ImageUploader class="tw-grow md:tw-grow-0" @input="setImage" /> - <button - v-if="imageStore.count > 0" - type="button" - class="btn btn-default tw-grow md:tw-grow-0" - @click.stop="showBrowser = true" + <form :id="id" @submit.prevent.stop="submit($event as SubmitEvent)"> + <div + v-if="!selectedImage && !showBrowser" + class="tw-flex tw-flex-wrap tw-items-center tw-gap-3" > - <icon-system-uicons-search /> - {{ t('imagePicker.browseImages') }} - </button> - <button - v-if="currentImage" - type="button" - class="btn btn-default tw-grow md:tw-grow-0" - @click.stop="selectedImage = currentImage" - > - <icon-system-uicons-pen /> - {{ t('imagePicker.editCurrentImage') }} - </button> - </div> + <ImageUploader class="tw-grow md:tw-grow-0" @input="setImage" /> + <button + v-if="imageStore.count > 0" + type="button" + class="btn btn-default tw-grow md:tw-grow-0" + @click.stop="showBrowser = true" + > + <icon-system-uicons-search /> + {{ t('imagePicker.browseImages') }} + </button> + <button + v-if="currentImage" + type="button" + class="btn btn-default tw-grow md:tw-grow-0" + @click.stop="selectedImage = currentImage" + > + <icon-system-uicons-pen /> + {{ t('imagePicker.editCurrentImage') }} + </button> + </div> - <AAlert v-if="error" is-error aria-live="assertive" class="tw-mb-3"> - {{ error.message }} - </AAlert> + <AAlert v-if="error" is-error aria-live="assertive" class="tw-mb-3"> + {{ error.message }} + </AAlert> - <ImageBrowser v-if="showBrowser" @input="setImage" /> - <ImageEditor v-if="selectedImage" v-model="selectedImage" :disabled="isSaving" /> + <ImageBrowser v-if="showBrowser" @input="setImage" /> + <ImageEditor v-if="selectedImage" v-model="selectedImage" :disabled="isSaving" /> + </form> <template v-if="showBrowser || selectedImage" #footer> <div class="tw-flex tw-gap-x-3"> <button v-if="selectedImage" :disabled="isSaving" - type="button" + type="submit" + :form="id" class="btn btn-primary" - @click.stop="selectedImage && saveAndSelectImage(selectedImage)" > <icon-system-uicons-loader v-if="isSaving" class="tw-animate-spin" /> <template v-if="isSelectedImageNew">{{ t('imagePicker.useImage') }}</template> @@ -77,7 +79,7 @@ import { APIResponseError } from '@rokoli/bnb/drf' import { computed, ref } from 'vue' import { useI18n } from '@/i18n' import { Image, NewImage, useImage, useImageStore } from '@/stores/images' -import { useAsyncFunction } from '@/util' +import { useAsyncFunction, useId } from '@/util' import { useCopy } from '@/form' import ADialog from '../generic/ADialog.vue' import ImageBrowser from './ImageBrowser.vue' @@ -96,6 +98,7 @@ const emit = defineEmits<{ const { t } = useI18n() const imageStore = useImageStore() const localIsOpen = useCopy(() => props.isOpen, { save: (isOpen) => emit('show', isOpen) }) +const id = useId('image-form') const error = ref<Error>() const showBrowser = ref(false) const selectedImage = ref<Image | NewImage | null>(null) @@ -141,6 +144,13 @@ const { isProcessing: isSaving, fn: saveAndSelectImage } = useAsyncFunction( }, ) +async function submit(event: SubmitEvent) { + if (!selectedImage.value) return + const form = event.target as HTMLFormElement + if (!form.checkValidity()) return + await saveAndSelectImage(selectedImage.value) +} + function setImage(image: Image | NewImage | null) { selectedImage.value = image showBrowser.value = false