This commit is contained in:
Timothy Jaeryang Baek
2026-03-22 22:01:38 -05:00
parent 9a6bf78e14
commit ebb7ce2092
4 changed files with 73 additions and 10 deletions

View File

@@ -2814,7 +2814,7 @@
</div>
</div>
<div class=" pb-2 z-10">
<div class=" pb-2 {dragged ? 'z-0' : 'z-10'}">
<MessageInput
bind:this={messageInput}
{history}

View File

@@ -55,6 +55,7 @@
import { uploadFile } from '$lib/apis/files';
import { generateAutoCompletion } from '$lib/apis';
import { deleteFileById } from '$lib/apis/files';
import { getChatById } from '$lib/apis/chats';
import { getSessionUser } from '$lib/apis/auths';
import { getTools } from '$lib/apis/tools';
@@ -806,8 +807,11 @@
const onDragOver = (e: DragEvent) => {
e.preventDefault();
// Check if a file is being dragged.
if (e.dataTransfer?.types?.includes('Files')) {
// Check if a file or a sidebar chat item is being dragged.
if (
e.dataTransfer?.types?.includes('Files') ||
e.dataTransfer?.types?.includes('text/plain')
) {
dragged = true;
} else {
dragged = false;
@@ -825,6 +829,35 @@
e.preventDefault();
console.log(e);
// Check if the dropped data is a sidebar chat item
const textData = e.dataTransfer?.getData('text/plain');
if (textData) {
try {
const data = JSON.parse(textData);
if (data.type === 'chat' && data.id) {
// Fetch the chat to get its title, then add as a reference chat
const chat = await getChatById(localStorage.token, data.id);
if (chat) {
const chatItem = {
type: 'chat',
id: chat.id,
name: chat.title,
collection_name: '',
status: 'processed'
};
if (!files.find((f) => f.id === chatItem.id)) {
files = [...files, chatItem];
}
}
dragged = false;
e.stopPropagation();
return;
}
} catch (_) {
// Not valid JSON — fall through to file handling
}
}
if (e.dataTransfer?.files) {
const inputFiles = Array.from(e.dataTransfer?.files);
if (inputFiles && inputFiles.length > 0) {
@@ -1022,8 +1055,8 @@
dropzoneElement = document.getElementById('chat-pane');
if (dropzoneElement) {
dropzoneElement.addEventListener('dragover', onDragOver);
dropzoneElement.addEventListener('drop', onDrop);
dropzoneElement.addEventListener('dragover', onDragOver, true);
dropzoneElement.addEventListener('drop', onDrop, true);
dropzoneElement.addEventListener('dragleave', onDragLeave);
}
@@ -1041,8 +1074,8 @@
window.removeEventListener('blur', onBlur);
if (dropzoneElement) {
dropzoneElement.removeEventListener('dragover', onDragOver);
dropzoneElement.removeEventListener('drop', onDrop);
dropzoneElement.removeEventListener('dragover', onDragOver, true);
dropzoneElement.removeEventListener('drop', onDrop, true);
dropzoneElement.removeEventListener('dragleave', onDragLeave);
}
};

View File

@@ -29,7 +29,7 @@
<div
bind:this={popupElement}
class="fixed top-0 left-0 w-screen h-[100dvh] z-50 touch-none pointer-events-none"
class="fixed top-0 left-0 w-screen h-[100dvh] z-[99999] touch-none pointer-events-none"
>
<div class=" absolute text-white z-99999" style="top: {y + 10}px; left: {x + 10}px;">
<slot></slot>

View File

@@ -801,8 +801,8 @@
if (!editor || !editor.view || editor.isDestroyed) {
return false;
}
// default logic
return from !== to;
// Only show when editor is focused and text is selected
return view.hasFocus() && from !== to;
}
}),
FloatingMenu.configure({
@@ -905,6 +905,24 @@
},
editorProps: {
attributes: { id },
handleDrop: (view, event) => {
// Intercept sidebar chat item drops to prevent ProseMirror
// from inserting the raw JSON as text. The actual handling
// (adding as Reference Chat) is done by MessageInput's onDrop.
const textData = event.dataTransfer?.getData('text/plain');
if (textData) {
try {
const data = JSON.parse(textData);
if (data.type === 'chat' && data.id) {
// Swallow the drop — let the parent handler deal with it
return true;
}
} catch (_) {
// Not JSON, let ProseMirror handle normally
}
}
return false;
},
handlePaste: (view, event) => {
// Force plain-text pasting when richText === false
if (!richText) {
@@ -1170,6 +1188,18 @@
}
},
onSelectionUpdate: onSelectionUpdate,
onBlur: () => {
// Force-hide floating menus when editor loses focus.
// shouldShow alone isn't enough because it only runs on transactions.
if (bubbleMenuElement) {
bubbleMenuElement.style.visibility = 'hidden';
bubbleMenuElement.style.opacity = '0';
}
if (floatingMenuElement) {
floatingMenuElement.style.visibility = 'hidden';
floatingMenuElement.style.opacity = '0';
}
},
enableInputRules: richText,
enablePasteRules: richText
});