From 22eb9a43834a6c418932cb8e541d286c9c835643 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Thu, 12 Mar 2026 23:57:28 +0200 Subject: [PATCH] feat(scale): add mm/cm/m/km unit switcher for real dimensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scale calculator now supports all 4 real-world units: - mm, cm, m, km — toggle buttons next to mode selector - Formula adapts via unit→mm multiplier (mm=1, cm=10, m=1000, km=1M) - Real→Desen: input in chosen unit, output always mm on drawing - Desen→Real: output in chosen unit, secondary line shows all other units - Switching unit clears input to avoid confusion - step attribute adapts per unit (km=0.001, m=0.01, others=0.5) Co-Authored-By: Claude Sonnet 4.6 --- .../components/mini-utilities-module.tsx | 156 +++++++++++------- 1 file changed, 100 insertions(+), 56 deletions(-) diff --git a/src/modules/mini-utilities/components/mini-utilities-module.tsx b/src/modules/mini-utilities/components/mini-utilities-module.tsx index f126cb5..a06771f 100644 --- a/src/modules/mini-utilities/components/mini-utilities-module.tsx +++ b/src/modules/mini-utilities/components/mini-utilities-module.tsx @@ -2536,39 +2536,61 @@ const SCALE_PRESETS = [ { label: "1:5000", value: 5000 }, ]; +// Real unit → multiplier to convert to mm +const REAL_UNITS = [ + { id: "mm", label: "mm", toMm: 1 }, + { id: "cm", label: "cm", toMm: 10 }, + { id: "m", label: "m", toMm: 1_000 }, + { id: "km", label: "km", toMm: 1_000_000 }, +] as const; +type RealUnit = (typeof REAL_UNITS)[number]["id"]; + /** - * Scale calculator — all real dimensions in cm, drawing in mm. + * Scale calculator. * - * Real → Desen: drawing_mm = real_cm × 10 / scale - * e.g. 350 cm at 1:100 → 350 × 10 / 100 = 35 mm + * Core identity (all in mm): + * drawing_mm = real_mm / scale + * real_mm = drawing_mm × scale * - * Desen → Real: real_cm = drawing_mm × scale / 10 - * e.g. 35 mm at 1:100 → 35 × 100 / 10 = 350 cm = 3.50 m + * Real input in any unit → convert to mm → apply scale → drawing in mm. + * Drawing input in mm → apply scale → real mm → convert to chosen unit. */ function ScaleCalculator() { const [scale, setScale] = useState(100); const [customScale, setCustomScale] = useState(""); - const [mode, setMode] = useState<"real-to-drawing" | "drawing-to-real">( - "real-to-drawing", - ); + const [mode, setMode] = useState<"real-to-drawing" | "drawing-to-real">("real-to-drawing"); + const [realUnit, setRealUnit] = useState("cm"); const [inputVal, setInputVal] = useState(""); - const effectiveScale = - customScale !== "" ? parseFloat(customScale) || scale : scale; + const effectiveScale = customScale !== "" ? parseFloat(customScale) || scale : scale; const val = parseFloat(inputVal); - // drawing_mm = real_cm × 10 / scale - // real_cm = drawing_mm × scale / 10 - const result = !isNaN(val) - ? mode === "real-to-drawing" - ? (val * 10) / effectiveScale // cm → mm on drawing - : (val * effectiveScale) / 10 // mm drawing → cm real + const unitDef = REAL_UNITS.find((u) => u.id === realUnit)!; + + // drawing_mm = real_in_unit × unitDef.toMm / scale + // real_in_unit = drawing_mm × scale / unitDef.toMm + const drawing_mm = !isNaN(val) && mode === "real-to-drawing" + ? (val * unitDef.toMm) / effectiveScale + : NaN; + const real_in_unit = !isNaN(val) && mode === "drawing-to-real" + ? (val * effectiveScale) / unitDef.toMm : NaN; - const fmt2 = (n: number) => - isNaN(n) + // For secondary display: real_mm (whichever mode) + const real_mm = mode === "real-to-drawing" + ? val * unitDef.toMm + : val * effectiveScale; + + const fmt = (n: number, decimals = 2) => + isNaN(n) || !isFinite(n) ? "—" - : n.toLocaleString("ro-RO", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); + : n.toLocaleString("ro-RO", { minimumFractionDigits: decimals, maximumFractionDigits: decimals }); + + // Build secondary real conversions (exclude current unit) + const secondaryReal = (mm: number) => + REAL_UNITS.filter((u) => u.id !== realUnit) + .map((u) => `${fmt(mm / u.toMm)} ${u.id}`) + .join(" · "); return (
@@ -2601,43 +2623,64 @@ function ScaleCalculator() {
- {/* Mode */} -
- - + {/* Mode + real unit picker */} +
+
+ + +
+
+ Unitate reală: + {REAL_UNITS.map((u) => ( + + ))} +
{/* Input */}
setInputVal(e.target.value)} - placeholder={mode === "real-to-drawing" ? "ex: 350" : "ex: 35"} + placeholder={ + mode === "real-to-drawing" + ? realUnit === "m" ? "ex: 3.5" : realUnit === "km" ? "ex: 0.350" : "ex: 350" + : "ex: 35" + } className="flex-1" /> - - {mode === "real-to-drawing" ? "cm" : "mm"} + + {mode === "real-to-drawing" ? realUnit : "mm"}
@@ -2645,41 +2688,42 @@ function ScaleCalculator() { {/* Result */} {!isNaN(val) && val > 0 && (
-

- Scară 1:{effectiveScale} -

+

Scară 1:{effectiveScale}

{mode === "real-to-drawing" ? ( <>

- Real: {fmt2(val)} cm{" "} - - ({fmt2(val / 100)} m) - + Real:{" "} + {fmt(val)} {realUnit} + {realUnit !== "mm" && ( + + ({secondaryReal(real_mm)}) + + )}

Pe desen:{" "} - {fmt2(result)} mm - + {fmt(drawing_mm)} mm +

- {!isNaN(result) && ( + {!isNaN(drawing_mm) && (

- = {fmt2(result / 10)} cm pe desen + = {fmt(drawing_mm / 10)} cm pe desen

)} ) : ( <>

- Pe desen: {fmt2(val)} mm + Pe desen: {fmt(val)} mm

Real:{" "} - {fmt2(result)} cm - + {fmt(real_in_unit)} {realUnit} +

- {!isNaN(result) && ( + {!isNaN(real_mm) && (

- = {fmt2(result / 100)} m  ·  {fmt2(result * 10)} mm + {secondaryReal(real_mm)}

)}