chore: setup linting
This commit is contained in:
14
packages/ui/src/app.d.ts
vendored
14
packages/ui/src/app.d.ts
vendored
@@ -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 {};
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user