From c968987ef55900e7f12f52fbf7758ac4f50b8e69 Mon Sep 17 00:00:00 2001 From: shrimbly Date: Tue, 3 Feb 2026 23:20:52 +1300 Subject: [PATCH] fix(quick-003): add audio file drag-drop support onto canvas - Detect audio file types in handleDragOver (audio/*) - Handle audio files in handleDrop creating AudioInput nodes - Show "Drop audio to create node" overlay for audio drag - Add "audio" to dropType state union --- src/components/WorkflowCanvas.tsx | 37 ++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/components/WorkflowCanvas.tsx b/src/components/WorkflowCanvas.tsx index ac6e4c5c..4fcb8bfd 100644 --- a/src/components/WorkflowCanvas.tsx +++ b/src/components/WorkflowCanvas.tsx @@ -208,7 +208,7 @@ export function WorkflowCanvas() { const { screenToFlowPosition, getViewport, zoomIn, zoomOut, setViewport, setCenter } = useReactFlow(); const { show: showToast } = useToast(); const [isDragOver, setIsDragOver] = useState(false); - const [dropType, setDropType] = useState<"image" | "workflow" | "node" | null>(null); + const [dropType, setDropType] = useState<"image" | "audio" | "workflow" | "node" | null>(null); const [connectionDrop, setConnectionDrop] = useState(null); const [isSplitting, setIsSplitting] = useState(false); const [isChatOpen, setIsChatOpen] = useState(false); @@ -1221,9 +1221,16 @@ export function WorkflowCanvas() { (item) => item.kind === "file" && item.type === "application/json" ); + const hasAudioFile = items.some( + (item) => item.kind === "file" && item.type.startsWith("audio/") + ); + if (hasJsonFile) { setIsDragOver(true); setDropType("workflow"); + } else if (hasAudioFile) { + setIsDragOver(true); + setDropType("audio"); } else if (hasImageFile) { setIsDragOver(true); setDropType("image"); @@ -1305,6 +1312,32 @@ export function WorkflowCanvas() { return; } + // Handle audio files + const audioFiles = allFiles.filter((file) => file.type.startsWith("audio/")); + if (audioFiles.length > 0) { + const position = screenToFlowPosition({ + x: event.clientX, + y: event.clientY, + }); + audioFiles.forEach((file, index) => { + const reader = new FileReader(); + reader.onload = (e) => { + const dataUrl = e.target?.result as string; + const nodeId = addNode("audioInput", { + x: position.x + index * 240, + y: position.y, + }); + updateNodeData(nodeId, { + audioFile: dataUrl, + filename: file.name, + format: file.type, + }); + }; + reader.readAsDataURL(file); + }); + return; + } + // Handle image files const imageFiles = allFiles.filter((file) => file.type.startsWith("image/")); if (imageFiles.length === 0) return; @@ -1362,6 +1395,8 @@ export function WorkflowCanvas() { ? "Drop to load workflow" : dropType === "node" ? "Drop to create node" + : dropType === "audio" + ? "Drop audio to create node" : "Drop image to create node"}