From 3d2978f5d2136e5b253a7f40699dc7daac3e0fd5 Mon Sep 17 00:00:00 2001 From: Jirawat Boonkumnerd Date: Sat, 18 Nov 2023 06:30:11 +0700 Subject: [PATCH 1/2] feat: add paste from clipboard - add paste image from clipboard (ctrl+v) - validate if the file is an image --- frontend/src/App.tsx | 10 ++++--- frontend/src/components/ImageUpload.tsx | 35 +++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 634c800..0ce890f 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -77,10 +77,12 @@ function App() { // Initial version creation function doCreate(referenceImages: string[]) { setReferenceImages(referenceImages); - doGenerateCode({ - generationType: "create", - image: referenceImages[0], - }); + if (referenceImages.length > 0) { + doGenerateCode({ + generationType: "create", + image: referenceImages[0], + }); + } } // Subsequent updates diff --git a/frontend/src/components/ImageUpload.tsx b/frontend/src/components/ImageUpload.tsx index 16b5373..35a9c5a 100644 --- a/frontend/src/components/ImageUpload.tsx +++ b/frontend/src/components/ImageUpload.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useMemo } from "react"; +import { useState, useEffect, useMemo, useCallback } from "react"; import { useDropzone } from "react-dropzone"; // import { PromptImage } from "../../../types"; import { toast } from "react-hot-toast"; @@ -89,6 +89,37 @@ function ImageUpload({ setReferenceImages }: Props) { }, }); + const pasteEvent = useCallback( + (event: ClipboardEvent) => { + const clipboardData = event.clipboardData; + if (!clipboardData) return; + + const items = clipboardData.items; + const files = []; + for (let i = 0; i < items.length; i++) { + const file = items[i].getAsFile(); + if (file && file.type.startsWith("image/")) { + files.push(file); + } + } + + // Convert images to data URLs and set the prompt images state + Promise.all(files.map((file) => fileToDataURL(file))) + .then((dataUrls) => { + setReferenceImages(dataUrls.map((dataUrl) => dataUrl as string)); + }) + .catch((error) => { + // TODO: Display error to user + console.error("Error reading files:", error); + }); + }, + [setReferenceImages] + ); + + useEffect(() => { + window.addEventListener("paste", pasteEvent); + }, [pasteEvent]); + useEffect(() => { return () => files.forEach((file) => URL.revokeObjectURL(file.preview)); }, [files]); // Added files as a dependency @@ -108,7 +139,7 @@ function ImageUpload({ setReferenceImages }: Props) { {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
-

Drop a screenshot here, or click to select

+

Drop a screenshot here, paste from clipboard, or click to select

); From 6651b884bb26b4510211f52acb7dd080ff19b321 Mon Sep 17 00:00:00 2001 From: Abi Raja Date: Sat, 18 Nov 2023 15:38:34 -0500 Subject: [PATCH 2/2] minor fixes --- frontend/src/components/ImageUpload.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/ImageUpload.tsx b/frontend/src/components/ImageUpload.tsx index 35a9c5a..2f0b059 100644 --- a/frontend/src/components/ImageUpload.tsx +++ b/frontend/src/components/ImageUpload.tsx @@ -80,7 +80,7 @@ function ImageUpload({ setReferenceImages }: Props) { setReferenceImages(dataUrls.map((dataUrl) => dataUrl as string)); }) .catch((error) => { - // TODO: Display error to user + toast.error("Error reading files" + error); console.error("Error reading files:", error); }); }, @@ -116,6 +116,7 @@ function ImageUpload({ setReferenceImages }: Props) { [setReferenceImages] ); + // TODO: Make sure we don't listen to paste events in text input components useEffect(() => { window.addEventListener("paste", pasteEvent); }, [pasteEvent]);