Files
lemonspace_app/components/canvas/canvas-command-palette.tsx
Matthias 9694c50195 feat: implement createNodeWithEdgeToTarget mutation for enhanced node connections
- Added a new mutation to create nodes connected to existing nodes, allowing for more dynamic interactions on the canvas.
- Updated the CanvasPlacementContext to include the new mutation, improving the workflow for node creation and edge management.
- Enhanced optimistic updates for immediate UI feedback during node and edge creation processes.
- Refactored related components to support the new connection method, streamlining user interactions.
2026-03-28 17:50:45 +01:00

100 lines
3.1 KiB
TypeScript

"use client";
import { useEffect, useRef, useState } from "react";
import { useTheme } from "next-themes";
import { Moon, Sun } from "lucide-react";
import { CanvasNodeTemplatePicker } from "@/components/canvas/canvas-node-template-picker";
import { useCanvasPlacement } from "@/components/canvas/canvas-placement-context";
import { useCenteredFlowNodePosition } from "@/hooks/use-centered-flow-node-position";
import {
Command,
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
} from "@/components/ui/command";
import type { CanvasNodeTemplate } from "@/lib/canvas-node-templates";
export function CanvasCommandPalette() {
const [open, setOpen] = useState(false);
const { createNodeWithIntersection } = useCanvasPlacement();
const getCenteredPosition = useCenteredFlowNodePosition();
const { setTheme } = useTheme();
const nodeCountRef = useRef(0);
useEffect(() => {
const onKeyDown = (e: KeyboardEvent) => {
if (!e.metaKey && !e.ctrlKey) return;
if (e.key.toLowerCase() !== "k") return;
e.preventDefault();
setOpen((prev) => !prev);
};
document.addEventListener("keydown", onKeyDown);
return () => document.removeEventListener("keydown", onKeyDown);
}, []);
const handleAddNode = (template: CanvasNodeTemplate) => {
const stagger = (nodeCountRef.current % 8) * 24;
nodeCountRef.current += 1;
setOpen(false);
void createNodeWithIntersection({
type: template.type,
position: getCenteredPosition(template.width, template.height, stagger),
width: template.width,
height: template.height,
data: template.defaultData,
clientRequestId: crypto.randomUUID(),
}).catch((error) => {
console.error("[CanvasCommandPalette] createNode failed", error);
});
};
return (
<CommandDialog
open={open}
onOpenChange={setOpen}
title="Befehle"
description="Knoten hinzufuegen oder Erscheinungsbild aendern"
>
<Command>
<CommandInput placeholder="Suchen …" />
<CommandList>
<CommandEmpty>Keine Treffer.</CommandEmpty>
<CanvasNodeTemplatePicker onPick={handleAddNode} />
<CommandSeparator />
<CommandGroup heading="Erscheinungsbild">
<CommandItem
keywords={["light", "hell", "day"]}
onSelect={() => {
setTheme("light");
setOpen(false);
}}
>
<Sun className="size-4" />
Hell
</CommandItem>
<CommandItem
keywords={["dark", "dunkel", "night"]}
onSelect={() => {
setTheme("dark");
setOpen(false);
}}
>
<Moon className="size-4" />
Dunkel
</CommandItem>
</CommandGroup>
</CommandList>
<div className="border-t px-3 py-2 text-xs text-muted-foreground">
<span className="font-mono tracking-wide">K · Ctrl+K</span>
<span className="ml-2">Palette umschalten</span>
</div>
</Command>
</CommandDialog>
);
}