Browse Source

Larger text area with support for dragging in images

Matt Rubens 1 year ago
parent
commit
d7e35d0834

+ 63 - 6
webview-ui/src/components/chat/ChatTextArea.tsx

@@ -13,6 +13,8 @@ import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
 import ContextMenu from "./ContextMenu"
 import Thumbnails from "../common/Thumbnails"
 
+declare const vscode: any;
+
 interface ChatTextAreaProps {
 	inputValue: string
 	setInputValue: (value: string) => void
@@ -427,7 +429,62 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 					opacity: textAreaDisabled ? 0.5 : 1,
 					position: "relative",
 					display: "flex",
-				}}>
+				}}
+				onDrop={async (e) => {
+					console.log("onDrop called")
+					e.preventDefault()
+					const files = Array.from(e.dataTransfer.files)
+					const text = e.dataTransfer.getData("text")
+					if (text) {
+						const newValue =
+							inputValue.slice(0, cursorPosition) + text + inputValue.slice(cursorPosition)
+						setInputValue(newValue)
+						const newCursorPosition = cursorPosition + text.length
+						setCursorPosition(newCursorPosition)
+						setIntendedCursorPosition(newCursorPosition)
+						return
+					}
+					const acceptedTypes = ["png", "jpeg", "webp"]
+					const imageFiles = files.filter((file) => {
+						const [type, subtype] = file.type.split("/")
+						return type === "image" && acceptedTypes.includes(subtype)
+					})
+					if (!shouldDisableImages && imageFiles.length > 0) {
+						const imagePromises = imageFiles.map((file) => {
+							return new Promise<string | null>((resolve) => {
+								const reader = new FileReader()
+								reader.onloadend = () => {
+									if (reader.error) {
+										console.error("Error reading file:", reader.error)
+										resolve(null)
+									} else {
+										const result = reader.result
+										console.log("File read successfully", result)
+										resolve(typeof result === "string" ? result : null)
+									}
+								}
+								reader.readAsDataURL(file)
+							})
+						})
+						const imageDataArray = await Promise.all(imagePromises)
+						const dataUrls = imageDataArray.filter((dataUrl): dataUrl is string => dataUrl !== null)
+						if (dataUrls.length > 0) {
+							setSelectedImages((prevImages) => [...prevImages, ...dataUrls].slice(0, MAX_IMAGES_PER_MESSAGE))
+							if (typeof vscode !== 'undefined') {
+								vscode.postMessage({
+									type: 'draggedImages',
+									dataUrls: dataUrls
+								})
+							}
+						} else {
+							console.warn("No valid images were processed")
+						}
+					}
+				}}
+				onDragOver={(e) => {
+					e.preventDefault()
+				}}
+			>
 				{showContextMenu && (
 					<div ref={contextMenuContainerRef}>
 						<ContextMenu
@@ -508,7 +565,8 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 						onHeightChange?.(height)
 					}}
 					placeholder={placeholderText}
-					maxRows={10}
+					minRows={2}
+					maxRows={20}
 					autoFocus={true}
 					style={{
 						width: "100%",
@@ -523,7 +581,6 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 						resize: "none",
 						overflowX: "hidden",
 						overflowY: "scroll",
-						scrollbarWidth: "none",
 						// Since we have maxRows, when text is long enough it starts to overflow the bottom padding, appearing behind the thumbnails. To fix this, we use a transparent border to push the text up instead. (https://stackoverflow.com/questions/42631947/maintaining-a-padding-inside-of-text-area/52538410#52538410)
 						// borderTop: "9px solid transparent",
 						borderLeft: 0,
@@ -560,11 +617,11 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 				<div
 					style={{
 						position: "absolute",
-						right: 23,
+						right: 28,
 						display: "flex",
-						alignItems: "flex-center",
+						alignItems: "flex-end",
 						height: textAreaBaseHeight || 31,
-						bottom: 9.5, // should be 10 but doesnt look good on mac
+						bottom: 18,
 						zIndex: 2,
 					}}>
 					<div style={{ display: "flex", flexDirection: "row", alignItems: "center" }}>

+ 1 - 1
webview-ui/src/components/chat/ChatView.tsx

@@ -689,7 +689,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
 	useEvent("wheel", handleWheel, window, { passive: true }) // passive improves scrolling performance
 
 	const placeholderText = useMemo(() => {
-		const text = task ? "Type a message (@ to add context)..." : "Type your task here (@ to add context)..."
+		const text = task ? "Type a message...\n(@ to add context, hold shift to drag in images)" : "Type your task here...\n(@ to add context, hold shift to drag in images)"
 		return text
 	}, [task])