From a94327c2401d6d7fa0413d8e0619cc326677aa80 Mon Sep 17 00:00:00 2001 From: shrimbly Date: Thu, 4 Dec 2025 20:29:23 +1300 Subject: [PATCH] build fixes --- next.config.ts | 3 ++ src/app/api/generate/route.ts | 2 +- src/components/WorkflowCanvas.tsx | 69 ++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/next.config.ts b/next.config.ts index 0afb877d..e2916b01 100644 --- a/next.config.ts +++ b/next.config.ts @@ -7,6 +7,9 @@ const nextConfig: NextConfig = { bodySizeLimit: "50mb", }, }, + turbopack: { + root: __dirname, + }, }; export default nextConfig; diff --git a/src/app/api/generate/route.ts b/src/app/api/generate/route.ts index 5a0afee0..09d1a596 100644 --- a/src/app/api/generate/route.ts +++ b/src/app/api/generate/route.ts @@ -179,7 +179,7 @@ export async function POST(request: NextRequest) { // Find image part in response for (const part of parts) { - if (part.inlineData) { + if (part.inlineData && part.inlineData.data) { const mimeType = part.inlineData.mimeType || "image/png"; const imageData = part.inlineData.data; const imageSizeKB = (imageData.length / 1024).toFixed(2); diff --git a/src/components/WorkflowCanvas.tsx b/src/components/WorkflowCanvas.tsx index 83941012..055acced 100644 --- a/src/components/WorkflowCanvas.tsx +++ b/src/components/WorkflowCanvas.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useRef, useState, DragEvent } from "react"; +import { useCallback, useRef, useState, useEffect, DragEvent } from "react"; import { ReactFlow, Background, @@ -212,6 +212,73 @@ function WorkflowCanvasInner() { setConnectionDrop(null); }, []); + // Keyboard shortcuts for stacking selected nodes + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + // Ignore if user is typing in an input field + if ( + event.target instanceof HTMLInputElement || + event.target instanceof HTMLTextAreaElement + ) { + return; + } + + const selectedNodes = nodes.filter((node) => node.selected); + if (selectedNodes.length < 2) return; + + const STACK_GAP = 20; + + if (event.key === "v" || event.key === "V") { + // Stack vertically - sort by current y position to maintain relative order + const sortedNodes = [...selectedNodes].sort((a, b) => a.position.y - b.position.y); + + // Use the leftmost x position as the alignment point + const alignX = Math.min(...sortedNodes.map((n) => n.position.x)); + + let currentY = sortedNodes[0].position.y; + + sortedNodes.forEach((node) => { + const nodeHeight = (node.style?.height as number) || (node.measured?.height) || 200; + + onNodesChange([ + { + type: "position", + id: node.id, + position: { x: alignX, y: currentY }, + }, + ]); + + currentY += nodeHeight + STACK_GAP; + }); + } else if (event.key === "h" || event.key === "H") { + // Stack horizontally - sort by current x position to maintain relative order + const sortedNodes = [...selectedNodes].sort((a, b) => a.position.x - b.position.x); + + // Use the topmost y position as the alignment point + const alignY = Math.min(...sortedNodes.map((n) => n.position.y)); + + let currentX = sortedNodes[0].position.x; + + sortedNodes.forEach((node) => { + const nodeWidth = (node.style?.width as number) || (node.measured?.width) || 220; + + onNodesChange([ + { + type: "position", + id: node.id, + position: { x: currentX, y: alignY }, + }, + ]); + + currentX += nodeWidth + STACK_GAP; + }); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [nodes, onNodesChange]); + const handleDragOver = useCallback((event: DragEvent) => { event.preventDefault(); event.dataTransfer.dropEffect = "copy";