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) →
|
Порядок согласован: C (контролы полей) → B (загрузка исходника) → E (download) →
|
||||||
D (pipeline). Делать по одной, сверху вниз.
|
D (pipeline). Делать по одной, сверху вниз.
|
||||||
|
|
||||||
- [ ] **C1. range slider field** — добавить поле для ввода цифр и кнопку сброса
|
|
||||||
значения
|
|
||||||
- [ ] **C2. keep Aspect field** — пересчитывать второе поле, учитывать какое
|
- [ ] **C2. keep Aspect field** — пересчитывать второе поле, учитывать какое
|
||||||
было изменено
|
было изменено
|
||||||
- [ ] **C3. пресеты размеров** — split-into-parts-png, resize (может еще
|
- [ ] **C3. пресеты размеров** — split-into-parts-png, resize (может еще
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { FieldSpec, NumberSpec, SliderSpec } from "$lib/registry-schema";
|
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";
|
import Control from "./Control.svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -11,33 +14,97 @@
|
|||||||
let { label, value, spec, onchange }: Props = $props();
|
let { label, value, spec, onchange }: Props = $props();
|
||||||
|
|
||||||
const sp = $derived(spec as NumberSpec | SliderSpec);
|
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(
|
const current = $derived(
|
||||||
typeof value === "number" && Number.isFinite(value) ? value : sp.default,
|
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) {
|
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>
|
</script>
|
||||||
|
|
||||||
<Control element="label" {label}>
|
<Control {label}>
|
||||||
{#snippet trailing()}
|
{#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}
|
{/snippet}
|
||||||
<input
|
<input
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
type="range"
|
type="range"
|
||||||
min={sp.min ?? 0}
|
{min}
|
||||||
max={sp.max ?? 100}
|
{max}
|
||||||
step={sp.step ?? 1}
|
{step}
|
||||||
value={current}
|
value={current}
|
||||||
oninput={handle}
|
oninput={handle}
|
||||||
/>
|
/>
|
||||||
</Control>
|
</Control>
|
||||||
|
|
||||||
<style>
|
<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);
|
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"] {
|
input[type="range"] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
Reference in New Issue
Block a user