fix(ui): F8-06 calculator polish — always 3-decimal display, mono font, input cap
Owner feedback round 2 on PR #61: - Pad every read-only calculator value to three decimals: tech labels, derived results (mass, speed, attack, defence, bombing, cargo capacity), planet MAT, planet build-rate, modernization cost, and the full-cargo capacity label all read as "1.000" instead of "1", matching the goal-seek back-solved input and the report. Drops thousands grouping so the same `fmt()` string also embeds cleanly in the read-only `<input type="number">` cell. - Switch label and input styling onto the existing `--font-mono` token (right-aligned, tabular-nums) so columns line up vertically across rows like a financial table. - Refuse a fourth decimal as the user types in every calculator number input (DWSC blocks, tech, MAT, custom load, lock value, modernization target tech): the `oninput` truncates the input text past three decimal digits and explicitly writes the truncated value back through `bind:value`, so Svelte's later reactive flush cannot undo the cap. - Doc + tests follow the rule (five new vitest cases covering the 3-decimal label format, the input cap on each input class, and the integer-padding rule for derived results).
This commit is contained in:
@@ -139,6 +139,20 @@ calculator math — so the ship-group upgrade flow can reuse it later.
|
||||
const floor = techFloor[key];
|
||||
techs[key] = next < floor ? floor : next;
|
||||
}
|
||||
// Refuse a fourth decimal as typing happens: keeps the calculator
|
||||
// from ever displaying a >3-decimal fraction the user could not
|
||||
// have intended (the calculator math is `Ceil3`-rounded for display
|
||||
// anyway). Pairs with `bind:value` — `apply` overwrites the bound
|
||||
// state when Svelte's own bind handler has already read the
|
||||
// over-precise number.
|
||||
function capDecimals(event: Event, apply: (next: number) => void): void {
|
||||
const el = event.currentTarget as HTMLInputElement;
|
||||
const txt = el.value;
|
||||
const dot = txt.indexOf(".");
|
||||
if (dot < 0 || txt.length - dot - 1 <= 3) return;
|
||||
el.value = txt.slice(0, dot + 4);
|
||||
apply(el.valueAsNumber);
|
||||
}
|
||||
|
||||
const BLOCK_ROWS: {
|
||||
key: keyof DesignBlocksState;
|
||||
@@ -196,6 +210,7 @@ calculator math — so the ship-group upgrade flow can reuse it later.
|
||||
title={blockError(row.key)}
|
||||
data-testid={`calculator-block-${row.key}`}
|
||||
onkeydown={(e) => onBlockKey(e, row.key, row.smartStep)}
|
||||
oninput={(e) => capDecimals(e, (v) => (blocks[row.key] = v))}
|
||||
/>
|
||||
{/if}
|
||||
{#if row.tech !== null}
|
||||
@@ -213,6 +228,7 @@ calculator math — so the ship-group upgrade flow can reuse it later.
|
||||
title={techError(techKey)}
|
||||
data-testid={`calculator-tech-${techKey}`}
|
||||
onkeydown={(e) => bumpTech(e, techKey)}
|
||||
oninput={(e) => capDecimals(e, (v) => (techs[techKey] = v))}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@@ -274,7 +290,7 @@ calculator math — so the ship-group upgrade flow can reuse it later.
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
input {
|
||||
font: inherit;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.8rem;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
@@ -284,6 +300,7 @@ calculator math — so the ship-group upgrade flow can reuse it later.
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 3px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-align: right;
|
||||
}
|
||||
/* Hide native spinners across the design area — the row drives
|
||||
every numeric edit through ArrowUp/ArrowDown so the column
|
||||
@@ -313,6 +330,7 @@ calculator math — so the ship-group upgrade flow can reuse it later.
|
||||
.tech-val {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.8rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-align: right;
|
||||
|
||||
Reference in New Issue
Block a user