Treppen UX-Polish: Start-Z, Trittmass-Lock, Pfeil-Stile, Grips
Properties-Panel: - Konsistentes 50px/1fr/14px Grid fuer alle Treppen-Rows - Lage + Unten als Dropdown (lowercase Labels) - Versatz: Dropdown (Geschoss-OKFF) oder eigenes Z mit Input + x-Button - Ziel: gleich (Geschoss-Liste oder eigene Hoehe), Geschosse-Filter excludes das Start-Geschoss - Start-Dropdown filtert auf okff < Ziel-Z (kein hoeheres Geschoss als Start waehlbar, beachtet auch eigene-Hoehe-Ziel) - Stufen: Dropdown 2-40 (statt freie Eingabe), mit Lock nur S-konforme Werte - Dropdowns nutzen System-Font (statt mono) - Ausgrenzung 'Aussenlinie'-Toggle (Aussenlinie immer an) - Pfeil-Style-Dropdown unter Lauflinie-Checkbox: klassisch / gefuellt (Solid-Hatch) / breit / voll (Spitzen bis Treppen-Aussenkanten) Backend Treppe: - Start-Z-Override via treppe_uk_over (m Offset relativ zu Geschoss-OKFF) - 2D-Symbol bleibt auf OKFF (egal ob Versatz) — Symbol klebt am Boden - Lauflinie-Schaft auf visuellen Treppen-Mittelpunkt versetzt (bei Lage=links/rechts), nicht mehr auf der Referenz-Achse - Trittmass-Lock: treppe_lock_s + target_S/A. Beim Aktivieren werden S+A als Ziel gespeichert. Bei H-Change wird N=round(H/target_S) recomputed + Axis-Laenge auf N*target_A angepasst (gerade Treppen) - Bruchsymbol-Toggle aus: ganze Treppe ungesplittet zeichnen (eff_cut_h=0 → kein Lower/Upper-Split) - Treppen-Endpunkt-Marker (treppe_grips.py) — gruene Punkte an Start/ Ende der Lauflinie, beachtet treppe_art (Wendel: poly[1]/poly[2]) Verdoppelungs-Fix: - _find_target_volume skipt treppe_2d_symbol explicit (sind 2D-Curves, kein Volume). Vorher konnte Replace(curve, brep) fehlschlagen → das echte Treppen-Brep blieb stehen + neues kam dazu → Duplikat - _find_objects_by_wall_id mit HiddenObjects+LockedObjects-Iterator, findet auch Objs auf hidden 3D-Layer - Anti-Dup-Cleanup in _regenerate_element: bei mehreren treppe_volume mit gleicher element_id → alle ausser dem ersten loeschen State-Pipeline: - geschosse-Liste enthaelt jetzt okff+hoehe (fuer Frontend-Constraints) - Treppe-State neu: ukOver, arrowStyle, lockS, targetS, targetA - Hidden-Source-Fallback in _send_state findet auch Treppen wenn der 3D-Layer aus ist (sodass Properties-Panel angezeigt wird) Dimensionen-Panel: - on_select + on_idle skippen waehrend Partnership-Cascade oder User-Transform — kein Flicker mehr beim Drag Andere: - Wand-Polyline-Vertex-Grips (alle Vertices, nicht nur Enden) - PopupMenu unterstuetzt _divider + checked-Items - TREPPEN/RAEUME Layer-Migration auf Capital-Case - selection-partnership tolerant: hidden Source wird trotzdem in die Selection genommen (sonst kann Drag nicht durch Pure-Transform)
This commit is contained in:
+230
-93
@@ -2035,6 +2035,7 @@ function TreppeProperties({ treppe, geschosse, onUpdate, onDelete }) {
|
||||
const [nStufen, setNStufen] = useState(String(treppe.nStufen ?? 15))
|
||||
const [laufD, setLaufD] = useState(String(treppe.laufD ?? 0.18))
|
||||
const [hStr, setHStr] = useState('')
|
||||
const [ukStr, setUkStr] = useState('')
|
||||
useEffect(() => {
|
||||
setBreite(String(treppe.breite ?? 1.0))
|
||||
setNStufen(String(treppe.nStufen ?? 15))
|
||||
@@ -2049,9 +2050,27 @@ function TreppeProperties({ treppe, geschosse, onUpdate, onDelete }) {
|
||||
const sa = 2 * S + A
|
||||
const soll = treppe.soll || DEFAULT_TREPPE_SOLL
|
||||
const hasHOver = treppe.hOver != null && treppe.hOver !== ''
|
||||
const hasUkOver = treppe.ukOver != null && treppe.ukOver !== ''
|
||||
useEffect(() => {
|
||||
setHStr(hasHOver ? String(treppe.hOver) : fmtNum(H))
|
||||
}, [treppe.id, treppe.hOver, H, hasHOver])
|
||||
useEffect(() => {
|
||||
setUkStr(hasUkOver ? String(treppe.ukOver) : '')
|
||||
}, [treppe.id, treppe.ukOver, hasUkOver])
|
||||
const onCommitUk = () => {
|
||||
const trimmed = (ukStr || '').trim()
|
||||
if (trimmed === '') {
|
||||
if (hasUkOver) onUpdate({ ukOver: '' })
|
||||
return
|
||||
}
|
||||
const v = parseFloat(trimmed)
|
||||
if (Number.isNaN(v)) { setUkStr(hasUkOver ? String(treppe.ukOver) : ''); return }
|
||||
if (Math.abs(v) < 1e-6) {
|
||||
if (hasUkOver) onUpdate({ ukOver: '' })
|
||||
} else if (Math.abs(v - (parseFloat(treppe.ukOver) || 0)) > 1e-5) {
|
||||
onUpdate({ ukOver: v })
|
||||
}
|
||||
}
|
||||
|
||||
const allOK = (
|
||||
(!soll.s[2] || (S >= soll.s[0] && S <= soll.s[1])) &&
|
||||
@@ -2075,17 +2094,36 @@ function TreppeProperties({ treppe, geschosse, onUpdate, onDelete }) {
|
||||
|
||||
const ref = treppe.treppeReferenz ?? 'mid'
|
||||
const REF_OPTIONS = [
|
||||
{ code: 'links', label: 'Links' },
|
||||
{ code: 'mid', label: 'Mittig' },
|
||||
{ code: 'rechts', label: 'Rechts' },
|
||||
{ code: 'links', label: 'links' },
|
||||
{ code: 'mid', label: 'mittig' },
|
||||
{ code: 'rechts', label: 'rechts' },
|
||||
]
|
||||
const modus = treppe.treppeModus ?? 'flach'
|
||||
const MODUS_OPTIONS = [
|
||||
{ code: 'massiv', label: 'massiv', hint: 'Block bis zum Boden — wie eine Mauer unter der Treppe' },
|
||||
{ code: 'flach', label: 'flach', hint: 'Schräge Plattenunterseite parallel zum Treppenlauf (realistisch)' },
|
||||
{ code: 'plattenrand', label: 'gestuft', hint: 'Plattenunterseite folgt den Stufen, vertikal versetzt' },
|
||||
{ code: 'massiv', label: 'massiv', hint: 'Block bis zum Boden — wie eine Mauer unter der Treppe' },
|
||||
{ code: 'flach', label: 'flach', hint: 'Schräge Plattenunterseite parallel zum Treppenlauf' },
|
||||
{ code: 'plattenrand', label: 'gestuft', hint: 'Plattenunterseite folgt den Stufen, vertikal versetzt' },
|
||||
]
|
||||
|
||||
// Konsistentes Grid: label(50) | control(1fr) | unit(14)
|
||||
const rowStyle = {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '50px 1fr 14px',
|
||||
alignItems: 'center', gap: 6,
|
||||
}
|
||||
const labelStyle = {
|
||||
fontSize: 10, color: 'var(--text-secondary)',
|
||||
}
|
||||
const unitStyle = {
|
||||
fontSize: 10, color: 'var(--text-muted)', textAlign: 'left',
|
||||
}
|
||||
const inputStyle = {
|
||||
fontSize: 11, fontFamily: 'DM Mono, monospace', width: '100%',
|
||||
}
|
||||
const selectStyle = {
|
||||
fontSize: 11, width: '100%', // Dropdowns nutzen System-Font (lesbar bei Worten)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex', flexDirection: 'column', gap: 8,
|
||||
@@ -2103,38 +2141,105 @@ function TreppeProperties({ treppe, geschosse, onUpdate, onDelete }) {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ fontSize: 10, color: 'var(--text-secondary)', width: 50 }}>Start</span>
|
||||
<div style={rowStyle}>
|
||||
<span style={labelStyle}>Start</span>
|
||||
<select value={treppe.geschoss}
|
||||
onChange={(e) => onUpdate({ geschoss: e.target.value })}
|
||||
style={{ flex: 1, fontSize: 11 }}>
|
||||
{geschosse.map(g => <option key={g.id} value={g.id}>{g.name}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ fontSize: 10, color: 'var(--text-secondary)', width: 50 }}>Ziel</span>
|
||||
<select
|
||||
value={hasHOver ? '__custom__' : (treppe.geschossEnd || '')}
|
||||
onChange={(e) => {
|
||||
const v = e.target.value
|
||||
if (v === '__custom__') {
|
||||
// Eigene Hoehe — falls noch nicht gesetzt, mit aktuellem H starten
|
||||
onUpdate({ hOver: H, geschossEnd: '' })
|
||||
} else {
|
||||
onUpdate({ geschossEnd: v, hOver: '' })
|
||||
style={selectStyle}
|
||||
title="Start-Geschoss — kann nicht hoeher als das Ziel-Geschoss sein">
|
||||
{(() => {
|
||||
// Ziel-Z bestimmen: aus Ziel-Geschoss oder aus hOver+startOkff+ukOver
|
||||
let zielZ = null
|
||||
if (treppe.geschossEnd) {
|
||||
const g = geschosse.find(x => x.id === treppe.geschossEnd)
|
||||
if (g) zielZ = Number(g.okff || 0)
|
||||
} else if (treppe.hOver) {
|
||||
const startG = geschosse.find(x => x.id === treppe.geschoss)
|
||||
const startOkff = startG ? Number(startG.okff || 0) : 0
|
||||
const ukO = Number(treppe.ukOver || 0)
|
||||
zielZ = startOkff + ukO + Number(treppe.hOver)
|
||||
}
|
||||
}}
|
||||
style={{ flex: 1, fontSize: 11 }}>
|
||||
<option value="">(auto: Start + Höhe)</option>
|
||||
{geschosse.filter(g => g.id !== treppe.geschoss)
|
||||
.map(g => <option key={g.id} value={g.id}>{g.name}</option>)}
|
||||
<option value="__custom__">eigene Höhe</option>
|
||||
return geschosse
|
||||
.filter(g => zielZ === null || Number(g.okff || 0) < zielZ)
|
||||
.map(g => <option key={g.id} value={g.id}>{g.name}</option>)
|
||||
})()}
|
||||
</select>
|
||||
<span style={unitStyle}></span>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ fontSize: 10, color: 'var(--text-secondary)', width: 50 }}>Breite</span>
|
||||
<div style={rowStyle}
|
||||
title="Vertikaler Versatz des Treppen-Anfangs (relativ zum Geschoss-OKFF)">
|
||||
<span style={labelStyle}>Versatz</span>
|
||||
{hasUkOver ? (
|
||||
<div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
|
||||
<input type="text" value={ukStr}
|
||||
placeholder="0.00"
|
||||
onChange={(e) => setUkStr(e.target.value)}
|
||||
onBlur={onCommitUk}
|
||||
onKeyDown={(e) => { if (e.key === 'Enter') e.target.blur() }}
|
||||
title="Versatz relativ zum Geschoss-OKFF"
|
||||
style={{ ...inputStyle, flex: 1,
|
||||
border: '1px solid var(--accent)' }} />
|
||||
<button onClick={() => onUpdate({ ukOver: '' })}
|
||||
title="Zurueck zu Geschoss-OKFF"
|
||||
style={{ fontSize: 11, padding: '0 6px',
|
||||
background: 'transparent', border: 'none',
|
||||
color: 'var(--text-muted)', cursor: 'pointer' }}>×</button>
|
||||
</div>
|
||||
) : (
|
||||
<select value=""
|
||||
onChange={(e) => {
|
||||
if (e.target.value === '__custom__') onUpdate({ ukOver: 0 })
|
||||
}}
|
||||
style={selectStyle}>
|
||||
<option value="">(Geschoss-OKFF)</option>
|
||||
<option value="__custom__">eigenes Z…</option>
|
||||
</select>
|
||||
)}
|
||||
<span style={unitStyle}>{hasUkOver ? 'm' : ''}</span>
|
||||
</div>
|
||||
|
||||
<div style={rowStyle}>
|
||||
<span style={labelStyle}>Ziel</span>
|
||||
{hasHOver ? (
|
||||
<div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
|
||||
<input type="text" value={hStr}
|
||||
placeholder="1.50"
|
||||
onChange={(e) => setHStr(e.target.value)}
|
||||
onBlur={onCommitH}
|
||||
onKeyDown={(e) => { if (e.key === 'Enter') e.target.blur() }}
|
||||
title="Treppen-Höhe (Delta Start → Ende)"
|
||||
style={{ ...inputStyle, flex: 1,
|
||||
border: '1px solid var(--accent)' }} />
|
||||
<button onClick={() => onUpdate({ hOver: '' })}
|
||||
title="Zurueck zu Geschoss-Verknuepfung"
|
||||
style={{ fontSize: 11, padding: '0 6px',
|
||||
background: 'transparent', border: 'none',
|
||||
color: 'var(--text-muted)', cursor: 'pointer' }}>×</button>
|
||||
</div>
|
||||
) : (
|
||||
<select
|
||||
value={treppe.geschossEnd || ''}
|
||||
onChange={(e) => {
|
||||
const v = e.target.value
|
||||
if (v === '__custom__') {
|
||||
onUpdate({ hOver: H, geschossEnd: '' })
|
||||
} else {
|
||||
onUpdate({ geschossEnd: v, hOver: '' })
|
||||
}
|
||||
}}
|
||||
style={selectStyle}>
|
||||
<option value="">(auto: Start + Höhe)</option>
|
||||
{geschosse.filter(g => g.id !== treppe.geschoss)
|
||||
.map(g => <option key={g.id} value={g.id}>{g.name}</option>)}
|
||||
<option value="__custom__">eigene Höhe…</option>
|
||||
</select>
|
||||
)}
|
||||
<span style={unitStyle}>{hasHOver ? 'm' : ''}</span>
|
||||
</div>
|
||||
|
||||
<div style={rowStyle}>
|
||||
<span style={labelStyle}>Breite</span>
|
||||
<input type="text" value={breite}
|
||||
onChange={(e) => setBreite(e.target.value)}
|
||||
onBlur={() => {
|
||||
@@ -2143,62 +2248,68 @@ function TreppeProperties({ treppe, geschosse, onUpdate, onDelete }) {
|
||||
else setBreite(String(treppe.breite))
|
||||
}}
|
||||
onKeyDown={(e) => { if (e.key === 'Enter') e.target.blur() }}
|
||||
style={{ flex: 1, fontSize: 11, fontFamily: 'DM Mono, monospace' }} />
|
||||
<span style={{ fontSize: 10, color: 'var(--text-muted)' }}>m</span>
|
||||
style={inputStyle} />
|
||||
<span style={unitStyle}>m</span>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ fontSize: 10, color: 'var(--text-secondary)', width: 50 }}>Stufen</span>
|
||||
<input type="text" value={nStufen}
|
||||
onChange={(e) => setNStufen(e.target.value)}
|
||||
onBlur={() => {
|
||||
const v = parseInt(nStufen, 10)
|
||||
if (Number.isFinite(v) && v >= 2 && v <= 40) onUpdate({ nStufen: v })
|
||||
else setNStufen(String(treppe.nStufen))
|
||||
}}
|
||||
onKeyDown={(e) => { if (e.key === 'Enter') e.target.blur() }}
|
||||
style={{ flex: 1, fontSize: 11, fontFamily: 'DM Mono, monospace' }} />
|
||||
<span style={{ fontSize: 10, color: 'var(--text-muted)' }}>×</span>
|
||||
<div style={rowStyle} title={treppe.lockS
|
||||
? 'Mit Trittmaß-Lock: nur Anzahlen die ein S-Werte nahe der Sollhöhe ergeben'
|
||||
: 'Anzahl Tritte (2-40)'}>
|
||||
<span style={labelStyle}>Stufen</span>
|
||||
<select value={treppe.nStufen}
|
||||
onChange={(e) => onUpdate({ nStufen: parseInt(e.target.value, 10) })}
|
||||
style={selectStyle}>
|
||||
{(() => {
|
||||
// Mit Lock: filtere die N-Werte deren resultierendes S nahe an
|
||||
// target_S liegt (±10%). Sonst 2-40.
|
||||
const range = []
|
||||
for (let i = 2; i <= 40; i++) range.push(i)
|
||||
if (treppe.lockS && treppe.targetS > 0.05 && H > 0.1) {
|
||||
const tgt = Number(treppe.targetS)
|
||||
const tol = tgt * 0.10
|
||||
return range
|
||||
.filter(n => Math.abs(H / n - tgt) <= tol)
|
||||
.map(n => (
|
||||
<option key={n} value={n}>
|
||||
{n} (S={(H / n).toFixed(3)} m)
|
||||
</option>
|
||||
))
|
||||
}
|
||||
return range.map(n => <option key={n} value={n}>{n}</option>)
|
||||
})()}
|
||||
</select>
|
||||
<span style={unitStyle}>×</span>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ fontSize: 10, color: 'var(--text-secondary)', width: 50 }}>Lage</span>
|
||||
<div style={{ flex: 1, display: 'flex', gap: 3 }}>
|
||||
<div style={rowStyle}>
|
||||
<span style={labelStyle}>Lage</span>
|
||||
<select value={ref}
|
||||
onChange={(e) => onUpdate({ treppeReferenz: e.target.value })}
|
||||
style={selectStyle}>
|
||||
{REF_OPTIONS.map(o => (
|
||||
<BarToggle key={o.code}
|
||||
label={o.label}
|
||||
active={ref === o.code}
|
||||
onClick={() => onUpdate({ treppeReferenz: o.code })} />
|
||||
<option key={o.code} value={o.code}>{o.label}</option>
|
||||
))}
|
||||
</div>
|
||||
</select>
|
||||
<span style={unitStyle}></span>
|
||||
</div>
|
||||
|
||||
<div style={{ height: 1, background: 'var(--border-light)', margin: '2px 0' }} />
|
||||
|
||||
{/* Unterseite-Modus */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ fontSize: 10, color: 'var(--text-secondary)', width: 50 }}
|
||||
title="Form der Treppen-Unterseite">
|
||||
Unten
|
||||
</span>
|
||||
<div style={{ flex: 1, display: 'flex', gap: 3 }}>
|
||||
<div style={rowStyle} title="Form der Treppen-Unterseite">
|
||||
<span style={labelStyle}>Unten</span>
|
||||
<select value={modus}
|
||||
onChange={(e) => onUpdate({ treppeModus: e.target.value })}
|
||||
style={selectStyle}>
|
||||
{MODUS_OPTIONS.map(o => (
|
||||
<BarToggle key={o.code}
|
||||
label={o.label}
|
||||
active={modus === o.code}
|
||||
onClick={() => onUpdate({ treppeModus: o.code })}
|
||||
title={o.hint} />
|
||||
<option key={o.code} value={o.code} title={o.hint}>{o.label}</option>
|
||||
))}
|
||||
</div>
|
||||
</select>
|
||||
<span style={unitStyle}></span>
|
||||
</div>
|
||||
|
||||
{/* Lauf-Plattendicke (nur fuer flach + plattenrand relevant) */}
|
||||
{modus !== 'massiv' && (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ fontSize: 10, color: 'var(--text-secondary)', width: 50 }}
|
||||
title="Dicke der Lauf-Platte (Materialdicke unter den Stufen)">
|
||||
Platte
|
||||
</span>
|
||||
<div style={rowStyle} title="Dicke der Lauf-Platte (Materialdicke unter den Stufen)">
|
||||
<span style={labelStyle}>Platte</span>
|
||||
<input type="text" value={laufD}
|
||||
onChange={(e) => setLaufD(e.target.value)}
|
||||
onBlur={() => {
|
||||
@@ -2207,8 +2318,8 @@ function TreppeProperties({ treppe, geschosse, onUpdate, onDelete }) {
|
||||
else setLaufD(String(treppe.laufD))
|
||||
}}
|
||||
onKeyDown={(e) => { if (e.key === 'Enter') e.target.blur() }}
|
||||
style={{ flex: 1, fontSize: 11, fontFamily: 'DM Mono, monospace' }} />
|
||||
<span style={{ fontSize: 10, color: 'var(--text-muted)' }}>m</span>
|
||||
style={inputStyle} />
|
||||
<span style={unitStyle}>m</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -2219,24 +2330,41 @@ function TreppeProperties({ treppe, geschosse, onUpdate, onDelete }) {
|
||||
letterSpacing: '0.06em', textTransform: 'uppercase' }}>
|
||||
2D-Plansymbol
|
||||
</span>
|
||||
{[
|
||||
['showLauflinie', 'Lauflinie'],
|
||||
['showAussen', 'Außenlinie'],
|
||||
['showBruch', 'Bruchsymbol'],
|
||||
].map(([key, label]) => {
|
||||
const on = treppe[key] !== false
|
||||
return (
|
||||
<label key={key} style={{
|
||||
display: 'flex', alignItems: 'center', gap: 6,
|
||||
fontSize: 11, cursor: 'pointer',
|
||||
}}>
|
||||
<input type="checkbox" checked={on}
|
||||
onChange={(e) => onUpdate({ [key]: e.target.checked })}
|
||||
style={{ accentColor: 'var(--accent)' }} />
|
||||
<span>{label}</span>
|
||||
</label>
|
||||
)
|
||||
})}
|
||||
<label style={{
|
||||
display: 'flex', alignItems: 'center', gap: 6,
|
||||
fontSize: 11, cursor: 'pointer',
|
||||
}}>
|
||||
<input type="checkbox" checked={treppe.showLauflinie !== false}
|
||||
onChange={(e) => onUpdate({ showLauflinie: e.target.checked })}
|
||||
style={{ accentColor: 'var(--accent)' }} />
|
||||
<span>Lauflinie</span>
|
||||
</label>
|
||||
{treppe.showLauflinie !== false && (
|
||||
<div style={{
|
||||
display: 'grid', gridTemplateColumns: '50px 1fr 14px',
|
||||
alignItems: 'center', gap: 6, marginLeft: 18,
|
||||
}}>
|
||||
<span style={labelStyle}>Pfeil</span>
|
||||
<select value={treppe.arrowStyle || 'klassisch'}
|
||||
onChange={(e) => onUpdate({ arrowStyle: e.target.value })}
|
||||
style={selectStyle}>
|
||||
<option value="klassisch">klassisch</option>
|
||||
<option value="filled">gefüllt</option>
|
||||
<option value="breit">breit</option>
|
||||
<option value="voll">voll (bis zu den Seiten)</option>
|
||||
</select>
|
||||
<span style={unitStyle}></span>
|
||||
</div>
|
||||
)}
|
||||
<label style={{
|
||||
display: 'flex', alignItems: 'center', gap: 6,
|
||||
fontSize: 11, cursor: 'pointer',
|
||||
}}>
|
||||
<input type="checkbox" checked={treppe.showBruch !== false}
|
||||
onChange={(e) => onUpdate({ showBruch: e.target.checked })}
|
||||
style={{ accentColor: 'var(--accent)' }} />
|
||||
<span>Bruchsymbol</span>
|
||||
</label>
|
||||
<label style={{
|
||||
display: 'flex', alignItems: 'center', gap: 6,
|
||||
fontSize: 10, cursor: 'pointer',
|
||||
@@ -2283,6 +2411,15 @@ function TreppeProperties({ treppe, geschosse, onUpdate, onDelete }) {
|
||||
}}>auto</button>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}
|
||||
title="Wenn an: Beim Aendern der Hoehe (oder Versatz/Ziel) wird die Anzahl Stufen automatisch nachgerechnet, damit S konstant bleibt.">
|
||||
<input type="checkbox" checked={!!treppe.lockS}
|
||||
onChange={(e) => onUpdate({ lockS: e.target.checked })}
|
||||
style={{ accentColor: 'var(--accent)', width: 12, height: 12 }} />
|
||||
<span style={{ fontSize: 10, color: 'var(--text-muted)' }}>
|
||||
Trittmaß fixiert (S{treppe.targetS ? ' = ' + Number(treppe.targetS).toFixed(3) + ' m' : ''})
|
||||
</span>
|
||||
</div>
|
||||
<SollRow label="S" value={S} unit="m" soll={soll} sollKey="s"
|
||||
onUpdateSoll={onUpdateSoll} />
|
||||
<SollRow label="A" value={A} unit="m" soll={soll} sollKey="a"
|
||||
|
||||
Reference in New Issue
Block a user