better
This commit is contained in:
parent
b9485e4097
commit
0c0f08b350
45 changed files with 1565 additions and 1579 deletions
|
|
@ -16,6 +16,7 @@ import { mm } from '../lib/format';
|
|||
import { NumberField, NumericInput, Issues } from './Fields';
|
||||
import { DoorPosition } from './DoorPosition';
|
||||
import { insertWallAfter, moveWall } from '../lib/wall-editing';
|
||||
import { PRECISION, PROJECT_LIMITS } from '../lib/limits';
|
||||
interface Props {
|
||||
room: Room;
|
||||
geometry: Geometry;
|
||||
|
|
@ -36,6 +37,7 @@ export function OutlineEditor({
|
|||
}: Props) {
|
||||
const draggedWall = useRef<string | null>(null);
|
||||
const [dropTarget, setDropTarget] = useState<string | null>(null);
|
||||
const [customSelected, setCustomSelected] = useState(false);
|
||||
const changeWall = (id: string, fn: (wall: Wall) => Wall) =>
|
||||
changeRoom((r) => ({ ...r, walls: r.walls.map((w) => (w.id === id ? fn(w) : w)) }));
|
||||
const isRectangle =
|
||||
|
|
@ -43,6 +45,10 @@ export function OutlineEditor({
|
|||
room.walls.every((w) => w.turn === 90) &&
|
||||
room.walls[0].length === room.walls[2].length &&
|
||||
room.walls[1].length === room.walls[3].length;
|
||||
const isFireplace =
|
||||
room.walls.length === 8 &&
|
||||
room.walls.every((wall, index) => wall.turn === [90, 90, 90, -90, -90, 90, 90, 90][index]);
|
||||
const isCustom = customSelected || (!isRectangle && !isFireplace);
|
||||
const lastEdge = geometry.edges.at(-1);
|
||||
const finalExpectedLength = lastEdge ? Math.hypot(lastEdge.start.x, lastEdge.start.y) : 0;
|
||||
const addWall = () =>
|
||||
|
|
@ -106,41 +112,72 @@ export function OutlineEditor({
|
|||
<span>Room name</span>
|
||||
<input
|
||||
value={room.name}
|
||||
maxLength={80}
|
||||
maxLength={PROJECT_LIMITS.nameLength}
|
||||
onChange={(e) => changeRoom((r) => ({ ...r, name: e.target.value }))}
|
||||
/>
|
||||
</label>
|
||||
<div className="template-options">
|
||||
<div className="subheading shape-heading">
|
||||
<h3>Room shape</h3>
|
||||
</div>
|
||||
<div
|
||||
className="template-options"
|
||||
role="group"
|
||||
aria-label="Room shape"
|
||||
aria-describedby="custom-shape-help"
|
||||
>
|
||||
<button
|
||||
className={isRectangle ? 'template active' : 'template'}
|
||||
aria-pressed={isRectangle}
|
||||
onClick={() => changeRoom((r) => rectangle(r.id, r.name))}
|
||||
className={isRectangle && !isCustom ? 'template active' : 'template'}
|
||||
aria-pressed={isRectangle && !isCustom}
|
||||
onClick={() => {
|
||||
setCustomSelected(false);
|
||||
changeRoom((r) => rectangle(r.id, r.name));
|
||||
}}
|
||||
>
|
||||
<span className="rectangle-icon" />
|
||||
Rectangle
|
||||
</button>
|
||||
<button
|
||||
className={room.walls.length === 8 ? 'template active' : 'template'}
|
||||
aria-pressed={room.walls.length === 8}
|
||||
onClick={() => changeRoom((r) => fireplace(r.id, r.name))}
|
||||
className={isFireplace && !isCustom ? 'template active' : 'template'}
|
||||
aria-pressed={isFireplace && !isCustom}
|
||||
onClick={() => {
|
||||
setCustomSelected(false);
|
||||
changeRoom((r) => fireplace(r.id, r.name));
|
||||
}}
|
||||
>
|
||||
<span className="fireplace-icon" />
|
||||
With fireplace
|
||||
</button>
|
||||
<button
|
||||
className="template"
|
||||
onClick={() =>
|
||||
className={isCustom ? 'template active' : 'template'}
|
||||
aria-pressed={isCustom}
|
||||
onClick={() => {
|
||||
setCustomSelected(true);
|
||||
changeRoom((r) => ({
|
||||
...r,
|
||||
walls: [{ id: `${r.id}-w1`, length: 4000, turn: 90, doors: [] }],
|
||||
}))
|
||||
}
|
||||
}));
|
||||
}}
|
||||
>
|
||||
<MoveUpRight size={19} />
|
||||
Custom
|
||||
</button>
|
||||
</div>
|
||||
{isRectangle && (
|
||||
<p className="shape-help" id="custom-shape-help">
|
||||
{isCustom && geometry.closed ? (
|
||||
<>Your outline is complete. Adjust individual walls, corners or doorways below.</>
|
||||
) : isCustom ? (
|
||||
<>
|
||||
Add your walls in order below, then use <strong>Add closing wall</strong> to complete
|
||||
the outline.
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Have an irregular room? Click <strong>Custom</strong> to start a new outline and enter
|
||||
each wall and corner. Choosing a shape replaces the current outline and doorways.
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
{isRectangle && !isCustom && (
|
||||
<div className="field-grid quick-dimensions">
|
||||
<NumberField
|
||||
label="Room width"
|
||||
|
|
@ -166,7 +203,7 @@ export function OutlineEditor({
|
|||
/>
|
||||
</div>
|
||||
)}
|
||||
<details className="wall-details" open={!isRectangle}>
|
||||
<details className="wall-details" open={isCustom || !isRectangle}>
|
||||
<summary>
|
||||
Walls & corners <span>{room.walls.length} walls</span>
|
||||
</summary>
|
||||
|
|
@ -270,7 +307,7 @@ export function OutlineEditor({
|
|||
className="icon-button"
|
||||
aria-label={`Insert wall after W${i + 1}`}
|
||||
title={`Insert wall after W${i + 1}`}
|
||||
disabled={room.walls.length >= 100}
|
||||
disabled={room.walls.length >= PROJECT_LIMITS.wallsPerRoom}
|
||||
onClick={() => changeRoom((r) => insertWallAfter(r, wall.id))}
|
||||
>
|
||||
<Plus size={16} />
|
||||
|
|
@ -289,7 +326,11 @@ export function OutlineEditor({
|
|||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button className="text-button" onClick={addWall} disabled={room.walls.length >= 100}>
|
||||
<button
|
||||
className="text-button"
|
||||
onClick={addWall}
|
||||
disabled={room.walls.length >= PROJECT_LIMITS.wallsPerRoom}
|
||||
>
|
||||
<Plus size={15} /> Add a wall
|
||||
</button>
|
||||
</details>
|
||||
|
|
@ -317,7 +358,10 @@ export function OutlineEditor({
|
|||
<button
|
||||
className="text-button"
|
||||
onClick={closeOutline}
|
||||
disabled={room.walls.length >= 100 || Math.abs(geometry.closingTurn) >= 179.99}
|
||||
disabled={
|
||||
room.walls.length >= PROJECT_LIMITS.wallsPerRoom ||
|
||||
Math.abs(geometry.closingTurn) >= PROJECT_LIMITS.maxTurn - PRECISION.millimetres
|
||||
}
|
||||
>
|
||||
Add closing wall <Plus size={14} />
|
||||
</button>
|
||||
|
|
@ -419,7 +463,9 @@ export function OutlineEditor({
|
|||
<button
|
||||
className="text-button"
|
||||
onClick={addDoor}
|
||||
disabled={!room.walls.length || room.walls.at(-1)!.doors.length >= 30}
|
||||
disabled={
|
||||
!room.walls.length || room.walls.at(-1)!.doors.length >= PROJECT_LIMITS.doorsPerWall
|
||||
}
|
||||
>
|
||||
<Plus size={15} /> Add a doorway
|
||||
</button>
|
||||
|
|
@ -427,7 +473,7 @@ export function OutlineEditor({
|
|||
<NumberField
|
||||
label="Measurement tolerance"
|
||||
value={tolerance}
|
||||
max={50}
|
||||
max={PROJECT_LIMITS.maxTolerance}
|
||||
onChange={(n) => changeProject((p) => ({ ...p, tolerance: n }))}
|
||||
hint="Largest closing gap accepted for the cut plan."
|
||||
/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue