121 lines
2.9 KiB
JavaScript
121 lines
2.9 KiB
JavaScript
export default {
|
|
template: `
|
|
<div
|
|
class="file-drop-zone"
|
|
:class="{ 'dragging': isDragging }"
|
|
@click="openFileDialog"
|
|
@dragover.prevent="onDragOver"
|
|
@dragleave.prevent="onDragLeave"
|
|
@drop.prevent="onDrop"
|
|
style="border: 2px dashed #d1d5db; border-radius: 8px; padding: 32px; text-align: center; cursor: pointer; transition: all 0.3s ease; min-height: 120px; display: flex; flex-direction: column; align-items: center; justify-content: center;"
|
|
>
|
|
<div style="color: #9ca3af; font-size: 48px; margin-bottom: 16px;">☁️</div>
|
|
<div style="font-size: 18px; color: #6b7280; margin-bottom: 8px;">Drop files here or click to browse</div>
|
|
<div style="font-size: 14px; color: #9ca3af;">Drag and drop your files</div>
|
|
|
|
<input
|
|
ref="fileInput"
|
|
type="file"
|
|
:multiple="multiple"
|
|
:accept="accept"
|
|
@change="onFileInputChange"
|
|
style="display: none;"
|
|
/>
|
|
</div>
|
|
`,
|
|
props: {
|
|
multiple: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
accept: {
|
|
type: String,
|
|
default: null
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
isDragging: false
|
|
};
|
|
},
|
|
methods: {
|
|
openFileDialog() {
|
|
this.$refs.fileInput.click();
|
|
},
|
|
|
|
onDragOver(e) {
|
|
e.preventDefault();
|
|
this.isDragging = true;
|
|
},
|
|
|
|
onDragLeave(e) {
|
|
e.preventDefault();
|
|
this.isDragging = false;
|
|
},
|
|
|
|
async onDrop(e) {
|
|
e.preventDefault();
|
|
this.isDragging = false;
|
|
|
|
const files = Array.from(e.dataTransfer.files);
|
|
if (files.length === 0) return;
|
|
|
|
await this.processFiles(files);
|
|
},
|
|
|
|
async onFileInputChange(e) {
|
|
const files = Array.from(e.target.files);
|
|
if (files.length === 0) return;
|
|
|
|
await this.processFiles(files);
|
|
|
|
// Clear the input
|
|
e.target.value = '';
|
|
},
|
|
|
|
async processFiles(files) {
|
|
if (!this.multiple && files.length > 1) {
|
|
files = [files[0]];
|
|
}
|
|
|
|
const filesData = [];
|
|
|
|
for (const file of files) {
|
|
const content = await this.readFileAsBase64(file);
|
|
|
|
filesData.push({
|
|
name: file.name,
|
|
size: file.size,
|
|
type: file.type || 'application/octet-stream',
|
|
content: content
|
|
});
|
|
}
|
|
|
|
this.$emit('upload', filesData);
|
|
},
|
|
|
|
readFileAsBase64(file) {
|
|
return new Promise((resolve) => {
|
|
const reader = new FileReader();
|
|
reader.onload = () => {
|
|
// Remove the data URL prefix to get just the base64 content
|
|
const base64 = reader.result.split(',')[1];
|
|
resolve(base64);
|
|
};
|
|
reader.readAsDataURL(file);
|
|
});
|
|
}
|
|
},
|
|
|
|
style: `
|
|
.file-drop-zone.dragging {
|
|
border-color: #3b82f6 !important;
|
|
background-color: #eff6ff !important;
|
|
}
|
|
|
|
.file-drop-zone:hover {
|
|
border-color: #9ca3af !important;
|
|
background-color: #f9fafb !important;
|
|
}
|
|
`
|
|
}; |