Massstab: Dropdown (gruen) oben, Zoom-Verhaeltnis unten
User-Wunsch: ueber dem aktuellen Live-Zoom soll der gesetzte Massstab in gruen oben sein, unten das Verhaeltnis des aktuellen Zooms zum gesetzten. Layout: - Buttons-Pill links (vertikal zentriert ueber beide Reihen) - Rechts oben: Massstab-Dropdown — BarCombo mit neuem valueAccent prop, faerbt Select-Text in accent-light + bold wenn ein Massstab gesetzt ist - Rechts unten: Zoom-Ratio-Chip (% des gesetzten Massstabs). 100% = at-scale → accent-dim Hintergrund + accent-light Text. <100% = rausgezoomt, >100% = reingezoomt → bg-input + muted text. Ratio-Formel: appliedScale / liveScale * 100. - 1:50 gesetzt, live 1:50 → 100% (exakt, accent) - 1:50 gesetzt, live 1:100 → 50% (rausgezoomt) - 1:50 gesetzt, live 1:25 → 200% (reingezoomt) Per Klick auf das "%" Button (Reihe 1) snappt der Zoom auf 100%. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+46
-26
@@ -128,10 +128,11 @@ function BarSelect({ icon, value, onChange, title, disabled, width, children, jo
|
|||||||
// BarCombo: dunklerer (bg-input) Pill-Container der select + optional gear
|
// BarCombo: dunklerer (bg-input) Pill-Container der select + optional gear
|
||||||
// als EINE nahtlose Box rendert. Icon roh links daneben (kein Container).
|
// als EINE nahtlose Box rendert. Icon roh links daneben (kein Container).
|
||||||
// iconClickable=true macht das Icon zum Toggle-Button (Overrides etc.).
|
// iconClickable=true macht das Icon zum Toggle-Button (Overrides etc.).
|
||||||
|
// valueAccent=true faerbt den Select-Text accent (fuer Massstab "gesetzt").
|
||||||
function BarCombo({
|
function BarCombo({
|
||||||
icon, iconActive, iconClickable, onIconClick, iconTitle,
|
icon, iconActive, iconClickable, onIconClick, iconTitle,
|
||||||
value, onChange, width, title, children, disabled,
|
value, onChange, width, title, children, disabled,
|
||||||
onGear, gearTitle,
|
onGear, gearTitle, valueAccent,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
@@ -173,10 +174,12 @@ function BarCombo({
|
|||||||
onChange={(e) => onChange(e.target.value)}
|
onChange={(e) => onChange(e.target.value)}
|
||||||
style={{
|
style={{
|
||||||
flex: 1, minWidth: 0,
|
flex: 1, minWidth: 0,
|
||||||
background: 'transparent', color: 'var(--text-primary)',
|
background: 'transparent',
|
||||||
|
color: valueAccent ? 'var(--accent-light)' : 'var(--text-primary)',
|
||||||
border: 'none', outline: 'none',
|
border: 'none', outline: 'none',
|
||||||
padding: '0 22px 0 12px',
|
padding: '0 22px 0 12px',
|
||||||
fontSize: 11, fontFamily: 'var(--font)',
|
fontSize: 11, fontFamily: 'var(--font)',
|
||||||
|
fontWeight: valueAccent ? 600 : 500,
|
||||||
appearance: 'none', WebkitAppearance: 'none',
|
appearance: 'none', WebkitAppearance: 'none',
|
||||||
backgroundImage: 'var(--select-arrow)',
|
backgroundImage: 'var(--select-arrow)',
|
||||||
backgroundRepeat: 'no-repeat',
|
backgroundRepeat: 'no-repeat',
|
||||||
@@ -558,11 +561,11 @@ export default function OberleisteApp() {
|
|||||||
<div style={sep} />
|
<div style={sep} />
|
||||||
|
|
||||||
{/* ====== MASSSTAB 2-Reihen ======
|
{/* ====== MASSSTAB 2-Reihen ======
|
||||||
Oben: Segmented-Pill mit 4 Tools (%, fit, center, print/edit)
|
Links: Segmented-Pill mit 4 Tools (zentriert ueber beide Reihen)
|
||||||
Unten: Live-Zoom-Chip + Dropdown
|
Rechts oben: Massstab-Dropdown (gesetzt = green)
|
||||||
|
Rechts unten: Zoom-Verhaeltnis zum gesetzten Massstab (% Anzeige)
|
||||||
*/}
|
*/}
|
||||||
{(() => {
|
{(() => {
|
||||||
// Segmented button — sitzt nahtlos in einer Pill mit den anderen
|
|
||||||
const SegBtn = ({ icon, onClick, title, disabled, active, isFirst, isLast }) => (
|
const SegBtn = ({ icon, onClick, title, disabled, active, isFirst, isLast }) => (
|
||||||
<button onClick={onClick} disabled={disabled} title={title}
|
<button onClick={onClick} disabled={disabled} title={title}
|
||||||
style={{
|
style={{
|
||||||
@@ -579,14 +582,22 @@ 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)
|
||||||
|
? appliedScale / scaleVal
|
||||||
|
: null
|
||||||
|
const ratioText = ratio == null
|
||||||
|
? '—'
|
||||||
|
: ratio >= 1
|
||||||
|
? Math.round(ratio * 100) + '%'
|
||||||
|
: (ratio * 100).toFixed(ratio < 0.1 ? 1 : 0) + '%'
|
||||||
|
const atScale = ratio != null && Math.abs(ratio - 1) < 0.005
|
||||||
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: 'flex', flexDirection: 'column', gap: 4,
|
display: 'inline-flex', alignSelf: 'center',
|
||||||
flexShrink: 0,
|
|
||||||
}}>
|
|
||||||
{/* Reihe 1: Segmented Pill mit 4 Tools */}
|
|
||||||
<div style={{
|
|
||||||
display: 'inline-flex', alignSelf: 'flex-start',
|
|
||||||
border: '1px solid var(--border)', borderRadius: 999,
|
border: '1px solid var(--border)', borderRadius: 999,
|
||||||
overflow: 'hidden', flexShrink: 0,
|
overflow: 'hidden', flexShrink: 0,
|
||||||
}}>
|
}}>
|
||||||
@@ -606,20 +617,9 @@ export default function OberleisteApp() {
|
|||||||
? 'Print-View aktiv — klick zum Ausschalten'
|
? 'Print-View aktiv — klick zum Ausschalten'
|
||||||
: 'Strichstärken anzeigen (Print-View)'} />
|
: 'Strichstärken anzeigen (Print-View)'} />
|
||||||
</div>
|
</div>
|
||||||
{/* Reihe 2: Live-Zoom + Dropdown */}
|
{/* Dropdown + Zoom-Ratio gestapelt */}
|
||||||
<div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
|
||||||
<div style={{
|
{/* Reihe 1: Set-Massstab Dropdown (grün wenn gesetzt) */}
|
||||||
display: 'inline-flex', alignItems: 'center',
|
|
||||||
height: BAR_H, padding: '0 10px',
|
|
||||||
background: isPerspective ? 'var(--bg-input)' : 'var(--accent)',
|
|
||||||
color: isPerspective ? 'var(--text-muted)' : 'var(--bg-panel)',
|
|
||||||
border: '1px solid var(--border)',
|
|
||||||
borderRadius: 999,
|
|
||||||
fontFamily: 'DM Mono, monospace', fontSize: 11, fontWeight: 600,
|
|
||||||
minWidth: 60, justifyContent: 'center', flexShrink: 0,
|
|
||||||
}} title="Live-Zoom">
|
|
||||||
{isPerspective ? '—' : fmtScale(scaleVal)}
|
|
||||||
</div>
|
|
||||||
{customMode ? (
|
{customMode ? (
|
||||||
<input
|
<input
|
||||||
ref={customInputRef}
|
ref={customInputRef}
|
||||||
@@ -633,7 +633,7 @@ export default function OberleisteApp() {
|
|||||||
}}
|
}}
|
||||||
onBlur={applyDraft}
|
onBlur={applyDraft}
|
||||||
style={{
|
style={{
|
||||||
height: BAR_H, width: 100,
|
height: BAR_H, width: 158,
|
||||||
background: 'var(--bg-input)',
|
background: 'var(--bg-input)',
|
||||||
color: 'var(--text-primary)',
|
color: 'var(--text-primary)',
|
||||||
border: '1px solid var(--border)',
|
border: '1px solid var(--border)',
|
||||||
@@ -651,6 +651,7 @@ export default function OberleisteApp() {
|
|||||||
onChange={(v) => applyDropdown(v)}
|
onChange={(v) => applyDropdown(v)}
|
||||||
disabled={isPerspective}
|
disabled={isPerspective}
|
||||||
width={140}
|
width={140}
|
||||||
|
valueAccent={appliedScale != null}
|
||||||
title="Gesetzter Massstab"
|
title="Gesetzter Massstab"
|
||||||
>
|
>
|
||||||
<option value="__none__">—</option>
|
<option value="__none__">—</option>
|
||||||
@@ -663,6 +664,25 @@ export default function OberleisteApp() {
|
|||||||
<option value="__custom__">Eigener…</option>
|
<option value="__custom__">Eigener…</option>
|
||||||
</BarCombo>
|
</BarCombo>
|
||||||
)}
|
)}
|
||||||
|
{/* Reihe 2: Zoom-Verhaeltnis zum gesetzten Massstab.
|
||||||
|
Aligned mit dem Pill (nicht mit dem Icon links davon). */}
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||||
|
<div style={{
|
||||||
|
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
|
||||||
|
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}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user