feat: node store interface

This commit is contained in:
2024-04-20 02:41:18 +02:00
parent 1d203c687c
commit 78c88e4d66
51 changed files with 772 additions and 552 deletions

View File

@ -0,0 +1,81 @@
<script lang="ts">
import type { Writable } from "svelte/store";
export let activeId: Writable<string>;
$: [activeUser, activeCollection, activeNode] = $activeId.split(`/`);
</script>
<div class="breadcrumbs">
{#if activeUser}
<button
on:click={() => {
$activeId = "";
}}
>
root
</button>
{#if activeCollection}
<button
on:click={() => {
$activeId = activeUser;
}}
>
{activeUser}
</button>
{#if activeNode}
<button
on:click={() => {
$activeId = `${activeUser}/${activeCollection}`;
}}
>
{activeCollection}
</button>
<span>{activeNode}</span>
{:else}
<span>{activeCollection}</span>
{/if}
{:else}
<span>{activeUser}</span>
{/if}
{:else}
<span>root</span>
{/if}
</div>
<style>
.breadcrumbs {
display: flex;
align-items: center;
padding: 0.4em;
gap: 0.8em;
height: 1em;
border-bottom: solid thin var(--outline);
}
.breadcrumbs > button {
position: relative;
background: none;
font-family: var(--font-family);
border: none;
font-size: 1em;
padding: 0px;
cursor: pointer;
}
.breadcrumbs > button::after {
content: "/";
position: absolute;
right: -11px;
opacity: 0.5;
white-space: pre;
text-decoration: none !important;
}
.breadcrumbs > button:hover {
text-decoration: underline;
}
.breadcrumbs > span {
font-size: 1em;
opacity: 0.5;
}
</style>

View File

@ -0,0 +1,74 @@
<script lang="ts">
import NodeHtml from "$lib/graph-interface/node/NodeHTML.svelte";
import type { NodeType } from "@nodes/types";
export let node: NodeType;
let dragging = false;
function handleDragStart(e: DragEvent) {
dragging = true;
const box = (e?.target as HTMLElement)?.getBoundingClientRect();
if (e.dataTransfer === null) return;
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("data/node-id", node.id);
e.dataTransfer.setData(
"data/node-offset-x",
Math.round(box.left - e.clientX).toString(),
);
e.dataTransfer.setData(
"data/node-offset-y",
Math.round(box.top - e.clientY).toString(),
);
}
</script>
<div class="node-wrapper" class:dragging>
<div
on:dragend={() => {
dragging = false;
}}
draggable={true}
role="button"
tabindex="0"
on:dragstart={handleDragStart}
>
<NodeHtml
inView={true}
position={"relative"}
z={5}
node={{
id: 0,
type: node.id,
position: [0, 0],
tmp: {
type: node,
},
}}
/>
</div>
</div>
<style>
.node-wrapper {
width: fit-content;
border-radius: 5px;
box-sizing: border-box;
border: solid 2px transparent;
padding: 5px;
margin-left: -5px;
}
.dragging {
border: dashed 2px var(--outline);
}
.node-wrapper > div {
opacity: 1;
display: block;
pointer-events: all;
transition: opacity 0.2s;
}
.dragging > div {
opacity: 0.2;
}
</style>

View File

@ -0,0 +1,92 @@
<script lang="ts">
import type { GraphManager } from "$lib/graph-interface/graph-manager";
import Node from "$lib/graph-interface/node/Node.svelte";
import localStore from "$lib/helpers/localStore";
import type { RemoteNodeRegistry } from "$lib/node-registry-client";
import { Canvas } from "@threlte/core";
import BreadCrumbs from "./BreadCrumbs.svelte";
import NodeHtml from "$lib/graph-interface/node/NodeHTML.svelte";
import DraggableNode from "./DraggableNode.svelte";
export let nodeRegistry: RemoteNodeRegistry;
export let manager: GraphManager;
function handleImport() {
nodeRegistry.load([$activeId]);
}
const activeId = localStore<
`${string}` | `${string}/${string}` | `${string}/${string}/${string}`
>("nodes.store.activeId", "");
$: [activeUser, activeCollection, activeNode] = $activeId.split(`/`);
</script>
<BreadCrumbs {activeId} />
<div class="wrapper">
{#if !activeUser}
<h3>Users</h3>
{#await nodeRegistry.fetchUsers()}
<div>Loading...</div>
{:then users}
{#each users as user}
<button
on:click={() => {
$activeId = user.id;
}}>{user.id}</button
>
{/each}
{:catch error}
<div>{error.message}</div>
{/await}
{:else if !activeCollection}
{#await nodeRegistry.fetchUser(activeUser)}
<div>Loading...</div>
{:then user}
<h3>Collections</h3>
{#each user.collections as collection}
<button
on:click={() => {
$activeId = collection.id;
}}
>
{collection.id.split(`/`)[1]}
</button>
{/each}
{:catch error}
<div>{error.message}</div>
{/await}
{:else if !activeNode}
<h3>Nodes</h3>
{#await nodeRegistry.fetchCollection(`${activeUser}/${activeCollection}`)}
<div>Loading...</div>
{:then collection}
{#each collection.nodes as node}
<button
on:click={() => {
$activeId = node.id;
}}
>
{node.id.split(`/`)[2]}
</button>
{/each}
{:catch error}
<div>{error.message}</div>
{/await}
{:else}
{#await nodeRegistry.fetchNodeDefinition(`${activeUser}/${activeCollection}/${activeNode}`)}
<div>Loading...</div>
{:then node}
<DraggableNode {node} />
{:catch error}
<div>{error.message}</div>
{/await}
{/if}
</div>
<style>
.wrapper {
padding: 1em;
}
</style>

View File

@ -0,0 +1,31 @@
<script lang="ts">
</script>
<span class="spinner"></span>
<style>
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.spinner::before {
content: "";
position: absolute;
bottom: 10px;
right: 10px;
width: 20px;
height: 20px;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
animation: spin 1s linear infinite;
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' class='icon icon-tabler icons-tabler-outline icon-tabler-loader-2'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M12 3a9 9 0 1 0 9 9' /%3E%3C/svg%3E");
background-size: cover;
z-index: 2;
}
</style>