This commit is contained in:
Andras Schmelczer 2026-09-11 22:14:24 +01:00
commit 0c0f08b350
45 changed files with 1565 additions and 1579 deletions

View file

@ -39,6 +39,9 @@ export function MaterialsEditor({
<h3 id="flooring-materials" className="material-heading">
Floorboards
</h3>
<p className="helper material-help">
Use the length and width printed on your flooring pack.
</p>
<div className="field-grid">
<NumberField
label="Board length"
@ -56,13 +59,6 @@ export function MaterialsEditor({
<div className="field">
<span>Laying pattern</span>
<div className="segmented" role="group" aria-label="Laying pattern">
<button
className={f.pattern === 'brick' ? 'active' : ''}
aria-pressed={f.pattern === 'brick'}
onClick={() => floor('pattern', 'brick')}
>
Brick
</button>
<button
className={f.pattern === 'random' ? 'active' : ''}
aria-pressed={f.pattern === 'random'}
@ -70,16 +66,28 @@ export function MaterialsEditor({
>
Random
</button>
<button
className={f.pattern === 'brick' ? 'active' : ''}
aria-pressed={f.pattern === 'brick'}
onClick={() => floor('pattern', 'brick')}
>
Brick
</button>
</div>
<p className="helper">
{f.pattern === 'random'
? 'Varied joints for a natural look. Choose fewer cuts or a more varied arrangement below.'
: 'A regular pattern with each row staggered by half a board.'}
</p>
</div>
{f.pattern === 'random' && (
<div className="field">
<span>Optimise random flooring · all rooms</span>
<span>What matters most? · all rooms</span>
<div className="optimisation-options" role="group" aria-label="Flooring optimisation">
{(['cuts', 'random'] as const).map((priority) => {
const plan = flooringOptions[priority];
const valid = !plan.issues.some((issue) => issue.severity === 'error');
const selected = (f.optimisation ?? 'cuts') === priority;
const selected = f.optimisation === priority;
return (
<button
key={priority}
@ -119,42 +127,56 @@ export function MaterialsEditor({
</button>
</div>
</div>
<div className="field-grid">
<NumberField label="Wall spacer" value={f.gap} onChange={(n) => floor('gap', n)} />
<NumberField
label="Saw kerf"
value={f.kerf}
onChange={(n) => floor('kerf', n)}
tooltip={kerfHelp}
/>
<NumberField
label="Minimum joint offset"
value={f.minOffset}
onChange={(n) => floor('minOffset', n)}
/>
<NumberField
label="Maximum joint offset"
value={f.maxOffset}
onChange={(n) => floor('maxOffset', n)}
/>
<NumberField
label="Shortest end piece"
value={f.minLength}
min={1}
onChange={(n) => floor('minLength', n)}
/>
<NumberField
label="Narrowest edge row"
value={f.minWidth}
min={1}
onChange={(n) => floor('minWidth', n)}
/>
</div>
<NumberField
label="Wall spacer"
value={f.gap}
onChange={(n) => floor('gap', n)}
hint="Expansion gap between the floorboards and walls. Check your flooring instructions."
/>
<details className="advanced-settings">
<summary>Advanced flooring settings</summary>
<p className="helper material-help">
Adjust the saw blade width, joint spacing and smallest pieces to suit your flooring.
</p>
<div className="field-grid">
<NumberField
label="Saw kerf"
value={f.kerf}
onChange={(n) => floor('kerf', n)}
tooltip={kerfHelp}
/>
<NumberField
label="Minimum joint offset"
value={f.minOffset}
onChange={(n) => floor('minOffset', n)}
/>
<NumberField
label="Maximum joint offset"
value={f.maxOffset}
onChange={(n) => floor('maxOffset', n)}
/>
<NumberField
label="Shortest end piece"
value={f.minLength}
min={1}
onChange={(n) => floor('minLength', n)}
/>
<NumberField
label="Narrowest edge row"
value={f.minWidth}
min={1}
onChange={(n) => floor('minWidth', n)}
/>
</div>
</details>
</section>
<section className="material-section skirting" aria-labelledby="skirting-materials">
<h3 id="skirting-materials" className="material-heading">
Skirting boards
</h3>
<p className="helper material-help">
Enter one purchased board length. Door openings are left clear automatically.
</p>
<div className="field-grid">
<NumberField
label="Skirting board length"
@ -167,19 +189,24 @@ export function MaterialsEditor({
value={s.thickness}
onChange={(n) => skirt('thickness', n)}
/>
<NumberField
label="Minimum piece"
value={s.minLength}
min={1}
onChange={(n) => skirt('minLength', n)}
/>
<NumberField
label="Skirting saw kerf"
value={s.kerf}
onChange={(n) => skirt('kerf', n)}
tooltip={kerfHelp}
/>
</div>
<details className="advanced-settings">
<summary>Advanced skirting settings</summary>
<div className="field-grid">
<NumberField
label="Minimum piece"
value={s.minLength}
min={1}
onChange={(n) => skirt('minLength', n)}
/>
<NumberField
label="Skirting saw kerf"
value={s.kerf}
onChange={(n) => skirt('kerf', n)}
tooltip={kerfHelp}
/>
</div>
</details>
</section>
</>
);