diff --git a/CLAUDE.md b/CLAUDE.md index 63eca49d..409912a1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -210,6 +210,14 @@ All routes in `src/app/api/`: - `node-banana-workflow-costs` - Cost tracking per workflow - `node-banana-nanoBanana-defaults` - Sticky generation settings +## Git Workflow + +- The primary development branch is `develop`, NOT `main` or `master` +- Always checkout `develop` before creating feature branches: `git checkout develop` +- Create feature branches from `develop` using: `feature/` or `fix/` +- All PRs MUST target `develop`: use `gh pr create --base develop` +- Never push directly to `main`, `master`, or `develop` + ## Commits - The .planning directory is untracked, do not attempt to commit any changes to the files in this directory. diff --git a/src/components/Header.tsx b/src/components/Header.tsx index ff12ea13..aeb28f80 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -171,6 +171,35 @@ export function Header() { } }, [revertToSnapshot]); + const settingsButtons = ( +
+ +
+ ); + return ( <> - {/* Settings - separated */} - + {settingsButtons} ) : ( <> @@ -340,31 +345,7 @@ export function Header() { - {/* Settings - separated */} - + {settingsButtons} )} diff --git a/src/components/ProjectSetupModal.tsx b/src/components/ProjectSetupModal.tsx index f234080a..4f12c64a 100644 --- a/src/components/ProjectSetupModal.tsx +++ b/src/components/ProjectSetupModal.tsx @@ -3,6 +3,7 @@ import { useState, useEffect } from "react"; import { generateWorkflowId, useWorkflowStore } from "@/store/workflowStore"; import { ProviderType, ProviderSettings, NodeDefaultsConfig, LLMProvider, LLMModelType } from "@/types"; +import { CanvasNavigationSettings, PanMode, ZoomMode, SelectionMode } from "@/types/canvas"; import { EnvStatusResponse } from "@/app/api/env-status/route"; import { loadNodeDefaults, saveNodeDefaults } from "@/store/utils/localStorage"; import { ProviderModel } from "@/lib/providers/types"; @@ -94,10 +95,12 @@ export function ProjectSetupModal({ toggleProvider, maxConcurrentCalls, setMaxConcurrentCalls, + canvasNavigationSettings, + updateCanvasNavigationSettings, } = useWorkflowStore(); // Tab state - const [activeTab, setActiveTab] = useState<"project" | "providers" | "nodeDefaults">("project"); + const [activeTab, setActiveTab] = useState<"project" | "providers" | "nodeDefaults" | "canvas">("project"); // Project tab state const [name, setName] = useState(""); @@ -132,6 +135,9 @@ export function ProjectSetupModal({ const [showImageModelDialog, setShowImageModelDialog] = useState(false); const [showVideoModelDialog, setShowVideoModelDialog] = useState(false); + // Canvas tab state + const [localCanvasSettings, setLocalCanvasSettings] = useState(canvasNavigationSettings); + // Pre-fill when opening in settings mode useEffect(() => { if (isOpen) { @@ -169,13 +175,16 @@ export function ProjectSetupModal({ setShowImageModelDialog(false); setShowVideoModelDialog(false); + // Sync canvas settings + setLocalCanvasSettings(canvasNavigationSettings); + // Fetch env status fetch("/api/env-status") .then((res) => res.json()) .then((data: EnvStatusResponse) => setEnvStatus(data)) .catch(() => setEnvStatus(null)); } - }, [isOpen, mode, workflowName, saveDirectoryPath, useExternalImageStorage, providerSettings]); + }, [isOpen, mode, workflowName, saveDirectoryPath, useExternalImageStorage, providerSettings, canvasNavigationSettings]); const handleBrowse = async () => { setIsBrowsing(true); @@ -285,11 +294,18 @@ export function ProjectSetupModal({ onClose(); }; + const handleSaveCanvas = () => { + updateCanvasNavigationSettings(localCanvasSettings); + onClose(); + }; + const handleSave = () => { if (activeTab === "project") { handleSaveProject(); } else if (activeTab === "providers") { handleSaveProviders(); + } else if (activeTab === "canvas") { + handleSaveCanvas(); } else { handleSaveNodeDefaults(); } @@ -324,15 +340,16 @@ export function ProjectSetupModal({ return (
-

- {mode === "new" ? "New Project" : "Project Settings"} -

+
+

+ {mode === "new" ? "New Project" : "Project Settings"} +

- {/* Tab Bar */} -
+ {/* Tab Bar */} +
+ +
+ {/* Scrollable tab content area */} +
+ {/* Project Tab Content */} {activeTab === "project" && (
@@ -961,7 +988,117 @@ export function ProjectSetupModal({
)} -
+ {/* Canvas Tab Content */} + {activeTab === "canvas" && ( +
+ {/* Pan Mode */} +
+

Pan Mode

+
+ {([ + { value: "space" as PanMode, label: "Space + Drag", description: "Hold Space and drag to pan (default)" }, + { value: "middleMouse" as PanMode, label: "Middle Mouse", description: "Click and drag with middle mouse button" }, + { value: "always" as PanMode, label: "Always On", description: "Pan without holding any keys" }, + ] as const).map((option) => ( + + ))} +
+
+ + {/* Zoom Mode */} +
+

Zoom Mode

+
+ {([ + { value: "altScroll" as ZoomMode, label: "Alt + Scroll", description: "Hold Alt and scroll to zoom (default)" }, + { value: "ctrlScroll" as ZoomMode, label: "Ctrl + Scroll", description: "Hold Ctrl/Cmd and scroll to zoom" }, + { value: "scroll" as ZoomMode, label: "Scroll", description: "Scroll to zoom without holding any keys" }, + ] as const).map((option) => ( + + ))} +
+
+ + {/* Selection Mode */} +
+

Selection Mode

+
+ {([ + { value: "click" as SelectionMode, label: "Click", description: "Click to select nodes (default)" }, + { value: "altDrag" as SelectionMode, label: "Alt + Drag", description: "Hold Alt and drag to select multiple nodes" }, + { value: "shiftDrag" as SelectionMode, label: "Shift + Drag", description: "Hold Shift and drag to select multiple nodes" }, + ] as const).map((option) => ( + + ))} +
+
+
+ )} + +
+ + {/* Fixed footer */} +