fix(scale)+docs: fix scale calculator units (cm not m), update CLAUDE.md+ROADMAP.md
Scale calculator: - Real input now in cm (not m) — more natural for architects - Drawing output in mm (unchanged) - Formula: drawing_mm = real_cm * 10 / scale (was val/scale, wrong) - Reverse: real_cm = drawing_mm * scale / 10 (was val*scale, wrong) - Secondary display: real in m; drawing in cm; reverse also shows mm - Added 1:20 preset (useful for detail drawings) - Removed Camere tab (not useful) Docs: - CLAUDE.md: update Mini Utilities 0.3.0 + Password Vault 0.4.0 descriptions - ROADMAP.md: add task 8.04 (this session), bump module versions, renumber 8.05-8.08 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2527,6 +2527,7 @@ function ColorPaletteExtractor() {
|
||||
// ─── Calculator Scară ─────────────────────────────────────────────────────────
|
||||
|
||||
const SCALE_PRESETS = [
|
||||
{ label: "1:20", value: 20 },
|
||||
{ label: "1:50", value: 50 },
|
||||
{ label: "1:100", value: 100 },
|
||||
{ label: "1:200", value: 200 },
|
||||
@@ -2535,6 +2536,15 @@ const SCALE_PRESETS = [
|
||||
{ label: "1:5000", value: 5000 },
|
||||
];
|
||||
|
||||
/**
|
||||
* Scale calculator — all real dimensions in cm, drawing in mm.
|
||||
*
|
||||
* Real → Desen: drawing_mm = real_cm × 10 / scale
|
||||
* e.g. 350 cm at 1:100 → 350 × 10 / 100 = 35 mm
|
||||
*
|
||||
* Desen → Real: real_cm = drawing_mm × scale / 10
|
||||
* e.g. 35 mm at 1:100 → 35 × 100 / 10 = 350 cm = 3.50 m
|
||||
*/
|
||||
function ScaleCalculator() {
|
||||
const [scale, setScale] = useState(100);
|
||||
const [customScale, setCustomScale] = useState("");
|
||||
@@ -2547,27 +2557,22 @@ function ScaleCalculator() {
|
||||
customScale !== "" ? parseFloat(customScale) || scale : scale;
|
||||
const val = parseFloat(inputVal);
|
||||
|
||||
// Real→Desen: val(m) × 1000 → mm, ÷ scale → mm pe desen
|
||||
// Desen→Real: val(mm) × scale → mm real, ÷ 1000 → m
|
||||
// drawing_mm = real_cm × 10 / scale
|
||||
// real_cm = drawing_mm × scale / 10
|
||||
const result = !isNaN(val)
|
||||
? mode === "real-to-drawing"
|
||||
? (val * 1000) / effectiveScale
|
||||
: (val * effectiveScale) / 1000
|
||||
? (val * 10) / effectiveScale // cm → mm on drawing
|
||||
: (val * effectiveScale) / 10 // mm drawing → cm real
|
||||
: NaN;
|
||||
|
||||
const unitIn = mode === "real-to-drawing" ? "m (real)" : "mm (desen)";
|
||||
|
||||
const fmtDesen = (n: number) =>
|
||||
const fmt2 = (n: number) =>
|
||||
isNaN(n)
|
||||
? "—"
|
||||
: n.toLocaleString("ro-RO", { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + " mm";
|
||||
const fmtReal = (n: number) =>
|
||||
isNaN(n)
|
||||
? "—"
|
||||
: n.toLocaleString("ro-RO", { minimumFractionDigits: 3, maximumFractionDigits: 3 }) + " m";
|
||||
: n.toLocaleString("ro-RO", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Scale picker */}
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">Scară</Label>
|
||||
<div className="mt-1 flex flex-wrap items-center gap-2">
|
||||
@@ -2595,6 +2600,8 @@ function ScaleCalculator() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mode */}
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant={mode === "real-to-drawing" ? "default" : "outline"}
|
||||
@@ -2611,49 +2618,71 @@ function ScaleCalculator() {
|
||||
Desen → Real
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Input */}
|
||||
<div>
|
||||
<Label>
|
||||
{mode === "real-to-drawing"
|
||||
? "Dimensiune reală (m)"
|
||||
? "Dimensiune reală (cm)"
|
||||
: "Dimensiune desen (mm)"}
|
||||
</Label>
|
||||
<div className="mt-1 flex gap-2">
|
||||
<div className="mt-1 flex gap-2 items-center">
|
||||
<Input
|
||||
type="number"
|
||||
min={0}
|
||||
step={0.5}
|
||||
value={inputVal}
|
||||
onChange={(e) => setInputVal(e.target.value)}
|
||||
placeholder={mode === "real-to-drawing" ? "ex: 5.4" : "ex: 54"}
|
||||
placeholder={mode === "real-to-drawing" ? "ex: 350" : "ex: 35"}
|
||||
className="flex-1"
|
||||
/>
|
||||
<span className="flex items-center text-sm text-muted-foreground px-2">
|
||||
{unitIn}
|
||||
<span className="text-sm text-muted-foreground shrink-0">
|
||||
{mode === "real-to-drawing" ? "cm" : "mm"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Result */}
|
||||
{!isNaN(val) && val > 0 && (
|
||||
<div className="rounded-md border bg-muted/30 p-4 space-y-2 text-sm">
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<p className="text-xs text-muted-foreground font-medium">
|
||||
Scară 1:{effectiveScale}
|
||||
</p>
|
||||
<p className="text-base font-medium">
|
||||
{mode === "real-to-drawing" ? (
|
||||
<>
|
||||
{val} m real →{" "}
|
||||
<strong className="text-primary">{fmtDesen(result)}</strong> pe desen
|
||||
<CopyButton text={isNaN(result) ? "" : result.toFixed(2)} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{val} mm desen →{" "}
|
||||
<strong className="text-primary">{fmtReal(result)}</strong> real
|
||||
<CopyButton text={isNaN(result) ? "" : result.toFixed(3)} />
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
{mode === "real-to-drawing" && !isNaN(result) && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
= {(result / 10).toFixed(2)} cm pe desen
|
||||
</p>
|
||||
{mode === "real-to-drawing" ? (
|
||||
<>
|
||||
<p>
|
||||
Real: <strong>{fmt2(val)} cm</strong>{" "}
|
||||
<span className="text-muted-foreground">
|
||||
({fmt2(val / 100)} m)
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-base border-t pt-2">
|
||||
Pe desen:{" "}
|
||||
<strong className="text-primary">{fmt2(result)} mm</strong>
|
||||
<CopyButton text={fmt2(result)} />
|
||||
</p>
|
||||
{!isNaN(result) && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
= {fmt2(result / 10)} cm pe desen
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p>
|
||||
Pe desen: <strong>{fmt2(val)} mm</strong>
|
||||
</p>
|
||||
<p className="text-base border-t pt-2">
|
||||
Real:{" "}
|
||||
<strong className="text-primary">{fmt2(result)} cm</strong>
|
||||
<CopyButton text={fmt2(result)} />
|
||||
</p>
|
||||
{!isNaN(result) && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
= {fmt2(result / 100)} m · {fmt2(result * 10)} mm
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user