File size: 2,377 Bytes
1de8a7e
c3571d4
9d4f7f4
9b3602c
1de8a7e
9d4f7f4
 
1de8a7e
9b3602c
7d76168
d7d2be5
3a971ea
1de8a7e
 
5152615
a261aa8
 
 
5152615
a261aa8
5152615
 
 
 
 
 
 
 
 
 
 
 
9d4f7f4
 
 
 
 
 
7d76168
 
1de8a7e
 
5152615
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7d76168
 
 
 
 
 
 
 
9d4f7f4
7d76168
 
 
 
 
 
 
 
 
 
1de8a7e
d7d2be5
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<script lang="ts">
	import "@xyflow/svelte/dist/style.css";
	import type { Node } from "@xyflow/svelte";
	import { Background, Controls, MiniMap, SvelteFlow } from "@xyflow/svelte";
	import "@xyflow/svelte/dist/style.css";
	import { useDebounce } from "runed";
	import IconAdd from "~icons/lucide/plus";
	import ChatNode from "./chat-node.svelte";
	import { edges, nodes } from "./state.js";
	import { models } from "$lib/state/models.svelte";
	import ImgPreview from "$lib/components/inference-playground/img-preview.svelte";

	const nodeTypes = { chat: ChatNode } as const;

	// Make edges non-editable with clean styling
	const edgeOptions = {
		deletable: false,
		selectable: false,
		style: "stroke: #9ca3af; stroke-width: 2px;",
	};

	function addNewNode() {
		const newNode: Node = {
			id: crypto.randomUUID(),
			position: { x: Math.random() * 500, y: Math.random() * 300 },
			data: { query: "", response: "", modelId: undefined },
			type: "chat",
			width: undefined,
			height: undefined,
		};
		nodes.current.push(newNode);
	}

	let derivedNodes = $derived(nodes.current);

	const throttledSave = useDebounce((n: Node[]) => {
		nodes.current = n;
	}, 100);

	await models.load();
</script>

<div class="h-screen w-screen bg-gray-50">
	<!-- Header -->
	<header class="absolute top-6 left-6 z-50 flex items-center gap-4">
		<div
			class="flex items-center gap-3 rounded-xl border border-gray-200/80 bg-white/95 px-6
		py-3 shadow-sm backdrop-blur-md"
		>
			<h1 class="text-lg font-medium text-gray-900">Canvas</h1>
		</div>

		<button
			onclick={addNewNode}
			class="flex items-center gap-2 rounded-xl bg-black px-5 py-3 text-sm
			font-medium text-white shadow-sm transition-all hover:scale-[1.02] hover:bg-gray-900
			focus:ring-2 focus:ring-gray-900/20 focus:outline-hidden active:scale-[0.98]"
		>
			<IconAdd class="h-4 w-4" />
			Add Node
		</button>
	</header>

	{#if models.ready}
		<SvelteFlow
			bind:nodes={
				() => derivedNodes,
				v => {
					derivedNodes = v;
					throttledSave(v);
				}
			}
			bind:edges={edges.current}
			fitView
			{nodeTypes}
			defaultEdgeOptions={edgeOptions}
		>
			<MiniMap pannable zoomable class="rounded-xl border border-gray-200 bg-white shadow-sm" />
			<Controls class="rounded-xl border border-gray-200 bg-white shadow-sm" />
			<Background gap={20} size={1} />
		</SvelteFlow>
	{/if}
</div>

<ImgPreview />