feat(internal-chat): support paste and drag-drop for attachments (#269)
This commit is contained in:
parent
c9b1917886
commit
adc0d892e0
@ -66,6 +66,7 @@
|
|||||||
"DELETED": "This message was deleted",
|
"DELETED": "This message was deleted",
|
||||||
"SEND": "Send",
|
"SEND": "Send",
|
||||||
"UPLOAD_FILE": "Upload File",
|
"UPLOAD_FILE": "Upload File",
|
||||||
|
"DRAG_DROP": "Drop files here to attach",
|
||||||
"MENTION_USER": "Mention a user",
|
"MENTION_USER": "Mention a user",
|
||||||
"MENTION_CONVERSATION": "Mention a conversation",
|
"MENTION_CONVERSATION": "Mention a conversation",
|
||||||
"CONFIRM_DELETE": "Are you sure you want to delete this message?",
|
"CONFIRM_DELETE": "Are you sure you want to delete this message?",
|
||||||
|
|||||||
@ -66,6 +66,7 @@
|
|||||||
"DELETED": "Esta mensagem foi exclu\u00edda",
|
"DELETED": "Esta mensagem foi exclu\u00edda",
|
||||||
"SEND": "Enviar",
|
"SEND": "Enviar",
|
||||||
"UPLOAD_FILE": "Enviar Arquivo",
|
"UPLOAD_FILE": "Enviar Arquivo",
|
||||||
|
"DRAG_DROP": "Solte os arquivos aqui para anexar",
|
||||||
"MENTION_USER": "Mencionar um usu\u00e1rio",
|
"MENTION_USER": "Mencionar um usu\u00e1rio",
|
||||||
"MENTION_CONVERSATION": "Mencionar uma conversa",
|
"MENTION_CONVERSATION": "Mencionar uma conversa",
|
||||||
"CONFIRM_DELETE": "Tem certeza que deseja excluir esta mensagem?",
|
"CONFIRM_DELETE": "Tem certeza que deseja excluir esta mensagem?",
|
||||||
|
|||||||
@ -49,8 +49,10 @@ const editorContent = ref(props.initialContent);
|
|||||||
const attachedFiles = ref([]);
|
const attachedFiles = ref([]);
|
||||||
const isMentionMenuOpen = ref(false);
|
const isMentionMenuOpen = ref(false);
|
||||||
const isConversationMenuOpen = ref(false);
|
const isConversationMenuOpen = ref(false);
|
||||||
|
const isDragging = ref(false);
|
||||||
|
|
||||||
let draftTimer = null;
|
let draftTimer = null;
|
||||||
|
let dragCounter = 0;
|
||||||
|
|
||||||
const canSend = computed(() => {
|
const canSend = computed(() => {
|
||||||
return (
|
return (
|
||||||
@ -147,6 +149,53 @@ function removeFile(index) {
|
|||||||
attachedFiles.value.splice(index, 1);
|
attachedFiles.value.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addFiles(fileList) {
|
||||||
|
const files = Array.from(fileList || []).filter(f => f && f.size > 0);
|
||||||
|
if (!files.length) return;
|
||||||
|
attachedFiles.value = [...attachedFiles.value, ...files];
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePaste(event) {
|
||||||
|
const files = event.clipboardData?.files;
|
||||||
|
if (!files?.length) return;
|
||||||
|
event.preventDefault();
|
||||||
|
addFiles(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasFileDrag(event) {
|
||||||
|
return event.dataTransfer?.types?.includes('Files');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragEnter(event) {
|
||||||
|
if (!hasFileDrag(event)) return;
|
||||||
|
event.preventDefault();
|
||||||
|
dragCounter += 1;
|
||||||
|
isDragging.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragOver(event) {
|
||||||
|
if (!hasFileDrag(event)) return;
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragLeave(event) {
|
||||||
|
if (!hasFileDrag(event)) return;
|
||||||
|
event.preventDefault();
|
||||||
|
dragCounter -= 1;
|
||||||
|
if (dragCounter <= 0) {
|
||||||
|
dragCounter = 0;
|
||||||
|
isDragging.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrop(event) {
|
||||||
|
if (!hasFileDrag(event)) return;
|
||||||
|
event.preventDefault();
|
||||||
|
dragCounter = 0;
|
||||||
|
isDragging.value = false;
|
||||||
|
addFiles(event.dataTransfer?.files);
|
||||||
|
}
|
||||||
|
|
||||||
function filePreviewUrl(file) {
|
function filePreviewUrl(file) {
|
||||||
return URL.createObjectURL(file);
|
return URL.createObjectURL(file);
|
||||||
}
|
}
|
||||||
@ -185,7 +234,25 @@ defineExpose({ focus, setContent, getContent });
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="border-t border-n-slate-5 bg-n-solid-2 px-4 py-3">
|
<div
|
||||||
|
class="relative border-t border-n-slate-5 bg-n-solid-2 px-4 py-3"
|
||||||
|
@paste="handlePaste"
|
||||||
|
@dragenter="handleDragEnter"
|
||||||
|
@dragover="handleDragOver"
|
||||||
|
@dragleave="handleDragLeave"
|
||||||
|
@drop="handleDrop"
|
||||||
|
>
|
||||||
|
<transition name="modal-fade">
|
||||||
|
<div
|
||||||
|
v-show="isDragging"
|
||||||
|
class="pointer-events-none absolute inset-0 z-20 m-2 flex flex-col items-center justify-center gap-1 rounded-lg border-2 border-dashed border-n-brand bg-n-solid-2/90 text-n-brand"
|
||||||
|
>
|
||||||
|
<Icon icon="i-lucide-upload-cloud" class="size-6" />
|
||||||
|
<span class="text-sm font-medium">
|
||||||
|
{{ t('INTERNAL_CHAT.MESSAGE.DRAG_DROP') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
<div
|
<div
|
||||||
v-if="editingMessage"
|
v-if="editingMessage"
|
||||||
class="flex items-center justify-between border-b border-n-slate-5 px-3 py-1.5 text-xs text-n-brand"
|
class="flex items-center justify-between border-b border-n-slate-5 px-3 py-1.5 text-xs text-n-brand"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user