From 481a7550cfaa773bd6a237c65f176d7783356790 Mon Sep 17 00:00:00 2001 From: Jage9 Date: Sun, 22 Feb 2026 16:37:42 -0500 Subject: [PATCH] Polish numeric step feedback and boundary handling --- client/public/version.js | 2 +- client/src/main.ts | 38 ++++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/client/public/version.js b/client/public/version.js index 31e2a2c..6d0d476 100644 --- a/client/public/version.js +++ b/client/public/version.js @@ -1,5 +1,5 @@ // Maintainer-controlled web client version. // Format: YYYY.MM.DD Rn (example: 2026.02.20 R2) -window.CHGRID_WEB_VERSION = "2026.02.22 R152"; +window.CHGRID_WEB_VERSION = "2026.02.22 R153"; // Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid. window.CHGRID_TIME_ZONE = "America/Detroit"; diff --git a/client/src/main.ts b/client/src/main.ts index 672ad48..8a2cbf8 100644 --- a/client/src/main.ts +++ b/client/src/main.ts @@ -900,7 +900,13 @@ function snapNumberToStep(value: number, step: number, anchor = 0): number { function formatSteppedNumber(value: number, step: number): string { const decimals = step >= 1 ? 0 : Math.min(6, Math.ceil(Math.abs(Math.log10(step))) + 1); - return value.toFixed(decimals); + if (decimals <= 0) { + return String(Math.round(value)); + } + return value + .toFixed(decimals) + .replace(/(\.\d*?[1-9])0+$/u, '$1') + .replace(/\.0+$/u, ''); } function squareWord(distance: number): string { @@ -1105,7 +1111,7 @@ async function calibrateMicInputGain(): Promise { const roundedGain = clampMicInputGain(snapNumberToStep(calibratedGain, MIC_INPUT_GAIN_STEP, MIC_CALIBRATION_MIN_GAIN)); const appliedGain = audio.setOutboundInputGain(roundedGain); persistMicInputGain(appliedGain); - updateStatus(`Mic calibration set to ${appliedGain.toFixed(2)}x.`); + updateStatus(`Mic calibration set to ${formatSteppedNumber(appliedGain, MIC_INPUT_GAIN_STEP)}x.`); audio.sfxUiConfirm(); } @@ -1533,7 +1539,7 @@ function handleNormalModeInput(code: string, shiftKey: boolean): void { return; } state.mode = 'micGainEdit'; - state.nicknameInput = audio.getOutboundInputGain().toFixed(2); + state.nicknameInput = formatSteppedNumber(audio.getOutboundInputGain(), MIC_INPUT_GAIN_STEP); state.cursorPos = state.nicknameInput.length; replaceTextOnNextType = true; updateStatus(`Set volume: ${state.nicknameInput}`); @@ -1867,14 +1873,17 @@ function handleMicGainEditModeInput(code: string, key: string, ctrlKey: boolean) const raw = Number(state.nicknameInput.trim()); const base = Number.isFinite(raw) ? raw : audio.getOutboundInputGain(); const delta = code === 'ArrowUp' ? MIC_INPUT_GAIN_STEP : -MIC_INPUT_GAIN_STEP; - const next = clampMicInputGain( - snapNumberToStep(base + delta, MIC_INPUT_GAIN_STEP, MIC_CALIBRATION_MIN_GAIN), - ); + const attempted = snapNumberToStep(base + delta, MIC_INPUT_GAIN_STEP, MIC_CALIBRATION_MIN_GAIN); + const next = clampMicInputGain(attempted); state.nicknameInput = formatSteppedNumber(next, MIC_INPUT_GAIN_STEP); state.cursorPos = state.nicknameInput.length; replaceTextOnNextType = false; - updateStatus(`Set volume: ${state.nicknameInput}`); - audio.sfxUiBlip(); + updateStatus(state.nicknameInput); + if (Math.abs(next - base) < 1e-9 || Math.abs(next - attempted) > 1e-9) { + audio.sfxUiCancel(); + } else { + audio.sfxUiBlip(); + } return; } @@ -1895,7 +1904,7 @@ function handleMicGainEditModeInput(code: string, key: string, ctrlKey: boolean) persistMicInputGain(applied); state.mode = 'normal'; replaceTextOnNextType = false; - updateStatus(`Volume set to ${applied.toFixed(2)}.`); + updateStatus(`Volume set to ${formatSteppedNumber(applied, MIC_INPUT_GAIN_STEP)}.`); audio.sfxUiConfirm(); return; } @@ -2337,14 +2346,19 @@ function handleItemPropertyEditModeInput(code: string, key: string, ctrlKey: boo : 0; const delta = code === 'ArrowUp' ? step : -step; const anchor = Number.isFinite(min) ? min : 0; - let nextValue = snapNumberToStep(currentValue + delta, step, anchor); + const attempted = snapNumberToStep(currentValue + delta, step, anchor); + let nextValue = attempted; if (Number.isFinite(min)) nextValue = Math.max(min, nextValue); if (Number.isFinite(max)) nextValue = Math.min(max, nextValue); state.nicknameInput = formatSteppedNumber(nextValue, step); state.cursorPos = state.nicknameInput.length; replaceTextOnNextType = false; - updateStatus(`Edit ${itemPropertyLabel(propertyKey)}: ${state.nicknameInput}`); - audio.sfxUiBlip(); + updateStatus(state.nicknameInput); + if (Math.abs(nextValue - currentValue) < 1e-9 || Math.abs(nextValue - attempted) > 1e-9) { + audio.sfxUiCancel(); + } else { + audio.sfxUiBlip(); + } return; } }