Slave/ui polishing #13
@@ -38,6 +38,16 @@
|
|||||||
:metadata-error-count="metadataErrorCount"
|
:metadata-error-count="metadataErrorCount"
|
||||||
@upload="onUploadFromModal"
|
@upload="onUploadFromModal"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Teleport to="body">
|
||||||
|
<div v-if="showFileDragOverlay" class="pointer-events-none fixed inset-0 z-70 bg-background/70">
|
||||||
|
<div
|
||||||
|
class="absolute inset-[5%] flex items-center justify-center rounded-lg border-2 border-dashed border-primary"
|
||||||
|
>
|
||||||
|
<p class="text-2xl font-medium text-foreground sm:text-3xl">Drop files</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -77,19 +87,28 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const fileInputRef = ref<HTMLInputElement | null>(null);
|
const fileInputRef = ref<HTMLInputElement | null>(null);
|
||||||
const configureModalOpen = ref(false);
|
const configureModalOpen = ref(false);
|
||||||
|
const fileDragDepth = ref(0);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
window.addEventListener('dragenter', onWindowDragEnter);
|
||||||
|
window.addEventListener('dragleave', onWindowDragLeave);
|
||||||
window.addEventListener('dragover', onWindowDragOver);
|
window.addEventListener('dragover', onWindowDragOver);
|
||||||
window.addEventListener('drop', onWindowDrop);
|
window.addEventListener('drop', onWindowDrop);
|
||||||
|
window.addEventListener('dragend', onWindowDragEnd);
|
||||||
window.addEventListener('paste', onWindowPaste);
|
window.addEventListener('paste', onWindowPaste);
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('dragenter', onWindowDragEnter);
|
||||||
|
window.removeEventListener('dragleave', onWindowDragLeave);
|
||||||
window.removeEventListener('dragover', onWindowDragOver);
|
window.removeEventListener('dragover', onWindowDragOver);
|
||||||
window.removeEventListener('drop', onWindowDrop);
|
window.removeEventListener('drop', onWindowDrop);
|
||||||
|
window.removeEventListener('dragend', onWindowDragEnd);
|
||||||
window.removeEventListener('paste', onWindowPaste);
|
window.removeEventListener('paste', onWindowPaste);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const showFileDragOverlay = computed(() => fileDragDepth.value > 0 && !props.disabled);
|
||||||
|
|
||||||
const maxImageSizeLabel = computed(() => prettyBytes(maxImageBytes, { binary: true, maximumFractionDigits: 1 }));
|
const maxImageSizeLabel = computed(() => prettyBytes(maxImageBytes, { binary: true, maximumFractionDigits: 1 }));
|
||||||
|
|
||||||
const emitPicked = (picked: File[]): void => {
|
const emitPicked = (picked: File[]): void => {
|
||||||
@@ -117,15 +136,37 @@ const isFileDrag = (event: DragEvent): boolean => {
|
|||||||
return Boolean(event.dataTransfer?.types.includes('Files'));
|
return Boolean(event.dataTransfer?.types.includes('Files'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onWindowDragEnter = (event: DragEvent): void => {
|
||||||
|
if (props.disabled || !isFileDrag(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileDragDepth.value += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onWindowDragLeave = (event: DragEvent): void => {
|
||||||
|
if (!isFileDrag(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileDragDepth.value = Math.max(0, fileDragDepth.value - 1);
|
||||||
|
};
|
||||||
|
|
||||||
const onWindowDragOver = (event: DragEvent): void => {
|
const onWindowDragOver = (event: DragEvent): void => {
|
||||||
if (props.disabled || !isFileDrag(event)) {
|
if (props.disabled || !isFileDrag(event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (fileDragDepth.value === 0) {
|
||||||
|
fileDragDepth.value = 1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onWindowDrop = (event: DragEvent): void => {
|
const onWindowDrop = (event: DragEvent): void => {
|
||||||
|
resetFileDragDepth();
|
||||||
|
|
||||||
if (props.disabled) {
|
if (props.disabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -137,6 +178,10 @@ const onWindowDrop = (event: DragEvent): void => {
|
|||||||
emitPicked(picked);
|
emitPicked(picked);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onWindowDragEnd = (): void => {
|
||||||
|
resetFileDragDepth();
|
||||||
|
};
|
||||||
|
|
||||||
const isPasswordInputTarget = (target: EventTarget | null): boolean => {
|
const isPasswordInputTarget = (target: EventTarget | null): boolean => {
|
||||||
if (!(target instanceof HTMLElement)) {
|
if (!(target instanceof HTMLElement)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -175,5 +220,9 @@ const closeConfigureModal = (): void => {
|
|||||||
configureModalOpen.value = false;
|
configureModalOpen.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetFileDragDepth = (): void => {
|
||||||
|
fileDragDepth.value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
defineExpose({ clearInput, closeConfigureModal });
|
defineExpose({ clearInput, closeConfigureModal });
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user