Files
lemonspace_app/components/canvas/nodes/ai-image-node.tsx
Matthias ca40f5cb13 feat: enhance canvas and layout components with new features and improvements
- Added remote image patterns to the Next.js configuration for enhanced image handling.
- Updated TypeScript configuration to exclude the 'implement' directory.
- Refactored layout component to fetch initial authentication token and pass it to Providers.
- Replaced CanvasToolbar with CanvasSidebar for improved UI layout and functionality.
- Enhanced Canvas component with new drag-and-drop file upload capabilities and batch node movement.
- Updated various node components to support new status handling and improved user interactions.
- Added debounced saving for note and prompt nodes to optimize performance.
2026-03-25 17:58:58 +01:00

80 lines
2.2 KiB
TypeScript

"use client";
import { Handle, Position, type NodeProps, type Node } from "@xyflow/react";
import BaseNodeWrapper from "./base-node-wrapper";
type AiImageNodeData = {
url?: string;
prompt?: string;
model?: string;
_status?: string;
_statusMessage?: string;
};
export type AiImageNode = Node<AiImageNodeData, "ai-image">;
export default function AiImageNode({
data,
selected,
}: NodeProps<AiImageNode>) {
const status = data._status ?? "idle";
return (
<BaseNodeWrapper
selected={selected}
status={status}
statusMessage={data._statusMessage}
>
<div className="p-2">
<div className="text-xs font-medium text-emerald-500 mb-1">
🤖 KI-Bild
</div>
{status === "executing" && (
<div className="flex h-36 w-56 items-center justify-center rounded-lg bg-muted">
<div className="h-6 w-6 animate-spin rounded-full border-2 border-primary border-t-transparent" />
</div>
)}
{status === "done" && data.url && (
<img
src={data.url}
alt={data.prompt ?? "KI-generiertes Bild"}
className="rounded-lg object-cover max-w-[260px]"
draggable={false}
/>
)}
{status === "error" && (
<div className="flex h-36 w-56 items-center justify-center rounded-lg bg-red-50 dark:bg-red-950/20 text-sm text-red-600">
{data._statusMessage ?? "Fehler bei der Generierung"}
</div>
)}
{status === "idle" && (
<div className="flex h-36 w-56 items-center justify-center rounded-lg border-2 border-dashed text-sm text-muted-foreground">
Prompt verbinden
</div>
)}
{data.prompt && status === "done" && (
<p className="mt-1 text-xs text-muted-foreground truncate max-w-[260px]">
{data.prompt}
</p>
)}
</div>
<Handle
type="target"
position={Position.Left}
className="!h-3 !w-3 !bg-emerald-500 !border-2 !border-background"
/>
<Handle
type="source"
position={Position.Right}
className="!h-3 !w-3 !bg-primary !border-2 !border-background"
/>
</BaseNodeWrapper>
);
}