feat: some shit
This commit is contained in:
@@ -39,6 +39,7 @@ export const AppSettingTypes = {
|
||||
}
|
||||
},
|
||||
debug: {
|
||||
title: "Debug",
|
||||
wireframe: {
|
||||
type: "boolean",
|
||||
label: "Wireframe",
|
||||
@@ -79,7 +80,8 @@ export const AppSettingTypes = {
|
||||
amount: {
|
||||
type: "integer",
|
||||
min: 2,
|
||||
max: 15
|
||||
max: 15,
|
||||
value: 4
|
||||
},
|
||||
loadGrid: {
|
||||
type: "button",
|
||||
@@ -138,8 +140,8 @@ export const appSettings = localState("app-settings", settingsToStore(AppSetting
|
||||
|
||||
$effect.root(() => {
|
||||
$effect(() => {
|
||||
const { theme } = $state.snapshot(appSettings);
|
||||
const classes = document.body.parentElement?.classList;
|
||||
const theme = appSettings.theme;
|
||||
const classes = document.documentElement.classList;
|
||||
const newClassName = `theme-${theme}`;
|
||||
if (classes) {
|
||||
for (const className of classes) {
|
||||
@@ -148,6 +150,6 @@ $effect.root(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
document.body?.parentElement?.classList.add(newClassName);
|
||||
document.documentElement.classList.add(newClassName);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
import localStore from "$lib/helpers/localStore";
|
||||
|
||||
export const AppSettings = localStore("node.settings", {
|
||||
theme: 0,
|
||||
showGrid: true,
|
||||
showNodeGrid: true,
|
||||
snapToGrid: true,
|
||||
showHelp: false,
|
||||
wireframe: false,
|
||||
showIndices: false,
|
||||
showVertices: false,
|
||||
showPerformancePanel: false,
|
||||
showBenchmarkPanel: false,
|
||||
centerCamera: true,
|
||||
showStemLines: false,
|
||||
useWorker: true,
|
||||
amount: 5
|
||||
});
|
||||
|
||||
const themes = ["dark", "light", "catppuccin", "solarized", "high-contrast", "nord", "dracula"];
|
||||
|
||||
AppSettings.subscribe((value) => {
|
||||
const classes = document.body.parentElement?.classList;
|
||||
const newClassName = `theme-${themes[value.theme]}`;
|
||||
if (classes) {
|
||||
for (const className of classes) {
|
||||
if (className.startsWith("theme-") && className !== newClassName) {
|
||||
classes.remove(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.body?.parentElement?.classList.add(newClassName);
|
||||
});
|
||||
|
||||
export const AppSettingTypes = {
|
||||
theme: {
|
||||
type: "select",
|
||||
options: themes,
|
||||
label: "Theme",
|
||||
value: themes[0],
|
||||
},
|
||||
showGrid: {
|
||||
type: "boolean",
|
||||
label: "Show Grid",
|
||||
value: true,
|
||||
},
|
||||
centerCamera: {
|
||||
type: "boolean",
|
||||
label: "Center Camera",
|
||||
value: true
|
||||
},
|
||||
nodeInterface: {
|
||||
__title: "Node Interface",
|
||||
showNodeGrid: {
|
||||
type: "boolean",
|
||||
label: "Show Grid",
|
||||
value: true
|
||||
},
|
||||
snapToGrid: {
|
||||
type: "boolean",
|
||||
label: "Snap to Grid",
|
||||
value: true
|
||||
},
|
||||
showHelp: {
|
||||
type: "boolean",
|
||||
label: "Show Help",
|
||||
value: false
|
||||
}
|
||||
},
|
||||
debug: {
|
||||
wireframe: {
|
||||
type: "boolean",
|
||||
label: "Wireframe",
|
||||
value: false,
|
||||
},
|
||||
useWorker: {
|
||||
type: "boolean",
|
||||
label: "Execute runtime in worker",
|
||||
value: true,
|
||||
},
|
||||
showIndices: {
|
||||
type: "boolean",
|
||||
label: "Show Indices",
|
||||
value: false,
|
||||
},
|
||||
showPerformancePanel: {
|
||||
type: "boolean",
|
||||
label: "Show Performance Panel",
|
||||
value: false,
|
||||
},
|
||||
showBenchmarkPanel: {
|
||||
type: "boolean",
|
||||
label: "Show Benchmark Panel",
|
||||
value: false,
|
||||
},
|
||||
showVertices: {
|
||||
type: "boolean",
|
||||
label: "Show Vertices",
|
||||
value: false,
|
||||
},
|
||||
showStemLines: {
|
||||
type: "boolean",
|
||||
label: "Show Stem Lines",
|
||||
value: false,
|
||||
},
|
||||
stressTest: {
|
||||
__title: "Stress Test",
|
||||
amount: {
|
||||
type: "integer",
|
||||
min: 2,
|
||||
max: 15
|
||||
},
|
||||
loadGrid: {
|
||||
type: "button",
|
||||
label: "Load Grid"
|
||||
},
|
||||
loadTree: {
|
||||
type: "button",
|
||||
label: "Load Tree"
|
||||
},
|
||||
lottaFaces: {
|
||||
type: "button",
|
||||
label: "Load 'lots of faces'"
|
||||
},
|
||||
lottaNodes: {
|
||||
type: "button",
|
||||
label: "Load 'lots of nodes'"
|
||||
},
|
||||
lottaNodesAndFaces: {
|
||||
type: "button",
|
||||
label: "Load 'lots of nodes and faces'"
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
92
app/src/lib/settings/panels/ActiveNodeSelected.svelte
Normal file
92
app/src/lib/settings/panels/ActiveNodeSelected.svelte
Normal file
@@ -0,0 +1,92 @@
|
||||
<script lang="ts">
|
||||
import type { Node, NodeInput } from "@nodes/types";
|
||||
import NestedSettings from "./NestedSettings.svelte";
|
||||
import type { GraphManager } from "$lib/graph-interface/graph-manager";
|
||||
|
||||
type Props = {
|
||||
manager: GraphManager;
|
||||
node: Node;
|
||||
};
|
||||
|
||||
const { manager, node }: Props = $props();
|
||||
|
||||
const nodeDefinition = filterInputs(node.tmp?.type?.inputs);
|
||||
function filterInputs(inputs?: Record<string, NodeInput>) {
|
||||
const _inputs = $state.snapshot(inputs);
|
||||
return Object.fromEntries(
|
||||
Object.entries(structuredClone(_inputs ?? {}))
|
||||
.filter(([_key, value]) => {
|
||||
return value.hidden === true;
|
||||
})
|
||||
.map(([key, value]) => {
|
||||
//@ts-ignore
|
||||
value.__node_type = node?.tmp?.type.id;
|
||||
//@ts-ignore
|
||||
value.__node_input = key;
|
||||
return [key, value];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
type Store = Record<string, number | number[]>;
|
||||
let store = $state<Store>(createStore(node?.props, nodeDefinition));
|
||||
function createStore(
|
||||
props: Node["props"],
|
||||
inputs: Record<string, NodeInput>,
|
||||
): Store {
|
||||
const store: Store = {};
|
||||
Object.keys(inputs).forEach((key) => {
|
||||
if (props) {
|
||||
//@ts-ignore
|
||||
store[key] = props[key] || inputs[key].value;
|
||||
}
|
||||
});
|
||||
return store;
|
||||
}
|
||||
|
||||
let lastPropsHash = "";
|
||||
function updateNode() {
|
||||
if (!node || !store) return;
|
||||
let needsUpdate = false;
|
||||
Object.keys(store).forEach((_key: string) => {
|
||||
node.props = node.props || {};
|
||||
const key = _key as keyof typeof store;
|
||||
if (node && store) {
|
||||
needsUpdate = true;
|
||||
node.props[key] = store[key];
|
||||
}
|
||||
});
|
||||
|
||||
let propsHash = JSON.stringify(node.props);
|
||||
if (propsHash === lastPropsHash) {
|
||||
return;
|
||||
}
|
||||
lastPropsHash = propsHash;
|
||||
|
||||
if (needsUpdate) {
|
||||
manager.execute();
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if (store && store) {
|
||||
updateNode();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if node}
|
||||
{#key node.id}
|
||||
{#if nodeDefinition && store && Object.keys(nodeDefinition).length > 0}
|
||||
<NestedSettings
|
||||
id="activeNodeSettings"
|
||||
bind:value={store}
|
||||
type={nodeDefinition}
|
||||
/>
|
||||
{:else}
|
||||
<p class="mx-4">Active Node has no Settings</p>
|
||||
{/if}
|
||||
{/key}
|
||||
{:else}
|
||||
<p class="mx-4">No active node</p>
|
||||
{/if}
|
||||
@@ -1,85 +1,20 @@
|
||||
<script lang="ts">
|
||||
import type { Node, NodeInput } from "@nodes/types";
|
||||
import NestedSettings from "./NestedSettings.svelte";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import type { Node } from "@nodes/types";
|
||||
import type { GraphManager } from "$lib/graph-interface/graph-manager";
|
||||
import ActiveNodeSelected from "./ActiveNodeSelected.svelte";
|
||||
|
||||
export let manager: GraphManager;
|
||||
export let node: Node | undefined;
|
||||
type Props = {
|
||||
manager: GraphManager;
|
||||
node: Node | undefined;
|
||||
};
|
||||
|
||||
function filterInputs(inputs: Record<string, NodeInput>) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(inputs)
|
||||
.filter(([_key, value]) => {
|
||||
return value.hidden === true;
|
||||
})
|
||||
.map(([key, value]) => {
|
||||
//@ts-ignore
|
||||
value.__node_type = node?.tmp?.type.id;
|
||||
//@ts-ignore
|
||||
value.__node_input = key;
|
||||
return [key, value];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function createStore(
|
||||
props: Node["props"],
|
||||
inputs: Record<string, NodeInput>,
|
||||
) {
|
||||
const store: Record<string, unknown> = {};
|
||||
Object.keys(inputs).forEach((key) => {
|
||||
if (props) {
|
||||
//@ts-ignore
|
||||
store[key] = props[key] || inputs[key].value;
|
||||
}
|
||||
});
|
||||
return writable(store);
|
||||
}
|
||||
|
||||
let nodeDefinition: Record<string, NodeInput> | undefined;
|
||||
$: nodeDefinition = node?.tmp?.type
|
||||
? filterInputs(node.tmp.type.inputs)
|
||||
: undefined;
|
||||
$: store = node ? createStore(node.props, nodeDefinition) : undefined;
|
||||
|
||||
let lastPropsHash = "";
|
||||
function updateNode() {
|
||||
if (!node || !$store) return;
|
||||
let needsUpdate = false;
|
||||
Object.keys($store).forEach((_key: string) => {
|
||||
node.props = node.props || {};
|
||||
const key = _key as keyof typeof $store;
|
||||
if (node && $store) {
|
||||
needsUpdate = true;
|
||||
node.props[key] = $store[key];
|
||||
}
|
||||
});
|
||||
let propsHash = JSON.stringify(node.props);
|
||||
if (propsHash === lastPropsHash) {
|
||||
return;
|
||||
}
|
||||
lastPropsHash = propsHash;
|
||||
// console.log(needsUpdate, node.props, $store);
|
||||
if (needsUpdate) {
|
||||
manager.execute();
|
||||
}
|
||||
}
|
||||
|
||||
$: if (store && $store) {
|
||||
updateNode();
|
||||
}
|
||||
const { manager, node }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if node}
|
||||
{#key node.id}
|
||||
{#if nodeDefinition && store && Object.keys(nodeDefinition).length > 0}
|
||||
<NestedSettings
|
||||
id="activeNodeSettings"
|
||||
settings={nodeDefinition}
|
||||
{store}
|
||||
/>
|
||||
{#if node}
|
||||
<ActiveNodeSelected {manager} {node} />
|
||||
{:else}
|
||||
<p class="mx-4">Active Node has no Settings</p>
|
||||
{/if}
|
||||
|
||||
@@ -1,44 +1,49 @@
|
||||
<script lang="ts">
|
||||
import type { createKeyMap } from "$lib/helpers/createKeyMap";
|
||||
import { ShortCut } from "@nodes/ui";
|
||||
import { get } from "svelte/store";
|
||||
|
||||
export let keymap: ReturnType<typeof createKeyMap>;
|
||||
const keys = keymap?.keys;
|
||||
export let title = "Keymap";
|
||||
type Props = {
|
||||
keymaps: {
|
||||
keymap: ReturnType<typeof createKeyMap>;
|
||||
title: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
let { keymaps }: Props = $props();
|
||||
console.log({ keymaps });
|
||||
</script>
|
||||
|
||||
<div class="wrapper">
|
||||
<h3>{title}</h3>
|
||||
|
||||
<section>
|
||||
{#each $keys as key}
|
||||
{#if key.description}
|
||||
<div class="command-wrapper">
|
||||
<ShortCut
|
||||
alt={key.alt}
|
||||
ctrl={key.ctrl}
|
||||
shift={key.shift}
|
||||
key={key.key}
|
||||
/>
|
||||
</div>
|
||||
<p>{key.description}</p>
|
||||
{/if}
|
||||
<table class="wrapper">
|
||||
<tbody>
|
||||
{#each keymaps as keymap}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<h3>{keymap.title}</h3>
|
||||
</td>
|
||||
</tr>
|
||||
{#each get(keymap.keymap?.keys) as key}
|
||||
<tr>
|
||||
{#if key.description}
|
||||
<td class="command-wrapper">
|
||||
<ShortCut
|
||||
alt={key.alt}
|
||||
ctrl={key.ctrl}
|
||||
shift={key.shift}
|
||||
key={key.key}
|
||||
/>
|
||||
</td>
|
||||
<td>{key.description}</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/each}
|
||||
{/each}
|
||||
</section>
|
||||
</div>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<style>
|
||||
.wrapper {
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
section {
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@@ -51,10 +56,11 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
p {
|
||||
td {
|
||||
font-size: 0.9em;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
padding: 7px;
|
||||
padding-left: 0;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<script module lang="ts">
|
||||
let openSections = localState<Record<string,boolean>>("open-details", {});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import NestedSettings from "./NestedSettings.svelte";
|
||||
import {localState} from "$lib/helpers/localState.svelte";
|
||||
@@ -11,15 +15,18 @@
|
||||
interface Nested {
|
||||
[key: string]: (Nested & { title?: string }) | InputType;
|
||||
}
|
||||
type SettingsType = Record<string, Nested>;
|
||||
type SettingsValue = Record<string, Record<string, unknown> | string | number | boolean>;
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
key?: string;
|
||||
value: Record<string, unknown> | string | number | boolean;
|
||||
type: Nested;
|
||||
value: SettingsValue;
|
||||
type: SettingsType;
|
||||
depth?: number;
|
||||
};
|
||||
|
||||
|
||||
let { id, key = "", value = $bindable(), type, depth = 0 }: Props = $props();
|
||||
|
||||
function isNodeInput(v: InputType | Nested): v is InputType {
|
||||
@@ -28,14 +35,14 @@
|
||||
|
||||
let internalValue = $state(Array.isArray(type?.[key]?.options) ? type[key]?.options?.indexOf(value?.[key]) : value?.[key]);
|
||||
|
||||
let openSections = localState("open-details", {});
|
||||
let open = $state(openSections[id]);
|
||||
if(depth > 0 && !isNodeInput(type[key])){
|
||||
$effect(() => {
|
||||
if(open !== undefined){}
|
||||
openSections[id] = open;
|
||||
});
|
||||
}
|
||||
if(open !== undefined){
|
||||
openSections[id] = open;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$effect(() => {
|
||||
@@ -49,7 +56,7 @@
|
||||
</script>
|
||||
|
||||
{#if key && isNodeInput(type?.[key]) }
|
||||
<div class="input input-{type[key].type}">
|
||||
<div class="input input-{type[key].type}" class:first-level={depth === 1}>
|
||||
{#if type[key].type === "button"}
|
||||
<button onclick={() => console.log(type[key])}>
|
||||
{type[key].label || key}
|
||||
@@ -65,27 +72,25 @@
|
||||
<NestedSettings
|
||||
id={`${id}.${childKey}`}
|
||||
key={childKey}
|
||||
value={value as Record<string, unknown>}
|
||||
type={type as Nested}
|
||||
value={value}
|
||||
type={type}
|
||||
depth={depth + 1}
|
||||
/>
|
||||
{/each}
|
||||
{#if depth > 0}
|
||||
<hr />
|
||||
{/if}
|
||||
{:else if key && type?.[key]}
|
||||
{#if depth > 0}
|
||||
<hr />
|
||||
{/if}
|
||||
<details bind:open>
|
||||
<summary>{type[key]?.title||key}</summary>
|
||||
<summary><p>{type[key]?.title||key}</p></summary>
|
||||
<div class="content">
|
||||
{#each Object.keys(type[key]).filter((key) => key !== "title") as childKey}
|
||||
<NestedSettings
|
||||
id={`${id}.${childKey}`}
|
||||
key={childKey}
|
||||
value={value[key] as Record<string, unknown>}
|
||||
type={type[key] as Nested}
|
||||
value={value[key] as SettingsValue}
|
||||
type={type[key] as SettingsType}
|
||||
depth={depth + 1}
|
||||
/>
|
||||
{/each}
|
||||
@@ -103,9 +108,18 @@
|
||||
user-select: none;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
summary::marker { }
|
||||
|
||||
summary > p {
|
||||
display: inline;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
details {
|
||||
padding: 1em;
|
||||
padding-bottom: 0;
|
||||
padding-left: 21px;
|
||||
}
|
||||
|
||||
.input {
|
||||
@@ -114,7 +128,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding-left: 14px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.input-boolean {
|
||||
@@ -126,16 +140,12 @@
|
||||
order: 2;
|
||||
}
|
||||
|
||||
.first-level > .input {
|
||||
padding-right: 1rem;
|
||||
.first-level.input {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
.first-level {
|
||||
border-bottom: solid thin var(--outline);
|
||||
}
|
||||
.first-level > details {
|
||||
border: none;
|
||||
}
|
||||
hr {
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
|
||||
Reference in New Issue
Block a user