fix: minor styles and ux

This commit is contained in:
2026-03-11 00:21:37 +01:00
parent 08d66b59c2
commit 7c1039f4c6
3 changed files with 185 additions and 78 deletions

View File

@@ -68,6 +68,7 @@ import {
} from '@/app/platform/projectGraphStorage'
const SNAP_GRID: [number, number] = [15, 15]
const DUPLICATE_OFFSET = { x: 30, y: 30 }
const snapToGrid = (x: number, y: number): { x: number; y: number } => ({
x: Math.round(x / SNAP_GRID[0]) * SNAP_GRID[0],
y: Math.round(y / SNAP_GRID[1]) * SNAP_GRID[1],
@@ -333,6 +334,59 @@ export function CanvasPage({ projectId }: CanvasPageProps) {
[setStateImmediate]
)
const selectedNodes = useMemo(
() => nodes.filter((n) => (n as Node & { selected?: boolean }).selected),
[nodes]
)
const handleDuplicate = useCallback(() => {
if (selectedNodes.length === 0 || !setNodes) return
setNodes((nds: Node[]) => {
const existingIds = nds.map((n) => n.id)
const toAdd: Node[] = []
for (const node of selectedNodes) {
const n = node as Node & { selected?: boolean }
const pos = n.position ?? { x: 0, y: 0 }
const newId = getNextNodeId(String(n.type), [...existingIds, ...toAdd.map((x) => x.id)])
existingIds.push(newId)
const newNode: Node = {
id: newId,
type: n.type,
position: { x: pos.x + DUPLICATE_OFFSET.x, y: pos.y + DUPLICATE_OFFSET.y },
data: typeof n.data === 'object' && n.data !== null ? { ...(n.data as object) } : n.data,
style: getDefaultStyle(String(n.type)),
}
if (
newNode.data &&
typeof newNode.data === 'object' &&
'title' in newNode.data &&
String(n.type) === 'config'
) {
;(newNode.data as Record<string, unknown>).title = `${newId}`
}
toAdd.push(newNode)
}
return nds.concat(toAdd)
})
}, [selectedNodes, setNodes])
const handleCopy = useCallback(() => {
if (selectedNodes.length !== 1) return
const node = selectedNodes[0] as Node & { selected?: boolean }
const copy = {
id: node.id,
type: node.type,
data: node.data,
position: node.position,
style: node.style,
}
navigator.clipboard?.writeText(JSON.stringify(copy)).catch(() => {})
}, [selectedNodes])
const handlePaste = useCallback(() => {
flowActionsRef.current?.pasteAtViewportCenter?.()
}, [])
const flowContextValue = useMemo(
() => ({
nodes,
@@ -498,6 +552,11 @@ export function CanvasPage({ projectId }: CanvasPageProps) {
redo={redo}
canUndo={canUndo}
canRedo={canRedo}
onDuplicate={handleDuplicate}
onCopy={handleCopy}
onPaste={handlePaste}
canDuplicate={selectedNodes.length > 0}
canCopy={selectedNodes.length === 1}
onFitView={() => flowActionsRef.current?.fitView?.()}
/>
{apiTodosCount !== null && (