chore: setup linting

This commit is contained in:
Max Richter
2026-02-02 16:22:14 +01:00
parent 137425b31b
commit 30e897468a
174 changed files with 6043 additions and 5107 deletions

View File

@@ -1,13 +1,13 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
}
export {};

View File

@@ -1,12 +1,12 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div>%sveltekit.body%</div>
</body>
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div>%sveltekit.body%</div>
</body>
</html>

View File

@@ -6,7 +6,8 @@
open?: boolean;
}
let { title = "Details", transparent = false, children, open = $bindable(false) }: Props = $props();
let { title = 'Details', transparent = false, children, open = $bindable(false) }: Props =
$props();
</script>
<details class:transparent bind:open>
@@ -33,5 +34,4 @@
padding: 0;
outline: none;
}
</style>

View File

@@ -1,25 +1,30 @@
<script lang="ts">
import type { NodeInput } from '@nodarium/types';
import type { NodeInput } from '@nodarium/types';
import { Checkbox, Number, Select, Vec3 } from './index.js';
import { Checkbox, Float, Select, Vec3 } from './index.js';
interface Props {
input: NodeInput;
value: any;
id?: string;
}
interface Props {
input: NodeInput;
value: unknown;
id?: string;
}
let { input, value = $bindable(), id }: Props = $props();
let { input, value = $bindable(), id }: Props = $props();
</script>
{#if input.type === 'float'}
<Number bind:value min={input?.min} max={input?.max} step={input?.step} />
<Float
bind:value={value as number}
min={input?.min}
max={input?.max}
step={input?.step}
/>
{:else if input.type === 'integer'}
<Number bind:value min={input?.min} max={input?.max} />
<Float bind:value={value as number} min={input?.min} max={input?.max} />
{:else if input.type === 'boolean'}
<Checkbox bind:value {id} />
<Checkbox bind:value={value as boolean} {id} />
{:else if input.type === 'select'}
<Select bind:value options={input.options} {id} />
<Select bind:value={value as number} options={input.options} {id} />
{:else if input.type === 'vec3'}
<Vec3 bind:value {id} />
<Vec3 bind:value={value as [number, number, number]} {id} />
{/if}

View File

@@ -1,39 +1,39 @@
<script lang="ts">
interface Props {
ctrl?: boolean;
shift?: boolean;
alt?: boolean;
key: string | string[];
}
interface Props {
ctrl?: boolean;
shift?: boolean;
alt?: boolean;
key: string | string[];
}
let { ctrl = false, shift = false, alt = false, key }: Props = $props();
let { ctrl = false, shift = false, alt = false, key }: Props = $props();
</script>
<div class="command">
{#if ctrl}
<span>Ctrl</span>
{/if}
{#if shift}
<span>Shift</span>
{/if}
{#if alt}
<span>Alt</span>
{/if}
{key}
{#if ctrl}
<span>Ctrl</span>
{/if}
{#if shift}
<span>Shift</span>
{/if}
{#if alt}
<span>Alt</span>
{/if}
{key}
</div>
<style>
.command {
background: var(--layer-2);
padding: 0.4em;
font-size: 0.8em;
border-radius: 0.3em;
white-space: nowrap;
width: fit-content;
}
.command {
background: var(--layer-2);
padding: 0.4em;
font-size: 0.8em;
border-radius: 0.3em;
white-space: nowrap;
width: fit-content;
}
span::after {
content: ' +';
opacity: 0.5;
}
span::after {
content: " +";
opacity: 0.5;
}
</style>

View File

@@ -4,10 +4,10 @@
@font-face {
font-display: swap;
/* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Fira Code';
font-family: "Fira Code";
font-style: normal;
font-weight: 300;
src: url('/fonts/fira-code-v22-latin-300.woff2') format('woff2');
src: url("/fonts/fira-code-v22-latin-300.woff2") format("woff2");
/* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
@@ -15,15 +15,15 @@
@font-face {
font-display: swap;
/* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Fira Code';
font-family: "Fira Code";
font-style: normal;
font-weight: 600;
src: url('/fonts/fira-code-v22-latin-600.woff2') format('woff2');
src: url("/fonts/fira-code-v22-latin-600.woff2") format("woff2");
/* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
:root {
--font-family: 'Fira Code', monospace;
--font-family: "Fira Code", monospace;
font-family: var(--font-family);
/* Spacing */
@@ -37,14 +37,13 @@
/* Large spacing */
--spacing-xl: 32px;
/* Extra large spacing */
}
@theme {
--color-neutral-100: #E7E7E7;
--color-neutral-200: #CECECE;
--color-neutral-300: #7C7C7C;
--color-neutral-400: #2D2D2D;
--color-neutral-100: #e7e7e7;
--color-neutral-200: #cecece;
--color-neutral-300: #7c7c7c;
--color-neutral-400: #2d2d2d;
--color-neutral-500: #171717;
--color-neutral-800: #111111;
--color-neutral-900: #060606;
@@ -65,10 +64,10 @@
}
html {
--neutral-100: #E7E7E7;
--neutral-200: #CECECE;
--neutral-300: #7C7C7C;
--neutral-400: #2D2D2D;
--neutral-100: #e7e7e7;
--neutral-200: #cecece;
--neutral-300: #7c7c7c;
--neutral-400: #2d2d2d;
--neutral-500: #171717;
--neutral-800: #111111;
--neutral-900: #060606;
@@ -123,45 +122,45 @@ html.theme-solarized {
}
html.theme-catppuccin {
--text-color: #CDD6F4;
--text-color: #cdd6f4;
--outline: #3e3e4f;
--layer-3: #a8aac8;
--layer-2: #313244;
--layer-1: #1E1E2E;
--layer-1: #1e1e2e;
--layer-0: #11111b;
--connection: #444459;
}
html.theme-high-contrast {
--text-color: #FFFFFF;
--text-color: #ffffff;
--outline: white;
--layer-0: #000000;
--layer-1: black;
--layer-2: #222222;
--layer-3: #FFFFFF;
--connection: #FFF;
--layer-3: #ffffff;
--connection: #fff;
}
html.theme-nord {
--text-color: #D8DEE9;
--outline: #4C566A;
--layer-0: #2E3440;
--layer-1: #3B4252;
--layer-2: #434C5E;
--layer-3: #5E81AC;
--text-color: #d8dee9;
--outline: #4c566a;
--layer-0: #2e3440;
--layer-1: #3b4252;
--layer-2: #434c5e;
--layer-3: #5e81ac;
--active: #8999bd;
--selected: #b76c3f;
--connection: #4C566A;
--connection: #4c566a;
}
html.theme-dracula {
--text-color: #F8F8F2;
--outline: #6272A4;
--layer-0: #282A36;
--layer-1: #44475A;
--layer-2: #32374D;
--layer-3: #BD93F9;
--connection: #6272A4;
--text-color: #f8f8f2;
--outline: #6272a4;
--layer-0: #282a36;
--layer-1: #44475a;
--layer-2: #32374d;
--layer-3: #bd93f9;
--connection: #6272a4;
}
button {

View File

@@ -1,7 +1,6 @@
export { default as Input } from './Input.svelte';
export { default as Checkbox } from './inputs/Checkbox.svelte';
export { default as Float, default as Number } from './inputs/Float.svelte';
export { default as Integer } from './inputs/Integer.svelte';
export { default as Float } from './inputs/Float.svelte';
export { default as Select } from './inputs/Select.svelte';
export { default as Vec3 } from './inputs/Vec3.svelte';

View File

@@ -1,47 +1,47 @@
<script lang="ts">
interface Props {
value: boolean;
id?: string;
}
interface Props {
value: boolean;
id?: string;
}
let { value = $bindable(false), id }: Props = $props();
let { value = $bindable(false), id }: Props = $props();
$effect(() => {
if (typeof value === 'string') {
value = value === 'true';
} else if (typeof value === 'number') {
value = value === 1;
} else if (!(typeof value === 'boolean')) {
value = !!value;
}
});
$effect(() => {
if (typeof value === 'string') {
value = value === 'true';
} else if (typeof value === 'number') {
value = value === 1;
} else if (!(typeof value === 'boolean')) {
value = !!value;
}
});
</script>
<label
class="relative inline-flex h-[22px] w-[22px] cursor-pointer items-center justify-center bg-[var(--layer-2)] rounded-[5px]"
class="relative inline-flex h-[22px] w-[22px] cursor-pointer items-center justify-center bg-[var(--layer-2)] rounded-[5px]"
>
<input
type="checkbox"
bind:checked={value}
class="peer absolute h-px w-px overflow-hidden whitespace-nowrap border-0 p-0 [clip:rect(0,0,0,0)]"
{id}
/>
<span
class="absolute opacity-0 peer-checked:opacity-100 transition-opacity duration-100 flex w-full h-full items-center justify-center"
>
<svg
viewBox="0 0 19 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="h-[10px] w-[12px] text-[var(--text-color)]"
>
<path
d="M2 7L7 12L17 2"
stroke="currentColor"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</span>
<input
type="checkbox"
bind:checked={value}
class="peer absolute h-px w-px overflow-hidden whitespace-nowrap border-0 p-0 [clip:rect(0,0,0,0)]"
{id}
/>
<span
class="absolute opacity-0 peer-checked:opacity-100 transition-opacity duration-100 flex w-full h-full items-center justify-center"
>
<svg
viewBox="0 0 19 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="h-[10px] w-[12px] text-[var(--text-color)]"
>
<path
d="M2 7L7 12L17 2"
stroke="currentColor"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</span>
</label>

View File

@@ -1,194 +1,199 @@
<script lang="ts">
interface Props {
value?: number;
step?: number;
min?: number;
max?: number;
id?: string;
}
interface Props {
value?: number;
step?: number;
min?: number;
max?: number;
id?: string;
}
let {
value = $bindable(0.5),
step,
min = $bindable(0),
max = $bindable(1),
id
}: Props = $props();
let {
value = $bindable(0.5),
step,
min = $bindable(0),
max = $bindable(1),
id
}: Props = $props();
if (min > max) {
[min, max] = [max, min];
}
if (value > max) {
max = value;
}
if (min > max) {
[min, max] = [max, min];
}
if (value > max) {
max = value;
}
// svelte-ignore state_referenced_locally only use initial values
const precision = ((step || value).toString().split('.')[1] || '').length;
const precision = $derived(
((step || value).toString().split('.')[1] || '').length
);
function strip(input: number) {
return +parseFloat(input + '').toFixed(precision);
}
function strip(input: number) {
return +parseFloat(input + '').toFixed(precision);
}
let inputEl: HTMLInputElement | undefined = $state();
let inputEl: HTMLInputElement | undefined = $state();
let oldValue: number;
function handleChange() {
if (value === oldValue) return;
oldValue = value;
}
let oldValue: number;
function handleChange() {
if (value === oldValue) return;
oldValue = value;
}
let isMouseDown = $state(false);
let downV = 0;
let vx = 0;
let rect: DOMRect;
let isMouseDown = $state(false);
let downV = 0;
let vx = 0;
let rect: DOMRect;
function handleMouseDown(ev: MouseEvent) {
ev.preventDefault();
function handleMouseDown(ev: MouseEvent) {
ev.preventDefault();
if (!inputEl) return;
if (!inputEl) return;
inputEl.focus();
inputEl.focus();
isMouseDown = true;
isMouseDown = true;
downV = value;
rect = inputEl.getBoundingClientRect();
downV = value;
rect = inputEl.getBoundingClientRect();
window.removeEventListener('mousemove', handleMouseMove);
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
document.body.style.cursor = 'ew-resize';
(ev.target as HTMLElement)?.blur();
}
window.removeEventListener('mousemove', handleMouseMove);
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
document.body.style.cursor = 'ew-resize';
(ev.target as HTMLElement)?.blur();
}
function handleMouseUp() {
isMouseDown = false;
function handleMouseUp() {
isMouseDown = false;
if (downV === value) {
inputEl?.focus();
}
if (downV === value) {
inputEl?.focus();
}
if (value > max) {
max = value;
}
if (value > max) {
max = value;
}
if (value < min) {
min = value;
}
if (value < min) {
min = value;
}
document.body.style.cursor = 'unset';
window.removeEventListener('mouseup', handleMouseUp);
window.removeEventListener('mousemove', handleMouseMove);
}
document.body.style.cursor = 'unset';
window.removeEventListener('mouseup', handleMouseUp);
window.removeEventListener('mousemove', handleMouseMove);
}
function handleKeyDown(ev: KeyboardEvent) {
if (ev.key === 'Escape' || ev.key === 'Enter') {
handleMouseUp();
inputEl?.blur();
}
}
function handleKeyDown(ev: KeyboardEvent) {
if (ev.key === 'Escape' || ev.key === 'Enter') {
handleMouseUp();
inputEl?.blur();
}
}
function handleMouseMove(ev: MouseEvent) {
vx = (ev.clientX - rect.left) / rect.width;
function handleMouseMove(ev: MouseEvent) {
vx = (ev.clientX - rect.left) / rect.width;
if (ev.ctrlKey) {
let v = min + (max - min) * vx;
value = v;
} else {
value = Math.max(Math.min(min + (max - min) * vx, max), min);
}
if (ev.ctrlKey) {
let v = min + (max - min) * vx;
value = v;
} else {
value = Math.max(Math.min(min + (max - min) * vx, max), min);
}
value = strip(value);
value = strip(value);
// With ctrl + outside of input ev.target becomes HTMLDocument
if (ev.target instanceof HTMLElement) {
ev.target?.blur();
}
}
// With ctrl + outside of input ev.target becomes HTMLDocument
if (ev.target instanceof HTMLElement) {
ev.target?.blur();
}
}
$effect(() => {
if (value.toString().length > 5) {
value = strip(value);
}
value !== undefined && handleChange();
});
$effect(() => {
if (value.toString().length > 5) {
value = strip(value);
}
if (value !== undefined) {
handleChange();
}
});
let width = $derived(
Number.isFinite(value) ? Math.max((value?.toString().length ?? 1) * 8, 50) + 'px' : '20px'
);
let width = $derived(
Number.isFinite(value)
? Math.max((value?.toString().length ?? 1) * 8, 50) + 'px'
: '20px'
);
</script>
<div class="component-wrapper" class:is-down={isMouseDown}>
<span class="overlay" style={`width: ${((value - min) / (max - min)) * 100}%`}></span>
<input
bind:value
bind:this={inputEl}
{id}
{step}
{max}
{min}
onkeydown={handleKeyDown}
onmousedown={handleMouseDown}
onmouseup={handleMouseUp}
type="number"
style={`width:${width};`}
/>
<span class="overlay" style={`width: ${((value - min) / (max - min)) * 100}%`}></span>
<input
bind:value
bind:this={inputEl}
{id}
{step}
{max}
{min}
onkeydown={handleKeyDown}
onmousedown={handleMouseDown}
onmouseup={handleMouseUp}
type="number"
style={`width:${width};`}
/>
</div>
<style>
.component-wrapper {
position: relative;
background-color: var(--layer-2, #4b4b4b);
border-radius: 4px;
user-select: none;
transition: box-shadow 0.3s ease;
border: solid 1px var(--outline);
box-sizing: border-box;
overflow: hidden;
border-radius: var(--border-radius, 2px);
}
.component-wrapper {
position: relative;
background-color: var(--layer-2, #4b4b4b);
border-radius: 4px;
user-select: none;
transition: box-shadow 0.3s ease;
border: solid 1px var(--outline);
box-sizing: border-box;
overflow: hidden;
border-radius: var(--border-radius, 2px);
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
input[type="number"] {
box-sizing: border-box;
-webkit-appearance: textfield;
-moz-appearance: textfield;
appearance: textfield;
font-family: var(--font-family);
font-variant-numeric: tabular-nums;
cursor: pointer;
color: var(--text-color);
background-color: transparent;
padding: var(--padding, 6px);
font-size: 1em;
padding-inline: 10px;
text-align: center;
border: none;
border-style: none;
min-width: 100%;
}
input[type="number"] {
box-sizing: border-box;
-webkit-appearance: textfield;
-moz-appearance: textfield;
appearance: textfield;
font-family: var(--font-family);
font-variant-numeric: tabular-nums;
cursor: pointer;
color: var(--text-color);
background-color: transparent;
padding: var(--padding, 6px);
font-size: 1em;
padding-inline: 10px;
text-align: center;
border: none;
border-style: none;
min-width: 100%;
}
.is-down > input {
cursor: ew-resize !important;
}
.is-down > input {
cursor: ew-resize !important;
}
.overlay {
position: absolute;
top: 0px;
left: 0px;
height: 100%;
max-width: 100%;
background-color: var(--text-color);
opacity: 0.3;
pointer-events: none;
transition: width 0.3s ease;
}
.overlay {
position: absolute;
top: 0px;
left: 0px;
height: 100%;
max-width: 100%;
background-color: var(--text-color);
opacity: 0.3;
pointer-events: none;
transition: width 0.3s ease;
}
.is-down > .overlay {
transition: none !important;
}
.is-down > .overlay {
transition: none !important;
}
</style>

View File

@@ -1,215 +0,0 @@
<!--
@component
@deprecated use Float.svelte
-->
<script lang="ts">
interface Props {
value?: number;
step?: number;
min?: number | undefined;
max?: number | undefined;
id?: string;
change?: (arg: number) => void;
}
let {
value = $bindable(0),
step = 1,
min = $bindable(0),
max = $bindable(1),
id,
change
}: Props = $props();
if (min > max) {
[min, max] = [max, min];
}
if (value > max) {
max = value;
}
function strip(input: number) {
return +parseFloat(input + '').toPrecision(2);
}
let inputEl = $state() as HTMLInputElement;
let wrapper = $state() as HTMLDivElement;
let prev = -1;
function update() {
if (prev === value) return;
prev = value;
change?.(value);
}
function handleChange(change: number) {
value = Math.max(min ?? -Infinity, Math.min(+value + change, max ?? Infinity));
}
let isMouseDown = $state(false);
let downX = 0;
let downV = 0;
let rect: DOMRect;
function handleMouseDown(ev: MouseEvent) {
ev.preventDefault();
downV = value;
downX = ev.clientX;
rect = wrapper.getBoundingClientRect();
window.removeEventListener('mousemove', handleMouseMove);
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
document.body.style.cursor = 'ew-resize';
}
function handleMouseUp() {
if (downV === value) {
inputEl.focus();
} else {
inputEl.blur();
}
document.body.style.cursor = 'unset';
window.removeEventListener('mouseup', handleMouseUp);
window.removeEventListener('mousemove', handleMouseMove);
}
function handleKeyDown(ev: KeyboardEvent) {
if (ev.key === 'Escape' || ev.key === 'Enter') {
handleMouseUp();
inputEl?.blur();
}
}
function handleMouseMove(ev: MouseEvent) {
if (!ev.ctrlKey && typeof min === 'number' && typeof max === 'number') {
const vx = (ev.clientX - rect.left) / rect.width;
value = Math.max(Math.min(Math.round(min + (max - min) * vx), max), min);
} else {
const vx = ev.clientX - downX;
value = downV + Math.round(vx / 10);
}
}
$effect(() => {
if ((value || 0).toString().length > 5) {
value = strip(value || 0);
}
value !== undefined && update();
});
let width = $derived(
Number.isFinite(value) ? Math.max((value?.toString().length ?? 1) * 8, 30) + 'px' : '20px'
);
</script>
<div
class="component-wrapper"
bind:this={wrapper}
class:is-down={isMouseDown}
role="slider"
tabindex="0"
aria-valuenow={value}
onkeydown={handleKeyDown}
onmousedown={handleMouseDown}
onmouseup={handleMouseUp}
>
<button onclick={() => handleChange(-step)}>-</button>
<input
bind:value
bind:this={inputEl}
{id}
{step}
{max}
{min}
type="number"
style={`width:${width};`}
/>
<button onclick={() => handleChange(+step)}>+</button>
{#if typeof min !== 'undefined' && typeof max !== 'undefined'}
<span
class="overlay"
style={`width: ${Math.min((value - min) / (max - min), 1) * 100}%`}
></span>
{/if}
</div>
<style>
.component-wrapper {
position: relative;
display: flex;
background-color: var(--layer-2, #4b4b4b);
border-radius: 2px;
user-select: none;
transition: box-shadow 0.3s ease;
outline: solid 1px var(--outline);
overflow: hidden;
border-radius: var(--border-radius, 2px);
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
input[type="number"] {
-webkit-appearance: textfield;
-moz-appearance: textfield;
appearance: textfield;
cursor: pointer;
font-family: var(--font-family);
font-variant-numeric: tabular-nums;
color: var(--text-color);
background-color: transparent;
padding: var(--padding, 6px);
font-size: 1em;
padding-inline: 10px;
text-align: center;
border: none;
border-style: none;
flex: 1;
width: 72%;
}
.is-down > input {
cursor: ew-resize !important;
}
.overlay {
position: absolute;
top: 0px;
left: 0px;
height: 100%;
background-color: var(--layer-3);
opacity: 0.3;
pointer-events: none;
}
.is-down > .overlay {
transition: none !important;
}
button {
background-color: transparent;
border: none;
cursor: pointer;
line-height: 0px;
margin: 0;
color: var(--text-color);
margin-inline: 6px;
}
div input[type="number"] {
color: var(--text-color);
background-color: transparent;
padding: var(--padding, 6px);
padding-inline: 0px;
text-align: center;
border: none;
border-style: none;
}
</style>

View File

@@ -0,0 +1 @@

View File

@@ -1,27 +1,27 @@
<script lang="ts">
interface Props {
options?: string[];
value?: number;
id?: string;
}
interface Props {
options?: string[];
value?: number;
id?: string;
}
let { options = [], value = $bindable(0), id = '' }: Props = $props();
let { options = [], value = $bindable(0), id = '' }: Props = $props();
</script>
<select {id} bind:value>
{#each options as label, i}
<option value={i}>{label}</option>
{/each}
{#each options as label, i (label)}
<option value={i}>{label}</option>
{/each}
</select>
<style>
select {
background: var(--layer-2);
color: var(--text-color);
font-family: var(--font-family);
outline: solid 1px var(--outline);
padding: 0.8em 1em;
border-radius: 5px;
border: none;
}
select {
background: var(--layer-2);
color: var(--text-color);
font-family: var(--font-family);
outline: solid 1px var(--outline);
padding: 0.8em 1em;
border-radius: 5px;
border: none;
}
</style>

View File

@@ -1,34 +1,34 @@
<script lang="ts">
import { Number } from '$lib/index.js';
import Float from './Float.svelte';
interface Props {
value?: any;
id?: string;
}
interface Props {
value?: number[];
id?: string;
}
let { value = $bindable([0, 0, 0]), id = '' }: Props = $props();
let { value = $bindable([0, 0, 0]), id = '' }: Props = $props();
</script>
<div>
<Number id={`${id}-x`} bind:value={value[0]} step={0.01} />
<Number id={`${id}-y`} bind:value={value[1]} step={0.01} />
<Number id={`${id}-z`} bind:value={value[2]} step={0.01} />
<Float id={`${id}-x`} bind:value={value[0]} step={0.01} />
<Float id={`${id}-y`} bind:value={value[1]} step={0.01} />
<Float id={`${id}-z`} bind:value={value[2]} step={0.01} />
</div>
<style>
div > :global(.component-wrapper:nth-child(1)) {
border-radius: 4px 4px 0px 0px !important;
border-bottom: none !important;
}
div > :global(.component-wrapper:nth-child(2)) {
border-radius: 0px !important;
outline: none;
border: solid thin var(--outline);
border-top: solid thin color-mix(in srgb, var(--outline) 50%, transparent);
border-bottom: solid thin color-mix(in srgb, var(--outline) 50%, transparent);
}
div > :global(.component-wrapper:nth-child(3)) {
border-top: none !important;
border-radius: 0px 0px 4px 4px !important;
}
div > :global(.component-wrapper:nth-child(1)) {
border-radius: 4px 4px 0px 0px !important;
border-bottom: none !important;
}
div > :global(.component-wrapper:nth-child(2)) {
border-radius: 0px !important;
outline: none;
border: solid thin var(--outline);
border-top: solid thin color-mix(in srgb, var(--outline) 50%, transparent);
border-bottom: solid thin color-mix(in srgb, var(--outline) 50%, transparent);
}
div > :global(.component-wrapper:nth-child(3)) {
border-top: none !important;
border-radius: 0px 0px 4px 4px !important;
}
</style>

View File

@@ -1,79 +1,86 @@
<script lang="ts">
import '$lib/app.css';
import { Checkbox, Details, Number, Select, ShortCut, Vec3 } from '$lib/index.js';
import Section from './Section.svelte';
import '$lib/app.css';
import { Checkbox, Details, Float, Select, ShortCut, Vec3 } from '$lib/index.js';
import Section from './Section.svelte';
let intValue = $state(0);
let floatValue = $state(0.2);
let float2Value = $state(0.02);
let float3Value = $state(1);
let vecValue = $state([0.2, 0.3, 0.4]);
const options = ['strawberry', 'raspberry', 'chickpeas'];
let selectValue = $state(0);
const d = $derived(options[selectValue]);
let intValue = $state(0);
let floatValue = $state(0.2);
let float2Value = $state(0.02);
let float3Value = $state(1);
let vecValue = $state([0.2, 0.3, 0.4]);
const options = ['strawberry', 'raspberry', 'chickpeas'];
let selectValue = $state(0);
const d = $derived(options[selectValue]);
let checked = $state(false);
let detailsOpen = $state(false);
let checked = $state(false);
let detailsOpen = $state(false);
const themes = ['light', 'solarized', 'catppuccin', 'high-contrast', 'nord', 'dracula'];
let themeIndex = $state(0);
$effect(() => {
const classList = document.documentElement.classList;
for (const c of classList) {
if (c.startsWith('theme-')) document.documentElement.classList.remove(c);
}
document.documentElement.classList.add(`theme-${themes[themeIndex]}`);
});
const themes = [
'light',
'solarized',
'catppuccin',
'high-contrast',
'nord',
'dracula'
];
let themeIndex = $state(0);
$effect(() => {
const classList = document.documentElement.classList;
for (const c of classList) {
if (c.startsWith('theme-')) document.documentElement.classList.remove(c);
}
document.documentElement.classList.add(`theme-${themes[themeIndex]}`);
});
</script>
<main class="flex flex-col gap-8 py-8">
<div class="flex gap-4">
<h1 class="text-4xl">@nodarium/ui</h1>
<Select bind:value={themeIndex} options={themes}></Select>
</div>
<div class="flex gap-4">
<h1 class="text-4xl">@nodarium/ui</h1>
<Select bind:value={themeIndex} options={themes}></Select>
</div>
<Section title="Integer (step inherit)" value={intValue}>
<Number bind:value={intValue} max={2} />
</Section>
<Section title="Integer (step inherit)" value={intValue}>
<Float bind:value={intValue} max={2} />
</Section>
<Section title="Float (step inherit)" value={floatValue}>
<Number bind:value={floatValue} />
</Section>
<Section title="Float (step inherit)" value={floatValue}>
<Float bind:value={floatValue} />
</Section>
<Section title="Float 2 (step inherit)" value={intValue}>
<Number bind:value={float2Value} />
</Section>
<Section title="Float 2 (step inherit)" value={intValue}>
<Float bind:value={float2Value} />
</Section>
<Section title="Float (0.01 step)" value={floatValue}>
<Number bind:value={float3Value} step={0.01} max={3} />
</Section>
<Section title="Float (0.01 step)" value={floatValue}>
<Float bind:value={float3Value} step={0.01} max={3} />
</Section>
<Section title="Vec3" value={JSON.stringify(vecValue)}>
<Vec3 bind:value={vecValue} />
</Section>
<Section title="Vec3" value={JSON.stringify(vecValue)}>
<Vec3 bind:value={vecValue} />
</Section>
<Section title="Select" value={d}>
<Select bind:value={selectValue} {options} />
</Section>
<Section title="Select" value={d}>
<Select bind:value={selectValue} {options} />
</Section>
<Section title="Checkbox" value={checked}>
<Checkbox bind:value={checked} />
</Section>
<Section title="Checkbox" value={checked}>
<Checkbox bind:value={checked} />
</Section>
<Section title="Details" value={detailsOpen}>
<Details title="More Information" bind:open={detailsOpen}>
<p>Here is some more information that was previously hidden.</p>
</Details>
</Section>
<Section title="Details" value={detailsOpen}>
<Details title="More Information" bind:open={detailsOpen}>
<p>Here is some more information that was previously hidden.</p>
</Details>
</Section>
<Section title="Shortcut">
<ShortCut ctrl key="S" />
</Section>
<Section title="Shortcut">
<ShortCut ctrl key="S" />
</Section>
</main>
<style>
main {
max-width: 800px;
margin: 0 auto;
}
main {
max-width: 800px;
margin: 0 auto;
}
</style>

View File

@@ -1,18 +1,18 @@
<script lang="ts">
import { type Snippet } from 'svelte';
let { title, value, children } = $props<{
title?: string;
value?: unknown;
children?: Snippet;
}>();
import { type Snippet } from 'svelte';
let { title, value, children } = $props<{
title?: string;
value?: unknown;
children?: Snippet;
}>();
</script>
<section class="border border-1/2 mb-4 p-4 flex flex-col gap-4">
<h3 class="flex gap-2 font-bold">
{title}
<p class="font-normal! opacity-50!">{value}</p>
</h3>
<div>
{@render children()}
</div>
<h3 class="flex gap-2 font-bold">
{title}
<p class="font-normal! opacity-50!">{value}</p>
</h3>
<div>
{@render children()}
</div>
</section>