diff --git a/app/src/interfaces/image/image.vue b/app/src/interfaces/image/image.vue
index d4be98475d..8221eaf97c 100644
--- a/app/src/interfaces/image/image.vue
+++ b/app/src/interfaces/image/image.vue
@@ -45,7 +45,53 @@
/>
-
+
+
+
+
+
+
+
+
+
+
+ {{ $t('choose_from_library') }}
+
+
+
+
+
+
+ {{ $t('import_from_url') }}
+
+
+
+
+
+
+
+
+
+ {{ $t('import_from_url') }}
+
+
+
+
+
+ {{ $t('cancel') }}
+
+
+ {{ $t('import') }}
+
+
+
+
+
@@ -56,6 +102,7 @@ import formatFilesize from '@/utils/format-filesize';
import i18n from '@/lang';
import FileLightbox from '@/views/private/components/file-lightbox';
import ImageEditor from '@/views/private/components/image-editor';
+import ModalBrowse from '@/views/private/components/modal-browse';
import { nanoid } from 'nanoid';
import getRootPath from '@/utils/get-root-path';
@@ -69,7 +116,7 @@ type Image = {
};
export default defineComponent({
- components: { FileLightbox, ImageEditor },
+ components: { FileLightbox, ImageEditor, ModalBrowse },
props: {
value: {
type: String,
@@ -81,6 +128,7 @@ export default defineComponent({
},
},
setup(props, { emit }) {
+ const activeDialog = ref<'choose' | 'url' | null>(null);
const loading = ref(false);
const image = ref(null);
const error = ref(null);
@@ -132,6 +180,8 @@ export default defineComponent({
}
);
+ const { url, isValidURL, loading: urlLoading, error: urlError, importFromURL } = useURLImport();
+
return {
loading,
image,
@@ -144,6 +194,12 @@ export default defineComponent({
setImage,
deselect,
downloadSrc,
+ activeDialog,
+ setSelection,
+ url,
+ isValidURL,
+ urlLoading,
+ importFromURL,
};
async function fetchImage() {
@@ -182,6 +238,51 @@ export default defineComponent({
lightboxActive.value = false;
editorActive.value = false;
}
+
+ function setSelection(selection: number[]) {
+ if (selection[0]) {
+ emit('input', selection[0]);
+ } else {
+ emit('input', null);
+ }
+ }
+
+ function useURLImport() {
+ const url = ref('');
+ const loading = ref(false);
+ const error = ref(null);
+
+ const isValidURL = computed(() => {
+ try {
+ new URL(url.value);
+ return true;
+ } catch {
+ return false;
+ }
+ });
+
+ return { url, loading, error, isValidURL, importFromURL };
+
+ async function importFromURL() {
+ loading.value = true;
+
+ try {
+ const response = await api.post(`/files/import`, {
+ url: url.value,
+ });
+
+ image.value = response.data.data;
+
+ activeDialog.value = null;
+ url.value = '';
+ emit('input', image.value?.id);
+ } catch (err) {
+ error.value = err;
+ } finally {
+ loading.value = false;
+ }
+ }
+ }
},
});
@@ -301,4 +402,17 @@ img {
.disabled-placeholder {
height: var(--input-height-tall);
}
+
+.options {
+ position: absolute;
+ top: 13px;
+ right: 13px;
+ color: var(--foreground-subdued);
+ cursor: pointer;
+ transition: color var(--medium) var(--transition);
+}
+
+.image:hover .options {
+ color: var(--primary);
+}