<script lang="ts">
// A directory's size cap, chosen on a slider.
//
// It used to be four or five buttons, which meant the cap could only ever be
// one of four or five numbers — 64 GB or 128 GB and nothing between. The
// steps are a ladder rather than a linear range because the useful sizes
// span three orders of magnitude, and a linear slider over that spends its
// whole travel at the top end.
import { human } from "../../stores/host.svelte.js";
import { sizeLadder, nearestStep } from "../../utils/size-ladder.js";
let {
value,
min,
max,
onchange,
}: {
/** The current cap, in bytes. */
value: number;
/** The smallest the daemon will accept. */
min: number;
/** The largest worth offering. */
max: number;
onchange: (bytes: number) => void;
} = $props();
const ladder = $derived(sizeLadder(min, max));
const index = $derived(nearestStep(ladder, value));
function move(event: Event) {
const next = ladder[Number((event.target as HTMLInputElement).value)];
if (next !== undefined) onchange(next);
}
</script>
<div class="size-field">
<div class="size-slider">
<input
type="range"
min="0"
max={ladder.length - 1}
step="1"
value={index}
oninput={move}
aria-label="maximum size"
aria-valuetext={human(ladder[index] ?? value)}
/>
<output class="size-value">{human(ladder[index] ?? value)}</output>
</div>
<div class="size-ends">
<span>{human(min)}</span>
<span>{human(max)}</span>
</div>
</div>
<style>
/* One root element: this sits inside a flex row beside its label, and two
roots would put the end labels next to the slider instead of under it. */
.size-field {
display: flex;
flex-direction: column;
gap: var(--wb-spacing-2);
flex: 1;
min-width: 0;
}
.size-slider {
display: flex;
align-items: center;
gap: var(--wb-spacing-10);
flex: 1;
min-width: 0;
}
input[type="range"] {
flex: 1;
min-width: 0;
accent-color: var(--vscode-button-background, #0e639c);
}
.size-value {
/* Fixed width and tabular figures: the number changes as the handle
moves, and a value that reflows the row under the cursor is a value
that is hard to land on. */
min-width: var(--wb-control-size-68);
text-align: right;
font-variant-numeric: tabular-nums;
font-weight: 600;
}
.size-ends {
display: flex;
justify-content: space-between;
/* Aligned to the track, not the row: the value readout sits to the right
of the slider and the end labels belong under the slider itself. */
margin-right: var(--wb-spacing-78);
opacity: 0.55;
font-size: 0.9em;
}
</style>