Massstab 2x2-Grid: Live | Dropdown / Ratio | Buttons

User-Korrektur: Layout sollte 2x2 sein:
  Reihe 1: [Aktueller Massstab]  [Dropdown gesetzter Massstab]
  Reihe 2: [Zoom-Verhaeltnis %]   [Buttons]

Restrukturiert auf CSS-Grid mit 2 Spalten, 2 Reihen.
- Live + Ratio-Chips links (80px fixe Breite, monospace)
- Dropdown + Buttons rechts
- Stat-Chip-Helper statChipStyle(accentTint): accentTint=true bei 100% match

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 23:22:12 +02:00
parent ea4c891b98
commit ea8292ed14
+48 -46
View File
@@ -560,10 +560,9 @@ export default function OberleisteApp() {
<div style={sep} /> <div style={sep} />
{/* ====== MASSSTAB 2-Reihen ====== {/* ====== MASSSTAB 2x2 ======
Links: Segmented-Pill mit 4 Tools (zentriert ueber beide Reihen) Reihe 1: [Aktueller Massstab] [Massstab-Dropdown (gruen wenn gesetzt)]
Rechts oben: Massstab-Dropdown (gesetzt = green) Reihe 2: [Zoom-Verhaeltnis %] [Buttons]
Rechts unten: Zoom-Verhaeltnis zum gesetzten Massstab (% Anzeige)
*/} */}
{(() => { {(() => {
const SegBtn = ({ icon, onClick, title, disabled, active, isFirst, isLast }) => ( const SegBtn = ({ icon, onClick, title, disabled, active, isFirst, isLast }) => (
@@ -582,8 +581,6 @@ export default function OberleisteApp() {
style={{ color: active ? 'var(--bg-panel)' : 'var(--text-muted)' }} /> style={{ color: active ? 'var(--bg-panel)' : 'var(--text-muted)' }} />
</button> </button>
) )
// Zoom-Verhaeltnis: setScale / liveScale → %
// 100% = perfekt am gesetzten Massstab; >100 = reingezoomt; <100 = rausgezoomt
const ratio = (!isPerspective && appliedScale && scaleVal) const ratio = (!isPerspective && appliedScale && scaleVal)
? appliedScale / scaleVal ? appliedScale / scaleVal
: null : null
@@ -593,33 +590,29 @@ export default function OberleisteApp() {
? Math.round(ratio * 100) + '%' ? Math.round(ratio * 100) + '%'
: (ratio * 100).toFixed(ratio < 0.1 ? 1 : 0) + '%' : (ratio * 100).toFixed(ratio < 0.1 ? 1 : 0) + '%'
const atScale = ratio != null && Math.abs(ratio - 1) < 0.005 const atScale = ratio != null && Math.abs(ratio - 1) < 0.005
const STAT_W = 80 // Breite der linken Stat-Chips (1:N / %)
const statChipStyle = (accentTint) => ({
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
height: BAR_H, width: STAT_W,
background: accentTint ? 'var(--accent-dim)' : 'var(--bg-input)',
color: accentTint ? 'var(--accent-light)' : 'var(--text-muted)',
border: '1px solid var(--border)',
borderRadius: 999,
fontFamily: 'DM Mono, monospace', fontSize: 11,
fontWeight: accentTint ? 600 : 500,
flexShrink: 0,
})
return ( return (
<div style={{ display: 'flex', gap: 6, alignItems: 'flex-start', flexShrink: 0 }}>
{/* Buttons-Pill — sitzt auf Reihe 1, vertikal zentriert ueber beide Reihen */}
<div style={{ <div style={{
display: 'inline-flex', alignSelf: 'center', display: 'grid', gridTemplateColumns: 'auto auto', gap: '4px 6px',
border: '1px solid var(--border)', borderRadius: 999, alignItems: 'center', flexShrink: 0,
overflow: 'hidden', flexShrink: 0,
}}> }}>
<SegBtn icon="percent" onClick={apply100} isFirst {/* Reihe 1, Spalte 1: Aktueller Live-Massstab */}
disabled={isPerspective || !appliedScale} <div style={statChipStyle(false)}
title={appliedScale ? `Zoom auf 1:${appliedScale} snappen` : 'Erst einen Massstab wählen'} /> title={isPerspective ? 'Perspektive — kein Massstab' : 'Aktueller Live-Massstab'}>
<SegBtn icon="fit_screen" onClick={zoomExtents} {isPerspective ? '—' : fmtScale(scaleVal)}
title="Auf gesamten Inhalt zoomen" />
<SegBtn icon="center_focus_strong" onClick={zoomSelection}
title="Auf Selektion zoomen" />
<SegBtn
icon={state.showLineweights ? 'print' : 'edit'}
active={state.showLineweights}
onClick={() => setShowLineweights(!state.showLineweights)}
isLast
title={state.showLineweights
? 'Print-View aktiv — klick zum Ausschalten'
: 'Strichstärken anzeigen (Print-View)'} />
</div> </div>
{/* Dropdown + Zoom-Ratio gestapelt */} {/* Reihe 1, Spalte 2: Gesetzter Massstab Dropdown */}
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
{/* Reihe 1: Set-Massstab Dropdown (grün wenn gesetzt) */}
{customMode ? ( {customMode ? (
<input <input
ref={customInputRef} ref={customInputRef}
@@ -664,25 +657,34 @@ export default function OberleisteApp() {
<option value="__custom__">Eigener</option> <option value="__custom__">Eigener</option>
</BarCombo> </BarCombo>
)} )}
{/* Reihe 2: Zoom-Verhaeltnis zum gesetzten Massstab. {/* Reihe 2, Spalte 1: Zoom-Verhaeltnis zum gesetzten Massstab */}
Aligned mit dem Pill (nicht mit dem Icon links davon). */} <div style={statChipStyle(atScale)}
<div style={{ display: 'flex', justifyContent: 'flex-end' }}> title={ratio != null
<div style={{ ? `Aktueller Zoom = ${ratioText} des gesetzten Massstabs`
display: 'inline-flex', alignItems: 'center', justifyContent: 'center', : (isPerspective ? 'Perspektive' : 'Kein Massstab gesetzt')}>
height: BAR_H, padding: '0 10px', minWidth: 140,
background: atScale ? 'var(--accent-dim)' : 'var(--bg-input)',
color: atScale ? 'var(--accent-light)' : 'var(--text-muted)',
border: '1px solid var(--border)',
borderRadius: 999,
fontFamily: 'DM Mono, monospace', fontSize: 11,
fontWeight: atScale ? 600 : 500,
flexShrink: 0,
}} title={ratio != null
? `Aktueller Zoom = ${ratioText} des gesetzten Massstabs (${atScale ? 'auf Massstab' : 'zoom mit % um zu snappen'})`
: (isPerspective ? 'Perspektive — kein Massstab' : 'Kein Massstab gesetzt')}>
{ratioText} {ratioText}
</div> </div>
</div> {/* Reihe 2, Spalte 2: Buttons-Pill */}
<div style={{
display: 'inline-flex',
border: '1px solid var(--border)', borderRadius: 999,
overflow: 'hidden', flexShrink: 0, justifySelf: 'start',
}}>
<SegBtn icon="percent" onClick={apply100} isFirst
disabled={isPerspective || !appliedScale}
title={appliedScale ? `Zoom auf 1:${appliedScale} snappen` : 'Erst einen Massstab wählen'} />
<SegBtn icon="fit_screen" onClick={zoomExtents}
title="Auf gesamten Inhalt zoomen" />
<SegBtn icon="center_focus_strong" onClick={zoomSelection}
title="Auf Selektion zoomen" />
<SegBtn
icon={state.showLineweights ? 'print' : 'edit'}
active={state.showLineweights}
onClick={() => setShowLineweights(!state.showLineweights)}
isLast
title={state.showLineweights
? 'Print-View aktiv — klick zum Ausschalten'
: 'Strichstärken anzeigen (Print-View)'} />
</div> </div>
</div> </div>
) )