mirror of
https://github.com/directus/directus.git
synced 2026-01-29 03:37:56 -05:00
move options to v-upload
This commit is contained in:
@@ -29,15 +29,66 @@
|
||||
<p class="type-label">{{ $t('drag_file_here') }}</p>
|
||||
<p class="type-text">{{ $t('click_to_browse') }}</p>
|
||||
<input class="browse" type="file" @input="onBrowseSelect" />
|
||||
|
||||
<template v-if="fromUrl !== false || fromLibrary !== false">
|
||||
<v-menu showArrow placement="bottom-end">
|
||||
<template #activator="{ toggle }">
|
||||
<v-icon @click="toggle" class="options" name="more_vert" />
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item @click="activeDialog = 'choose'" v-if="fromLibrary">
|
||||
<v-list-item-icon><v-icon name="folder_open" /></v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
{{ $t('choose_from_library') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item @click="activeDialog = 'url'" v-if="fromUrl">
|
||||
<v-list-item-icon><v-icon name="link" /></v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
{{ $t('import_from_url') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
<modal-browse
|
||||
collection="directus_files"
|
||||
:active="activeDialog === 'choose'"
|
||||
@update:active="activeDialog = null"
|
||||
@input="setSelection"
|
||||
/>
|
||||
|
||||
<v-dialog :active="activeDialog === 'url'" @toggle="activeDialog = null" :persistent="urlLoading">
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('import_from_url') }}</v-card-title>
|
||||
<v-card-text>
|
||||
<v-input :placeholder="$t('url')" v-model="url" :disabled="urlLoading" />
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-button :disabled="urlLoading" @click="activeDialog = null" secondary>
|
||||
{{ $t('cancel') }}
|
||||
</v-button>
|
||||
<v-button :loading="urlLoading" @click="importFromURL" :disabled="isValidURL === false">
|
||||
{{ $t('import') }}
|
||||
</v-button>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from '@vue/composition-api';
|
||||
import { defineComponent, ref, computed, watch } from '@vue/composition-api';
|
||||
import uploadFiles from '@/utils/upload-files';
|
||||
import ModalBrowse from '@/views/private/components/modal-browse';
|
||||
import api from '@/api';
|
||||
import useItem from '@/composables/use-item';
|
||||
|
||||
export default defineComponent({
|
||||
components: { ModalBrowse },
|
||||
props: {
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
@@ -47,10 +98,21 @@ export default defineComponent({
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
fromUrl: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
fromLibrary: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const { uploading, progress, error, upload, onBrowseSelect, done, numberOfFiles } = useUpload();
|
||||
const { onDragEnter, onDragLeave, onDrop, dragging } = useDragging();
|
||||
const { url, isValidURL, loading: urlLoading, error: urlError, importFromURL } = useURLImport();
|
||||
const { setSelection } = useSelection();
|
||||
const activeDialog = ref<'choose' | 'url' | null>(null);
|
||||
|
||||
return {
|
||||
uploading,
|
||||
@@ -63,6 +125,12 @@ export default defineComponent({
|
||||
onBrowseSelect,
|
||||
done,
|
||||
numberOfFiles,
|
||||
activeDialog,
|
||||
url,
|
||||
isValidURL,
|
||||
urlLoading,
|
||||
importFromURL,
|
||||
setSelection,
|
||||
};
|
||||
|
||||
function useUpload() {
|
||||
@@ -146,6 +214,67 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function useSelection() {
|
||||
const collection = ref('directus_files');
|
||||
const image = ref<string | null>(null);
|
||||
const { item, error, loading } = useItem(collection, image);
|
||||
|
||||
function setSelection(selection: string[]) {
|
||||
if (selection[0]) {
|
||||
image.value = selection[0];
|
||||
} else {
|
||||
image.value = null;
|
||||
emit('upload', null);
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => item.value,
|
||||
(id) => {
|
||||
if (error.value === null && loading.value === false) {
|
||||
emit('upload', item.value);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return { setSelection };
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
emit('upload', response.data.data);
|
||||
activeDialog.value = null;
|
||||
url.value = '';
|
||||
} catch (err) {
|
||||
error.value = err;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -214,4 +343,17 @@ export default defineComponent({
|
||||
width: calc(100% - 64px);
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
color: var(--foreground-subdued);
|
||||
cursor: pointer;
|
||||
transition: color var(--medium) var(--transition);
|
||||
}
|
||||
|
||||
.v-upload:hover .options {
|
||||
color: var(--primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('upload_from_device') }}</v-card-title>
|
||||
<v-card-text>
|
||||
<v-upload @upload="onUpload" />
|
||||
<v-upload @upload="onUpload" fromUrl />
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-button @click="activeDialog = null" secondary>{{ $t('cancel') }}</v-button>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<v-dialog v-model="showUpload">
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('upload_file') }}</v-card-title>
|
||||
<v-card-text><v-upload @upload="onUpload" multiple /></v-card-text>
|
||||
<v-card-text><v-upload @upload="onUpload" multiple fromUrl /></v-card-text>
|
||||
<v-card-actions>
|
||||
<v-button @click="showUpload = false">{{ $t('done') }}</v-button>
|
||||
</v-card-actions>
|
||||
|
||||
@@ -45,53 +45,7 @@
|
||||
/>
|
||||
<file-lightbox v-model="lightboxActive" :id="image.id" />
|
||||
</div>
|
||||
<template v-else>
|
||||
<v-upload @upload="setImage" />
|
||||
<v-menu showArrow placement="bottom-end">
|
||||
<template #activator="{ toggle }">
|
||||
<v-icon @click="toggle" class="options" name="more_vert" />
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item @click="activeDialog = 'choose'">
|
||||
<v-list-item-icon><v-icon name="folder_open" /></v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
{{ $t('choose_from_library') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item @click="activeDialog = 'url'">
|
||||
<v-list-item-icon><v-icon name="link" /></v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
{{ $t('import_from_url') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
<modal-browse
|
||||
collection="directus_files"
|
||||
:active="activeDialog === 'choose'"
|
||||
@update:active="activeDialog = null"
|
||||
@input="setSelection"
|
||||
/>
|
||||
|
||||
<v-dialog :active="activeDialog === 'url'" @toggle="activeDialog = null" :persistent="urlLoading">
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('import_from_url') }}</v-card-title>
|
||||
<v-card-text>
|
||||
<v-input :placeholder="$t('url')" v-model="url" :disabled="urlLoading" />
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-button :disabled="urlLoading" @click="activeDialog = null" secondary>
|
||||
{{ $t('cancel') }}
|
||||
</v-button>
|
||||
<v-button :loading="urlLoading" @click="importFromURL" :disabled="isValidURL === false">
|
||||
{{ $t('import') }}
|
||||
</v-button>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
<v-upload v-else @upload="setImage" fromLibrary fromUrl />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -102,7 +56,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';
|
||||
|
||||
@@ -116,7 +70,7 @@ type Image = {
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
components: { FileLightbox, ImageEditor, ModalBrowse },
|
||||
components: { FileLightbox, ImageEditor },
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
@@ -128,7 +82,6 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const activeDialog = ref<'choose' | 'url' | null>(null);
|
||||
const loading = ref(false);
|
||||
const image = ref<Image | null>(null);
|
||||
const error = ref(null);
|
||||
@@ -180,8 +133,6 @@ export default defineComponent({
|
||||
}
|
||||
);
|
||||
|
||||
const { url, isValidURL, loading: urlLoading, error: urlError, importFromURL } = useURLImport();
|
||||
|
||||
return {
|
||||
loading,
|
||||
image,
|
||||
@@ -194,12 +145,6 @@ export default defineComponent({
|
||||
setImage,
|
||||
deselect,
|
||||
downloadSrc,
|
||||
activeDialog,
|
||||
setSelection,
|
||||
url,
|
||||
isValidURL,
|
||||
urlLoading,
|
||||
importFromURL,
|
||||
};
|
||||
|
||||
async function fetchImage() {
|
||||
@@ -238,51 +183,6 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -402,17 +302,4 @@ 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);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('add_file') }}</v-card-title>
|
||||
<v-card-text>
|
||||
<v-upload :preset="preset" multiple @upload="close" />
|
||||
<v-upload :preset="preset" multiple @upload="close" fromUrl />
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-button secondary @click="close">{{ $t('done') }}</v-button>
|
||||
|
||||
Reference in New Issue
Block a user