fix(editor): site-panel property-line coords + area/perimeter follow the unit toggle

The property-line vertex X/Z inputs and the Area/Perimeter readout were
hardcoded to meters. Convert them to feet / ft² when the viewer preference is
imperial, matching every other length input.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aymeric Rabot
2026-07-08 17:00:47 +02:00
co-authored by Claude Opus 4.8
parent 69813a6e62
commit 5ffde5f66a
@@ -38,6 +38,11 @@ import {
} from './../../../../../lib/level-duplication' } from './../../../../../lib/level-duplication'
import { getDefaultLevelName } from '@pascal-app/core' import { getDefaultLevelName } from '@pascal-app/core'
import { deleteLevelWithFallbackSelection } from './../../../../../lib/level-selection' import { deleteLevelWithFallbackSelection } from './../../../../../lib/level-selection'
import {
getLinearUnitLabel,
linearUnitToMeters,
metersToLinearUnit,
} from './../../../../../lib/measurements'
import { createLocalGuideImage } from './../../../../../lib/local-guide-image' import { createLocalGuideImage } from './../../../../../lib/local-guide-image'
import { cn } from './../../../../../lib/utils' import { cn } from './../../../../../lib/utils'
import useEditor from './../../../../../store/use-editor' import useEditor from './../../../../../store/use-editor'
@@ -93,6 +98,7 @@ const PropertyLineSection = memo(function PropertyLineSection() {
const updateNode = useScene((state) => state.updateNode) const updateNode = useScene((state) => state.updateNode)
const mode = useEditor((state) => state.mode) const mode = useEditor((state) => state.mode)
const setMode = useEditor((state) => state.setMode) const setMode = useEditor((state) => state.setMode)
const viewerUnit = useViewer((state) => state.unit)
if (!siteNode) return null if (!siteNode) return null
@@ -101,6 +107,14 @@ const PropertyLineSection = memo(function PropertyLineSection() {
const perimeter = calculatePerimeter(points) const perimeter = calculatePerimeter(points)
const isEditing = mode === 'edit' const isEditing = mode === 'edit'
// Property-line coordinates and readouts follow the metric/imperial toggle.
const isImperial = viewerUnit === 'imperial'
const linearLabel = getLinearUnitLabel(viewerUnit)
const toDisplayLinear = (meters: number) => metersToLinearUnit(meters, viewerUnit)
const toStoredLinear = (display: number) => linearUnitToMeters(display, viewerUnit)
const displayArea = isImperial ? area * 10.763_910_417 : area
const displayPerimeter = toDisplayLinear(perimeter)
const handleToggleEdit = () => { const handleToggleEdit = () => {
setMode(isEditing ? 'select' : 'edit') setMode(isEditing ? 'select' : 'edit')
} }
@@ -166,10 +180,16 @@ const PropertyLineSection = memo(function PropertyLineSection() {
{/* Measurements */} {/* Measurements */}
<div className="relative flex gap-3 pr-3 pb-2 pl-10"> <div className="relative flex gap-3 pr-3 pb-2 pl-10">
<div className="text-muted-foreground text-xs"> <div className="text-muted-foreground text-xs">
Area: <span className="text-foreground">{area.toFixed(1)} m²</span> Area:{' '}
<span className="text-foreground">
{displayArea.toFixed(1)} {isImperial ? 'ft²' : 'm²'}
</span>
</div> </div>
<div className="text-muted-foreground text-xs"> <div className="text-muted-foreground text-xs">
Perimeter: <span className="text-foreground">{perimeter.toFixed(1)} m</span> Perimeter:{' '}
<span className="text-foreground">
{displayPerimeter.toFixed(1)} {linearLabel}
</span>
</div> </div>
</div> </div>
@@ -184,21 +204,21 @@ const PropertyLineSection = memo(function PropertyLineSection() {
<input <input
className="w-16 rounded border border-border/50 bg-accent/50 px-1.5 py-0.5 text-foreground text-xs focus:border-primary focus:outline-none" className="w-16 rounded border border-border/50 bg-accent/50 px-1.5 py-0.5 text-foreground text-xs focus:border-primary focus:outline-none"
onChange={(e) => onChange={(e) =>
handlePointChange(index, 0, Number.parseFloat(e.target.value) || 0) handlePointChange(index, 0, toStoredLinear(Number.parseFloat(e.target.value) || 0))
} }
step={0.5} step={0.5}
type="number" type="number"
value={point[0]} value={Number(toDisplayLinear(point[0]).toFixed(2))}
/> />
<label className="shrink-0 text-muted-foreground">Z</label> <label className="shrink-0 text-muted-foreground">Z</label>
<input <input
className="w-16 rounded border border-border/50 bg-accent/50 px-1.5 py-0.5 text-foreground text-xs focus:border-primary focus:outline-none" className="w-16 rounded border border-border/50 bg-accent/50 px-1.5 py-0.5 text-foreground text-xs focus:border-primary focus:outline-none"
onChange={(e) => onChange={(e) =>
handlePointChange(index, 1, Number.parseFloat(e.target.value) || 0) handlePointChange(index, 1, toStoredLinear(Number.parseFloat(e.target.value) || 0))
} }
step={0.5} step={0.5}
type="number" type="number"
value={point[1]} value={Number(toDisplayLinear(point[1]).toFixed(2))}
/> />
<button <button
className={cn( className={cn(