diff --git a/apps/x/apps/preload/src/preload.ts b/apps/x/apps/preload/src/preload.ts index 1def7bdd..7d7d53e4 100644 --- a/apps/x/apps/preload/src/preload.ts +++ b/apps/x/apps/preload/src/preload.ts @@ -1,4 +1,4 @@ -import { contextBridge, ipcRenderer } from 'electron'; +import { contextBridge, ipcRenderer, webUtils } from 'electron'; import { ipc as ipcShared } from '@x/shared'; type InvokeChannels = ipcShared.InvokeChannels; @@ -51,4 +51,8 @@ const ipc = { }, }; -contextBridge.exposeInMainWorld('ipc', ipc); \ No newline at end of file +contextBridge.exposeInMainWorld('ipc', ipc); + +contextBridge.exposeInMainWorld('electronUtils', { + getPathForFile: (file: File) => webUtils.getPathForFile(file), +}); \ No newline at end of file diff --git a/apps/x/apps/renderer/src/App.tsx b/apps/x/apps/renderer/src/App.tsx index 69576938..f100b9bb 100644 --- a/apps/x/apps/renderer/src/App.tsx +++ b/apps/x/apps/renderer/src/App.tsx @@ -322,6 +322,37 @@ function ChatInputInner({ } }, [handleSubmit]) + useEffect(() => { + const onDragOver = (e: DragEvent) => { + if (e.dataTransfer?.types?.includes("Files")) { + e.preventDefault() + } + } + const onDrop = (e: DragEvent) => { + if (e.dataTransfer?.types?.includes("Files")) { + e.preventDefault() + } + if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) { + const paths = Array.from(e.dataTransfer.files) + .map((f) => window.electronUtils?.getPathForFile(f)) + .filter(Boolean) + if (paths.length > 0) { + const currentText = controller.textInput.value + const pathText = paths.join(' ') + controller.textInput.setInput( + currentText ? `${currentText} ${pathText}` : pathText + ) + } + } + } + document.addEventListener("dragover", onDragOver) + document.addEventListener("drop", onDrop) + return () => { + document.removeEventListener("dragover", onDragOver) + document.removeEventListener("drop", onDrop) + } + }, [controller]) + return (