feat: update sidebar to svelte-5
All checks were successful
Deploy to GitHub Pages / build_site (push) Successful in 2m1s
All checks were successful
Deploy to GitHub Pages / build_site (push) Successful in 2m1s
This commit is contained in:
@@ -1,12 +1,16 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getContext } from "svelte";
|
import { getContext, type Snippet } from "svelte";
|
||||||
|
|
||||||
let index = -1;
|
let index = $state(-1);
|
||||||
let wrapper: HTMLDivElement;
|
let wrapper: HTMLDivElement;
|
||||||
|
|
||||||
$: if (index === -1) {
|
const { children } = $props<{ children?: Snippet }>();
|
||||||
index = getContext<() => number>("registerCell")();
|
|
||||||
}
|
$effect(() => {
|
||||||
|
if (index === -1) {
|
||||||
|
index = getContext<() => number>("registerCell")();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const sizes = getContext<{ value: string[] }>("sizes");
|
const sizes = getContext<{ value: string[] }>("sizes");
|
||||||
|
|
||||||
@@ -31,8 +35,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window
|
<svelte:window
|
||||||
on:mouseup={() => (mouseDown = false)}
|
onmouseup={() => (mouseDown = false)}
|
||||||
on:mousemove={handleMouseMove}
|
onmousemove={handleMouseMove}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if index > 0}
|
{#if index > 0}
|
||||||
@@ -40,12 +44,12 @@
|
|||||||
class="seperator"
|
class="seperator"
|
||||||
role="button"
|
role="button"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
on:mousedown={handleMouseDown}
|
onmousedown={handleMouseDown}
|
||||||
></div>
|
></div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="cell" bind:this={wrapper}>
|
<div class="cell" bind:this={wrapper}>
|
||||||
<slot />
|
{@render children?.()}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { setContext } from "svelte";
|
import { setContext, type Snippet } from "svelte";
|
||||||
|
|
||||||
export let id = "grid-0";
|
const { children, id } = $props<{ children?: Snippet; id?: string }>();
|
||||||
|
|
||||||
setContext("grid-id", id);
|
setContext("grid-id", id);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<slot {id} />
|
{@render children({ id })}
|
||||||
|
|||||||
@@ -1,36 +1,39 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getContext } from "svelte";
|
import { getContext, type Snippet } from "svelte";
|
||||||
import type { Readable } from "svelte/store";
|
import type { PanelState } from "./PanelState.svelte";
|
||||||
|
|
||||||
export let id: string;
|
const {
|
||||||
export let icon: string = "";
|
id,
|
||||||
export let title = "";
|
icon = "",
|
||||||
export let classes = "";
|
title = "",
|
||||||
export let hidden: boolean | undefined = undefined;
|
classes = "",
|
||||||
|
hidden,
|
||||||
|
children,
|
||||||
|
} = $props<{
|
||||||
|
id: string;
|
||||||
|
icon?: string;
|
||||||
|
title?: string;
|
||||||
|
classes?: string;
|
||||||
|
hidden?: boolean;
|
||||||
|
children?: Snippet;
|
||||||
|
}>();
|
||||||
|
|
||||||
const setVisibility =
|
const panelState = getContext<PanelState>("panel-state");
|
||||||
getContext<(id: string, visible: boolean) => void>("setVisibility");
|
|
||||||
|
|
||||||
$: if (typeof hidden === "boolean") {
|
const panel = panelState.registerPanel(id, icon, classes, hidden);
|
||||||
setVisibility(id, !hidden);
|
$effect(() => {
|
||||||
}
|
panel.hidden = hidden;
|
||||||
|
});
|
||||||
const registerPanel =
|
|
||||||
getContext<
|
|
||||||
(id: string, icon: string, classes: string) => Readable<boolean>
|
|
||||||
>("registerPanel");
|
|
||||||
|
|
||||||
let visible = registerPanel(id, icon, classes);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $visible}
|
{#if panelState.activePanel.value === id}
|
||||||
<div class="wrapper" class:hidden>
|
<div class="wrapper" class:hidden>
|
||||||
{#if title}
|
{#if title}
|
||||||
<header>
|
<header>
|
||||||
<h3>{title}</h3>
|
<h3>{title}</h3>
|
||||||
</header>
|
</header>
|
||||||
{/if}
|
{/if}
|
||||||
<slot />
|
{@render children?.()}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|||||||
35
app/src/lib/sidebar/PanelState.svelte.ts
Normal file
35
app/src/lib/sidebar/PanelState.svelte.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { localState } from "$lib/helpers/localState.svelte";
|
||||||
|
|
||||||
|
type Panel = {
|
||||||
|
icon: string;
|
||||||
|
classes: string;
|
||||||
|
hidden?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PanelState {
|
||||||
|
|
||||||
|
panels = $state<Record<string, Panel>>({});
|
||||||
|
activePanel = localState<string | boolean>("node.activePanel", "")
|
||||||
|
|
||||||
|
get keys() {
|
||||||
|
return Object.keys(this.panels);
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerPanel(id: string, icon: string, classes: string, hidden: boolean): Panel {
|
||||||
|
const state = $state({
|
||||||
|
icon: icon,
|
||||||
|
classes: classes,
|
||||||
|
hidden: hidden,
|
||||||
|
});
|
||||||
|
this.panels[id] = state;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toggleOpen() {
|
||||||
|
if (this.activePanel.value) {
|
||||||
|
this.activePanel.value = false;
|
||||||
|
} else {
|
||||||
|
this.activePanel.value = this.keys[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,78 +1,35 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import localStore from "$lib/helpers/localStore";
|
import { setContext, type Snippet } from "svelte";
|
||||||
import { setContext } from "svelte";
|
import { PanelState } from "./PanelState.svelte";
|
||||||
import { derived } from "svelte/store";
|
|
||||||
|
|
||||||
let panels: Record<
|
const state = new PanelState();
|
||||||
string,
|
setContext("panel-state", state);
|
||||||
{
|
|
||||||
icon: string;
|
|
||||||
id: string;
|
|
||||||
classes: string;
|
|
||||||
visible?: boolean;
|
|
||||||
}
|
|
||||||
> = {};
|
|
||||||
|
|
||||||
const activePanel = localStore<keyof typeof panels | false>(
|
const { children } = $props<{ children?: Snippet }>();
|
||||||
"nodes.settings.activePanel",
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
$: keys = panels
|
|
||||||
? (Object.keys(panels) as unknown as (keyof typeof panels)[]).filter(
|
|
||||||
(key) => !!panels[key]?.id,
|
|
||||||
)
|
|
||||||
: [];
|
|
||||||
|
|
||||||
setContext("setVisibility", (id: string, visible: boolean) => {
|
|
||||||
panels[id].visible = visible;
|
|
||||||
panels = { ...panels };
|
|
||||||
});
|
|
||||||
|
|
||||||
setContext("registerPanel", (id: string, icon: string, classes: string) => {
|
|
||||||
panels[id] = { id, icon, classes };
|
|
||||||
return derived(activePanel, ($activePanel) => {
|
|
||||||
return $activePanel === id;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function setActivePanel(panel: keyof typeof panels | false) {
|
|
||||||
if (panel === $activePanel) {
|
|
||||||
$activePanel = false;
|
|
||||||
} else if (panel) {
|
|
||||||
$activePanel = panel;
|
|
||||||
} else {
|
|
||||||
$activePanel = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper" class:visible={$activePanel}>
|
<div class="wrapper" class:visible={state.activePanel.value}>
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<button
|
<button aria-label="Close" onclick={() => state.toggleOpen()}>
|
||||||
aria-label="Close"
|
|
||||||
on:click={() => {
|
|
||||||
setActivePanel($activePanel ? false : keys[0]);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span class="icon-[tabler--settings]"></span>
|
<span class="icon-[tabler--settings]"></span>
|
||||||
<span class="absolute i-[tabler--chevron-left] w-6 h-6 block"></span>
|
<span class="absolute i-[tabler--chevron-left] w-6 h-6 block"></span>
|
||||||
</button>
|
</button>
|
||||||
{#each keys as panel (panels[panel].id)}
|
{#each state.keys as panelId (panelId)}
|
||||||
{#if panels[panel].visible !== false}
|
{#if !state.panels[panelId].hidden}
|
||||||
<button
|
<button
|
||||||
aria-label={panel}
|
aria-label={panelId}
|
||||||
class="tab {panels[panel].classes}"
|
class="tab {state.panels[panelId].classes}"
|
||||||
class:active={panel === $activePanel}
|
class:active={panelId === state.activePanel.value}
|
||||||
on:click={() => setActivePanel(panel)}
|
onclick={() => (state.activePanel.value = panelId)}
|
||||||
>
|
>
|
||||||
<span class={`block w-6 h-6 iconify ${panels[panel].icon}`}></span>
|
<span class={`block w-6 h-6 iconify ${state.panels[panelId].icon}`}
|
||||||
|
></span>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<slot />
|
{@render children?.()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
FileSaver.saveAs(blob, name + "." + extension);
|
FileSaver.saveAs(blob, name + "." + extension);
|
||||||
};
|
};
|
||||||
|
|
||||||
export let scene: Group;
|
const { scene } = $props<{ scene: Group }>();
|
||||||
|
|
||||||
let gltfExporter: GLTFExporter;
|
let gltfExporter: GLTFExporter;
|
||||||
async function exportGltf() {
|
async function exportGltf() {
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="p-2">
|
<div class="p-4">
|
||||||
<button on:click={exportObj}> export obj </button>
|
<button onclick={exportObj}> export obj </button>
|
||||||
<button on:click={exportGltf}> export gltf </button>
|
<button onclick={exportGltf}> export gltf </button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,32 +13,34 @@
|
|||||||
let { keymaps }: Props = $props();
|
let { keymaps }: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<table class="wrapper">
|
<div class="p-4">
|
||||||
<tbody>
|
<table class="wrapper">
|
||||||
{#each keymaps as keymap}
|
<tbody>
|
||||||
<tr>
|
{#each keymaps as keymap}
|
||||||
<td colspan="2">
|
|
||||||
<h3>{keymap.title}</h3>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{#each get(keymap.keymap?.keys) as key}
|
|
||||||
<tr>
|
<tr>
|
||||||
{#if key.description}
|
<td colspan="2">
|
||||||
<td class="command-wrapper">
|
<h3>{keymap.title}</h3>
|
||||||
<ShortCut
|
</td>
|
||||||
alt={key.alt}
|
|
||||||
ctrl={key.ctrl}
|
|
||||||
shift={key.shift}
|
|
||||||
key={key.key}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td>{key.description}</td>
|
|
||||||
{/if}
|
|
||||||
</tr>
|
</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}
|
{/each}
|
||||||
{/each}
|
</tbody>
|
||||||
</tbody>
|
</table>
|
||||||
</table>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.wrapper {
|
.wrapper {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import "@nodarium/ui/app.css";
|
import "@nodarium/ui/app.css";
|
||||||
import "../app.css";
|
import "../app.css";
|
||||||
|
import type { Snippet } from "svelte";
|
||||||
|
const { children } = $props<{ children?: Snippet }>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<slot />
|
{@render children?.()}
|
||||||
|
|||||||
Reference in New Issue
Block a user