Files
matosbox/frontend/components/FileUploader.vue

95 lines
2.4 KiB
Vue

<template>
<div>
<div
class="card"
:style="dropStyle"
@dragenter.prevent="onDragEnter"
@dragover.prevent
@dragleave.prevent="onDragLeave"
@drop.prevent="onDrop"
>
<p>{{ label || t('fileUploader.label') }}</p>
<input :disabled="disabled" type="file" multiple @change="onFilesSelected" />
<button class="card" type="button" :disabled="disabled" @click="emitUpload">
{{ buttonText || t('actions.upload') }}
</button>
</div>
<div v-if="previews.length" class="grid" style="margin-top: 12px;">
<div v-for="preview in previews" :key="preview.name" class="card">
<img v-if="preview.url" :src="preview.url" :alt="preview.name" style="max-width: 100%;" />
<p>{{ preview.name }}</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const { t } = useI18n()
const props = defineProps({
disabled: { type: Boolean, default: false },
buttonText: { type: String, default: '' },
label: { type: String, default: '' }
})
const emit = defineEmits<{
(e: 'upload', files: FileList): void
}>()
const files = ref<FileList | null>(null)
const isDragging = ref(false)
const previews = ref<{ name: string; url?: string }[]>([])
const dropStyle = computed(() => ({
border: isDragging.value ? '2px dashed #c46b2d' : '1px dashed #d9c9b2',
padding: '16px',
cursor: props.disabled ? 'not-allowed' : 'pointer',
opacity: props.disabled ? '0.6' : '1'
}))
const onFilesSelected = (event: Event) => {
const target = event.target as HTMLInputElement
files.value = target.files
buildPreviews(target.files)
}
const emitUpload = () => {
if (!files.value || files.value.length === 0) {
return
}
emit('upload', files.value)
}
const onDragEnter = () => {
if (props.disabled) return
isDragging.value = true
}
const onDragLeave = () => {
isDragging.value = false
}
const onDrop = (event: DragEvent) => {
if (props.disabled) return
isDragging.value = false
if (event.dataTransfer?.files) {
files.value = event.dataTransfer.files
buildPreviews(event.dataTransfer.files)
}
}
const buildPreviews = (fileList: FileList | null) => {
previews.value = []
if (!fileList) return
Array.from(fileList).forEach((file) => {
if (file.type.startsWith('image/')) {
const url = URL.createObjectURL(file)
previews.value.push({ name: file.name, url })
} else {
previews.value.push({ name: file.name })
}
})
}
</script>