feat: implement settings

This commit is contained in:
2024-04-18 18:39:24 +02:00
parent e7f43020dc
commit 36faeae886
39 changed files with 1398 additions and 196 deletions

View File

@ -12,11 +12,11 @@
</script>
{#if input.type === "float"}
<Float {id} bind:value />
<Float {id} bind:value min={input?.min} max={input?.max} />
{:else if input.type === "integer"}
<Integer {id} bind:value />
<Integer {id} bind:value min={input?.min} max={input?.max} />
{:else if input.type === "boolean"}
<Checkbox {id} bind:value />
{:else if input.type === "select"}
<Select {id} bind:value labels={input.labels} />
<Select {id} bind:value options={input.options} />
{/if}

View File

@ -49,6 +49,8 @@ body {
--background-color-darker: #101010;
--text-color: #aeaeae;
color: var(--text-color);
background-color: var(--background-color-darker);
}

View File

@ -1,60 +1,13 @@
<script lang="ts">
export let value: boolean;
$: if (typeof value === "string") {
value = value === "true";
} else if (typeof value === "number") {
value = value === 1;
}
export let id: string;
</script>
<input {id} type="checkbox" bind:checked={value} />
<style>
input[type="checkbox"] {
/* Add if not using autoprefixer */
-webkit-appearance: none;
/* Remove most all native input styles */
appearance: none;
/* For iOS < 15 */
background-color: var(--form-background);
/* Not removed via appearance */
margin: 0;
font: inherit;
color: currentColor;
width: 1.15em;
height: 1.15em;
border: 0.15em solid currentColor;
border-radius: 0.15em;
transform: translateY(-0.075em);
display: grid;
place-content: center;
}
input[type="checkbox"]::before {
content: "";
width: 0.65em;
height: 0.65em;
clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
transform: scale(0);
transform-origin: bottom left;
transition: 120ms transform ease-in-out;
box-shadow: inset 1em 1em var(--form-control-color);
/* Windows High Contrast Mode */
background-color: CanvasText;
}
input[type="checkbox"]:checked::before {
transform: scale(1);
}
input[type="checkbox"]:focus {
outline: max(2px, 0.15em) solid currentColor;
outline-offset: max(2px, 0.15em);
}
input[type="checkbox"]:disabled {
--form-control-color: var(--form-control-disabled);
color: var(--form-control-disabled);
cursor: not-allowed;
}
</style>

View File

@ -1,20 +1,169 @@
<svelte:options accessors />
<script lang="ts">
export let value: number = 0;
export let min = 0;
export let max = 10;
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
// Styling
export let min: number | undefined = undefined;
export let max: number | undefined = undefined;
export let step = 1;
export let id: string;
export let value = 0;
if (!value) {
value = 0;
}
let inputEl: HTMLInputElement;
let wrapper: HTMLDivElement;
$: value !== undefined && update();
let prev = -1;
function update() {
if (prev === value) return;
prev = value;
dispatch("change", parseFloat(value + ""));
}
$: width = Number.isFinite(value)
? Math.max((value?.toString().length ?? 1) * 8, 30) + "px"
: "20px";
function handleChange(change: number) {
value = Math.max(
min ?? -Infinity,
Math.min(+value + change, max ?? Infinity),
);
}
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 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.floor(min + (max - min) * vx), max), min);
} else {
const vx = ev.clientX - downX;
value = downV + Math.floor(vx / 10);
}
}
</script>
<input {id} type="number" bind:value {min} {max} {step} />
<div
class="component-wrapper"
bind:this={wrapper}
role="slider"
tabindex="0"
aria-valuenow={value}
on:mousedown={handleMouseDown}
on:mouseup={handleMouseUp}
>
{#if typeof min !== "undefined" && typeof max !== "undefined"}
<span
class="overlay"
style={`width: ${Math.min((value - min) / (max - min), 1) * 100}%`}
/>
{/if}
<button on:click={() => handleChange(-step)}>-</button>
<input
bind:value
bind:this={inputEl}
{step}
{max}
{min}
type="number"
style={`width:${width};`}
/>
<button on:click={() => handleChange(+step)}>+</button>
</div>
<style>
input {
background: var(--background-color-lighter);
color: var(--text-color);
.component-wrapper {
position: relative;
display: flex;
background-color: var(--background-color-lighter, #4b4b4b);
border-radius: 2px;
user-select: none;
transition: box-shadow 0.3s ease;
box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.2);
outline: none !important;
overflow: hidden;
border-radius: var(--border-radius, 2px);
}
input[type="number"] {
-webkit-appearance: textfield;
-moz-appearance: textfield;
appearance: textfield;
cursor: pointer;
font-size: 1em;
font-family: var(--font-family);
padding: 0.8em 1em;
border-radius: 5px;
padding-top: 8px;
flex: 1;
width: 72%;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
.overlay {
position: absolute;
top: 0px;
left: 0px;
height: 100%;
background-color: var(--text-color);
opacity: 0.3;
pointer-events: none;
}
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

@ -1,11 +1,11 @@
<script lang="ts">
export let labels: string[] = [];
export let options: string[] = [];
export let value: number = 0;
export let id: string;
</script>
<select {id} bind:value>
{#each labels as label, i}
{#each options as label, i}
<option value={i}>{label}</option>
{/each}
</select>