improve menus

This commit is contained in:
2026-03-07 21:49:15 +01:00
parent 65d4f216a8
commit 39719b1823
2 changed files with 64 additions and 44 deletions

View File

@@ -23,13 +23,15 @@ import { useTheme } from './lib/themeContext'
import {
ContextMenu,
ContextMenuContent,
ContextMenuGroup,
ContextMenuItem,
ContextMenuLabel,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuTrigger,
ContextMenuGroup
} from "@/components/ui/context-menu"
import { Button } from '@/components/ui/button'
import { Moon, Sun } from 'lucide-react'
import { Code2, Moon, ScrollText, Sparkles, Sun, Variable } from 'lucide-react'
// Generate short unique node ids when missing
const genId = () => `node_${Math.random().toString(36).slice(2, 9)}`
@@ -118,14 +120,13 @@ export default function App() {
const click = contextTarget ?? lastClickRef.current
const clientX = click?.clientX ?? window.innerWidth / 2
const clientY = click?.clientY ?? window.innerHeight / 2
const rect = wrapperRef.current?.getBoundingClientRect()
const point = rect ? { x: clientX - rect.left, y: clientY - rect.top } : { x: clientX, y: clientY }
let position = point
let position: { x: number; y: number }
try {
// project to flow coords when possible
position = rfInstance.project ? rfInstance.project(point) : point
} catch (e) {
// ignore and use raw point
// Convert screen (client) coordinates to flow coordinates — same position as where the context menu opened
const screenToFlow = rfInstance.screenToFlowPosition ?? rfInstance.project
position = screenToFlow.call(rfInstance, { x: clientX, y: clientY })
} catch {
position = { x: clientX, y: clientY }
}
position = snapToGrid(position.x, position.y)
@@ -154,7 +155,7 @@ export default function App() {
lastClickRef.current = null
setContextTarget(null)
},
[rfInstance, setNodes]
[rfInstance, setNodes, contextTarget]
)
const deleteNode = React.useCallback((id: string | undefined) => {
@@ -204,24 +205,42 @@ export default function App() {
</div>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuContent className="w-48">
{contextTarget?.type === 'node' ? (
<ContextMenuItem onSelect={() => deleteNode(contextTarget.nodeId)}>Delete</ContextMenuItem>
) : (
<>
<ContextMenuGroup>
<ContextMenuLabel>New Node</ContextMenuLabel>
<ContextMenuItem onSelect={() => createNode('config')}>Config</ContextMenuItem>
<ContextMenuItem onSelect={() => createNode('render')}>Renderer</ContextMenuItem>
<ContextMenuItem onSelect={() => createNode('variable')}>Variable</ContextMenuItem>
<ContextMenuItem onSelect={() => createNode('function')}>Function</ContextMenuItem>
<ContextMenuItem onSelect={() => deleteNode(contextTarget.nodeId)}>Delete</ContextMenuItem>
</ContextMenuGroup>
) : (
<ContextMenuGroup>
<ContextMenuSub>
<ContextMenuSubTrigger>Create node</ContextMenuSubTrigger>
<ContextMenuSubContent className="w-44">
<ContextMenuGroup>
<ContextMenuItem onSelect={() => createNode('config')}>
<ScrollText className="mr-2 h-4 w-4" />
Config
</ContextMenuItem>
<ContextMenuItem onSelect={() => createNode('render')}>
<Sparkles className="mr-2 h-4 w-4" />
Renderer
</ContextMenuItem>
<ContextMenuItem onSelect={() => createNode('variable')}>
<Variable className="mr-2 h-4 w-4" />
Variable
</ContextMenuItem>
<ContextMenuItem onSelect={() => createNode('function')}>
<Code2 className="mr-2 h-4 w-4" />
Function
</ContextMenuItem>
</ContextMenuGroup>
</ContextMenuSubContent>
</ContextMenuSub>
</ContextMenuGroup>
</>
)}
</ContextMenuContent>
</ContextMenu>
</FlowContext.Provider>
</div>
</div >
)
}

View File

@@ -44,11 +44,12 @@ body {
@keyframes edge-flow {
from {
stroke-dashoffset: 0;
}
to {
stroke-dashoffset: 14;
}
to {
stroke-dashoffset: 0;
}
}
/* Resize control: snappy drag, no transition or selection delay */