Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 20 additions & 65 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import {
import { useDeferredValue, useMemo } from "react";
import { useMassStorage, Bar, Max, Plate } from "./plate-db";
import MassConfig from "./MassConfig";
import { useAutoRepeat } from "./useAutoRepeat";
import { useWeightSet } from "./useWeightSet";
import { numbdfined } from "./utils";
import { NumberInput } from "./NumberInput";
import { HiddenDeleteFieldset } from "./HiddenDeleteFieldset";
import BarView from "./BarView";
import { Link, Route, Routes } from "react-router";
Expand Down Expand Up @@ -139,19 +139,6 @@ function BarComputer({
const weightSet = useWeightSet();
const inWeightSet = target != null && weightSet.weights.includes(target);

const nudgeDown = useAutoRepeat(() => {
const nudge = activeBar?.sliderMinStep;
if (nudge == null) return;
const prev = Math.ceil((target ?? 0) / nudge) * nudge - nudge;
if (weightMin != null && prev >= weightMin) dispatchState({ target: prev });
});
const nudgeUp = useAutoRepeat(() => {
const nudge = activeBar?.sliderMinStep;
if (nudge == null) return;
const next = Math.floor((target ?? 0) / nudge) * nudge + nudge;
if (weightMax != null && next <= weightMax) dispatchState({ target: next });
});

return (
<>
<select
Expand Down Expand Up @@ -204,48 +191,20 @@ function BarComputer({
))}
</datalist>
<div style={{ display: "flex", gap: "0.5rem", alignItems: "start" }}>
<fieldset role="group" style={{ flex: 1 }}>
{activeBar?.sliderMinStep != null && (
<>
<button
type="button"
className="secondary"
disabled={activeBar?.sliderMinStep == null}
style={{ width: "auto", paddingInline: "0.5rem" }}
{...nudgeDown}
>
-{activeBar.sliderMinStep}
</button>
</>
)}
<input
id="target-number"
type="number"
placeholder="work weight"
value={target ?? ""}
min={weightMin}
max={weightMax}
step={weightStep}
onFocus={clear}
onKeyDown={onEnterBlur}
onBlur={scrollToTop}
onChange={(e) =>
dispatchState({ target: numbdfined(e.target.value) })
}
aria-invalid={!validTarget}
/>
{activeBar?.sliderMinStep != null && (
<button
type="button"
className="secondary"
disabled={activeBar?.sliderMinStep == null}
style={{ width: "auto", paddingInline: "0.5rem" }}
{...nudgeUp}
>
{activeBar.sliderMinStep}+
</button>
)}
</fieldset>
<NumberInput
value={target}
onChange={(v) => dispatchState({ target: v })}
step={activeBar?.sliderMinStep}
min={weightMin}
max={weightMax}
style={{ flex: 1 }}
id="target-number"
placeholder="work weight"
onFocus={clear}
onKeyDown={onEnterBlur}
onBlur={scrollToTop}
aria-invalid={!validTarget}
/>
{target != null && (
<button
type="button"
Expand Down Expand Up @@ -447,15 +406,11 @@ function MaxEditor({
defaultValue={max.label ?? ""}
onChange={(e) => putMax?.({ ...max, label: e.target.value })}
/>
<input
defaultValue={max.weight ?? ""}
type="number"
onChange={(e) =>
putMax?.({
...max,
weight: numbdfined(e.target.value) ?? null,
})
}
<NumberInput
value={max.weight}
onChange={(v) => putMax?.({ ...max, weight: v ?? null })}
step={5}
min={0}
/>
</HiddenDeleteFieldset>
);
Expand Down
70 changes: 70 additions & 0 deletions src/NumberInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useAutoRepeat } from "./useAutoRepeat";
import { numbdfined } from "./utils";

export function NumberInput({
value,
onChange,
step,
min,
max,
style,
...inputProps
}: {
value: number | null | undefined;
onChange: (value: number | undefined) => void;
step?: number;
min?: number;
max?: number;
style?: React.CSSProperties;
} & Omit<
React.InputHTMLAttributes<HTMLInputElement>,
"value" | "onChange" | "type" | "step" | "min" | "max" | "style"
>) {
const nudgeDown = useAutoRepeat(() => {
if (step == null) return;
const prev = Math.ceil((value ?? 0) / step) * step - step;
if (min != null && prev < min) return;
onChange(prev);
});

const nudgeUp = useAutoRepeat(() => {
if (step == null) return;
const next = Math.floor((value ?? 0) / step) * step + step;
if (max != null && next > max) return;
onChange(next);
});

return (
<fieldset role="group" style={style}>
{step != null && (
<button
type="button"
className="secondary"
style={{ width: "auto", paddingInline: "0.5rem" }}
{...nudgeDown}
>
-{step}
</button>
)}
<input
type="number"
value={value ?? ""}
min={min}
max={max}
step={step}
onChange={(e) => onChange(numbdfined(e.target.value))}
{...inputProps}
/>
{step != null && (
<button
type="button"
className="secondary"
style={{ width: "auto", paddingInline: "0.5rem" }}
{...nudgeUp}
>
{step}+
</button>
)}
</fieldset>
);
}