|
<script setup> |
|
import { ref, watch, computed } from "vue"; |
|
|
|
// TODO: handle only video file |
|
const dropzoneInput = ref(null); |
|
const uploadedVideoFile = ref(null); |
|
const isUploaded = computed(() => (uploadedVideoFile.value ? true : false)); |
|
const isDragOver = ref(false); |
|
|
|
// Emit events |
|
const emit = defineEmits(["fileUploaded"]); |
|
watch( |
|
() => uploadedVideoFile.value, |
|
(newData, oldData) => { |
|
if (newData) { |
|
emit("fileUploaded", newData); |
|
} |
|
} |
|
); |
|
|
|
// * Handle Drag Events |
|
const removeDragEventDefault = (event) => { |
|
event.preventDefault(); |
|
event.stopPropagation(); |
|
}; |
|
const handleDragOver = (event) => { |
|
removeDragEventDefault(event); |
|
isDragOver.value = true; |
|
}; |
|
const handleDragLeave = (event) => { |
|
removeDragEventDefault(event); |
|
isDragOver.value = false; |
|
}; |
|
const handleDrop = (event) => { |
|
removeDragEventDefault(event); |
|
isDragOver.value = false; |
|
|
|
let videoFile = event.dataTransfer.files[0]; |
|
|
|
let dataTransfer = new DataTransfer(); |
|
dataTransfer.items.add(videoFile); |
|
let filesToBeAdded = dataTransfer.files; |
|
|
|
dropzoneInput.value.files = filesToBeAdded; |
|
uploadedVideoFile.value = videoFile; |
|
}; |
|
|
|
// Handle File Input |
|
const openFileInput = () => { |
|
dropzoneInput.value.click(); |
|
}; |
|
const handleClickUpload = (event) => { |
|
const target = event.target; |
|
if (target && target.files) { |
|
uploadedVideoFile.value = target.files[0]; |
|
} |
|
}; |
|
|
|
// Other utils func |
|
const byteToMB = (bytes) => { |
|
return Math.round(bytes / 1000000); |
|
}; |
|
</script> |
|
|
|
<template> |
|
<div |
|
class="dropzone" |
|
:class="{ 'dropzone-dragging': isDragOver }" |
|
id="dropzone" |
|
@drag="removeDragEventDefault" |
|
@dragstart="removeDragEventDefault" |
|
@dragend="removeDragEventDefault" |
|
@dragover="handleDragOver" |
|
@dragenter="handleDragLeave" |
|
@dragleave="removeDragEventDefault" |
|
@drop="handleDrop" |
|
@click.self="openFileInput" |
|
> |
|
<!-- Initial Stage --> |
|
<template v-if="!isUploaded"> |
|
<i class="fa-solid fa-cloud-arrow-up dropzone-icon"></i> |
|
Drop files or Click here to select files to upload. |
|
</template> |
|
|
|
<!-- Uploaded State --> |
|
<template v-else> |
|
<i class="fa-regular fa-file-video dropzone-icon"></i> |
|
{{ uploadedVideoFile.name }} |
|
({{ byteToMB(uploadedVideoFile.size) }} MB) |
|
</template> |
|
|
|
<input |
|
type="file" |
|
name="files" |
|
class="dropzone-input" |
|
ref="dropzoneInput" |
|
@change="handleClickUpload" |
|
/> |
|
</div> |
|
</template> |
|
|
|
<style lang="scss" scoped> |
|
.dropzone { |
|
display: flex; |
|
flex-direction: column; |
|
justify-content: center; |
|
align-items: center; |
|
border: 0.2rem dashed var(--primary-color); |
|
padding: 2rem; |
|
border-radius: 0.25rem; |
|
background-color: |
|
font-size: 1.25rem; |
|
text-align: center; |
|
transition: 0.25s background-color ease-in-out; |
|
cursor: pointer; |
|
|
|
&-dragging, |
|
&:hover { |
|
background-color: lighten( |
|
} |
|
|
|
&-icon { |
|
display: block; |
|
font-size: 3rem; |
|
margin: 0 auto 1.5rem; |
|
color: var(--primary-color); |
|
} |
|
|
|
&-input { |
|
display: none; |
|
} |
|
} |
|
</style> |
|
|