Files
lemonspace_app/components/canvas/nodes/compare-surface.tsx

94 lines
2.8 KiB
TypeScript

"use client";
import { useCanvasGraph } from "@/components/canvas/canvas-graph-context";
import { usePipelinePreview } from "@/hooks/use-pipeline-preview";
import {
shouldFastPathPreviewPipeline,
type RenderPreviewInput,
} from "@/lib/canvas-render-preview";
const EMPTY_STEPS: RenderPreviewInput["steps"] = [];
type CompareSurfaceProps = {
finalUrl?: string;
label?: string;
previewInput?: RenderPreviewInput;
nodeWidth: number;
clipWidthPercent?: number;
preferPreview?: boolean;
};
export default function CompareSurface({
finalUrl,
label,
previewInput,
nodeWidth,
clipWidthPercent,
preferPreview,
}: CompareSurfaceProps) {
const graph = useCanvasGraph();
const usePreview = Boolean(previewInput && (preferPreview || !finalUrl));
const previewSourceUrl = usePreview ? previewInput?.sourceUrl ?? null : null;
const previewSteps = usePreview ? previewInput?.steps ?? EMPTY_STEPS : EMPTY_STEPS;
const visibleFinalUrl = usePreview ? undefined : finalUrl;
const previewDebounceMs = shouldFastPathPreviewPipeline(
previewSteps,
graph.previewNodeDataOverrides,
)
? 16
: undefined;
const { canvasRef, isRendering, error } = usePipelinePreview({
sourceUrl: previewSourceUrl,
steps: previewSteps,
nodeWidth,
includeHistogram: false,
debounceMs: previewDebounceMs,
// Compare-Nodes zeigen nur eine kompakte Live-Ansicht; kleinere Kacheln
// halten lange Workflows spürbar reaktionsfreudiger.
previewScale: 0.5,
maxPreviewWidth: 720,
maxDevicePixelRatio: 1.25,
});
const hasPreview = Boolean(usePreview && previewInput);
const clipStyle =
typeof clipWidthPercent === "number"
? {
clipPath: `inset(0 ${100 - clipWidthPercent}% 0 0)`,
WebkitClipPath: `inset(0 ${100 - clipWidthPercent}% 0 0)`,
}
: undefined;
return (
<div className="pointer-events-none absolute inset-0" style={clipStyle}>
{visibleFinalUrl ? (
// eslint-disable-next-line @next/next/no-img-element
<img
src={visibleFinalUrl}
alt={label ?? "Comparison image"}
className="absolute inset-0 h-full w-full object-contain"
draggable={false}
/>
) : hasPreview ? (
<canvas
ref={canvasRef}
className="absolute inset-0 h-full w-full object-contain"
/>
) : null}
{hasPreview ? (
<div className="absolute bottom-2 left-2 rounded bg-amber-500/85 px-1.5 py-0.5 text-[10px] font-medium text-black/90 backdrop-blur-sm">
{isRendering ? "Live Preview..." : "Live Preview"}
</div>
) : null}
{hasPreview && error ? (
<div className="absolute bottom-2 right-2 rounded bg-destructive/85 px-1.5 py-0.5 text-[10px] font-medium text-white backdrop-blur-sm">
Preview error
</div>
) : null}
</div>
);
}