mirror of
https://github.com/Ku6epXBOCTuK/easy-png-tools.git
synced 2026-11-13 17:08:20 +00:00
fix: update range slider field component
This commit is contained in:
@@ -9,8 +9,6 @@
|
||||
Порядок согласован: C (контролы полей) → B (загрузка исходника) → E (download) →
|
||||
D (pipeline). Делать по одной, сверху вниз.
|
||||
|
||||
- [ ] **C1. range slider field** — добавить поле для ввода цифр и кнопку сброса
|
||||
значения
|
||||
- [ ] **C2. keep Aspect field** — пересчитывать второе поле, учитывать какое
|
||||
было изменено
|
||||
- [ ] **C3. пресеты размеров** — split-into-parts-png, resize (может еще
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { FieldSpec, NumberSpec, SliderSpec } from "$lib/registry-schema";
|
||||
import { t } from "$lib/i18n/t";
|
||||
import { Minus, Plus, RotateCcw } from "@lucide/svelte";
|
||||
import IconButton from "$lib/components/ui/IconButton.svelte";
|
||||
import Control from "./Control.svelte";
|
||||
|
||||
interface Props {
|
||||
@@ -11,33 +14,97 @@
|
||||
let { label, value, spec, onchange }: Props = $props();
|
||||
|
||||
const sp = $derived(spec as NumberSpec | SliderSpec);
|
||||
const min = $derived(sp.min ?? 0);
|
||||
const max = $derived(sp.max ?? 100);
|
||||
const step = $derived(sp.step ?? 1);
|
||||
const current = $derived(
|
||||
typeof value === "number" && Number.isFinite(value) ? value : sp.default,
|
||||
);
|
||||
const atDefault = $derived(current === sp.default);
|
||||
const atMin = $derived(current <= min);
|
||||
const atMax = $derived(current >= max);
|
||||
|
||||
function handle(e: Event) {
|
||||
onchange?.(Number((e.target as HTMLInputElement).value));
|
||||
const n = (e.target as HTMLInputElement).valueAsNumber;
|
||||
if (Number.isFinite(n)) onchange?.(n);
|
||||
}
|
||||
|
||||
function stepBy(dir: 1 | -1) {
|
||||
onchange?.(Math.min(max, Math.max(min, current + dir * step)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<Control element="label" {label}>
|
||||
<Control {label}>
|
||||
{#snippet trailing()}
|
||||
<output>{current}</output>
|
||||
<span class="range-trailing">
|
||||
<IconButton
|
||||
icon={Minus}
|
||||
label={t("ui.decrease")}
|
||||
variant="clear"
|
||||
size="s"
|
||||
disabled={atMin}
|
||||
onclick={() => stepBy(-1)}
|
||||
/>
|
||||
<input
|
||||
class="range-number"
|
||||
aria-label={label}
|
||||
type="number"
|
||||
{min}
|
||||
{max}
|
||||
{step}
|
||||
value={current}
|
||||
oninput={handle}
|
||||
/>
|
||||
<IconButton
|
||||
icon={Plus}
|
||||
label={t("ui.increase")}
|
||||
variant="clear"
|
||||
size="s"
|
||||
disabled={atMax}
|
||||
onclick={() => stepBy(1)}
|
||||
/>
|
||||
<IconButton
|
||||
icon={RotateCcw}
|
||||
label={t("ui.reset")}
|
||||
variant="clear"
|
||||
size="s"
|
||||
disabled={atDefault}
|
||||
onclick={() => onchange?.(sp.default)}
|
||||
/>
|
||||
</span>
|
||||
{/snippet}
|
||||
<input
|
||||
aria-label={label}
|
||||
type="range"
|
||||
min={sp.min ?? 0}
|
||||
max={sp.max ?? 100}
|
||||
step={sp.step ?? 1}
|
||||
{min}
|
||||
{max}
|
||||
{step}
|
||||
value={current}
|
||||
oninput={handle}
|
||||
/>
|
||||
</Control>
|
||||
|
||||
<style>
|
||||
output {
|
||||
.range-trailing {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-s);
|
||||
}
|
||||
.range-number {
|
||||
width: calc(var(--space-xxxl) * 3);
|
||||
padding: var(--space-m) var(--space-l);
|
||||
background: var(--color-background);
|
||||
border: var(--size-border) solid var(--color-border);
|
||||
border-radius: var(--radius-s);
|
||||
color: var(--color-text);
|
||||
font: var(--font-size-m) var(--font-mono);
|
||||
text-align: center;
|
||||
appearance: textfield;
|
||||
}
|
||||
.range-number::-webkit-outer-spin-button,
|
||||
.range-number::-webkit-inner-spin-button {
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
input[type="range"] {
|
||||
width: 100%;
|
||||
|
||||
Reference in New Issue
Block a user