diff --git a/app/src/lib/graph-interface/components/AddMenu.svelte b/app/src/lib/graph-interface/components/AddMenu.svelte index d355ed7..36d46c6 100644 --- a/app/src/lib/graph-interface/components/AddMenu.svelte +++ b/app/src/lib/graph-interface/components/AddMenu.svelte @@ -5,19 +5,33 @@ import { getGraphManager, getGraphState } from '../graph-state.svelte'; type Props = { + paddingLeft?: number; + paddingRight?: number; + paddingTop?: number; + paddingBottom?: number; onnode: (n: NodeInstance) => void; }; - const { onnode }: Props = $props(); + const padding = 10; + + const { + paddingLeft = padding, + paddingRight = padding, + paddingTop = padding, + paddingBottom = padding, + onnode + }: Props = $props(); const graph = getGraphManager(); const graphState = getGraphState(); let input: HTMLInputElement; - let wrapper: HTMLDivElement; let value = $state(); let activeNodeId = $state(); + const MENU_WIDTH = 150; + const MENU_HEIGHT = 350; + const allNodes = graphState.activeSocket ? graph.getPossibleNodes(graphState.activeSocket) : graph.getNodeDefinitions(); @@ -79,19 +93,52 @@ } } + function clampAddMenuPosition() { + if (!graphState.addMenuPosition) return; + + const camX = graphState.cameraPosition[0]; + const camY = graphState.cameraPosition[1]; + const zoom = graphState.cameraPosition[2]; + + const halfViewportWidth = (graphState.width / 2) / zoom; + const halfViewportHeight = (graphState.height / 2) / zoom; + + const halfMenuWidth = (MENU_WIDTH / 2) / zoom; + const halfMenuHeight = (MENU_HEIGHT / 2) / zoom; + + const minX = camX - halfViewportWidth - halfMenuWidth + paddingLeft / zoom; + const maxX = camX + halfViewportWidth - halfMenuWidth - paddingRight / zoom; + const minY = camY - halfViewportHeight - halfMenuHeight + paddingTop / zoom; + const maxY = camY + halfViewportHeight - halfMenuHeight - paddingBottom / zoom; + + const clampedX = Math.max( + minX + halfMenuWidth, + Math.min(graphState.addMenuPosition[0], maxX - halfMenuWidth) + ); + const clampedY = Math.max( + minY + halfMenuHeight, + Math.min(graphState.addMenuPosition[1], maxY - halfMenuHeight) + ); + + if (clampedX !== graphState.addMenuPosition[0] || clampedY !== graphState.addMenuPosition[1]) { + graphState.addMenuPosition = [clampedX, clampedY]; + } + } + + $effect(() => { + const pos = graphState.addMenuPosition; + const zoom = graphState.cameraPosition[2]; + const width = graphState.width; + const height = graphState.height; + + if (pos && zoom && width && height) { + clampAddMenuPosition(); + } + }); + onMount(() => { input.disabled = false; setTimeout(() => input.focus(), 50); - - const rect = wrapper.getBoundingClientRect(); - const deltaY = rect.bottom - window.innerHeight; - const deltaX = rect.right - window.innerWidth; - if (deltaY > 0) { - wrapper.style.marginTop = `-${deltaY + 30}px`; - } - if (deltaX > 0) { - wrapper.style.marginLeft = `-${deltaX + 30}px`; - } }); @@ -100,7 +147,7 @@ position.z={graphState.addMenuPosition?.[1]} transform={false} > -
+
; + addMenuPadding?: { left?: number; right?: number; bottom?: number; top?: number }; } = $props(); const graph = getGraphManager(); @@ -160,7 +162,13 @@ {#if graph.status === 'idle'} {#if graphState.addMenuPosition} - + {/if} {#if graphState.activeSocket} diff --git a/app/src/lib/graph-interface/graph/Wrapper.svelte b/app/src/lib/graph-interface/graph/Wrapper.svelte index 72e69dd..73a08ac 100644 --- a/app/src/lib/graph-interface/graph/Wrapper.svelte +++ b/app/src/lib/graph-interface/graph/Wrapper.svelte @@ -18,6 +18,8 @@ showHelp?: boolean; settingTypes?: Record; + addMenuPadding?: { left?: number; right?: number; bottom?: number; top?: number }; + onsave?: (save: Graph) => void; onresult?: (result: unknown) => void; }; @@ -25,6 +27,7 @@ let { graph, registry, + addMenuPadding, settings = $bindable(), activeNode = $bindable(), backgroundType = $bindable('grid'), @@ -83,4 +86,4 @@ }); - + diff --git a/app/src/lib/sidebar/Sidebar.svelte b/app/src/lib/sidebar/Sidebar.svelte index b2ad5fe..1d5c2dd 100644 --- a/app/src/lib/sidebar/Sidebar.svelte +++ b/app/src/lib/sidebar/Sidebar.svelte @@ -2,7 +2,11 @@ import { type Snippet } from 'svelte'; import { panelState as state } from './PanelState.svelte'; - const { children } = $props<{ children?: Snippet }>(); + let { children, open = $bindable(false) } = $props<{ children?: Snippet; open?: boolean }>(); + + $effect(() => { + open = !!state.activePanel.value; + });
diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index 3747db6..4cb7dd3 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -63,6 +63,7 @@ let activeNode = $state(undefined); let scene = $state(null!); + let sidebarOpen = $state(false); let graphInterface = $state>(null!); let viewerComponent = $state>(); const manager = $derived(graphInterface?.manager); @@ -171,6 +172,7 @@ graph={pm.graph} bind:this={graphInterface} registry={nodeRegistry} + addMenuPadding={{ right: sidebarOpen ? 330 : undefined }} backgroundType={appSettings.value.nodeInterface.backgroundType} snapToGrid={appSettings.value.nodeInterface.snapToGrid} bind:activeNode @@ -181,7 +183,7 @@ onresult={(result) => handleUpdate(result as Graph)} /> {/if} - +