Massstab: Pills gleich breit + Icon weg + weisse Texte + Hover-Akzent
User-Wunsch: - Aktueller Massstab (live) + Zoom-% weiss, accent bei 100% - Dropdown immer weiss (kein valueAccent mehr) - Buttons unten wie View-Toggle (weiss default, gruen on hover) - Massstabs-Icon weg, Pills (Dropdown + Buttons-Bar) gleich breit + exakt uebereinander Aenderungen: - BarCombo: Icon-Slot nur wenn `icon` truthy gerendert (kein leerer Slot) - Massstab-Dropdown ohne icon-Prop → kein 18px Slot links, Pill sitzt direkt in der Grid-Zelle - PILL_W=140 für Dropdown UND Buttons-Pill, jeder Button BTN_W=35 - statChipStyle: color text-primary (weiss) statt text-muted, accent-light nur bei atScale=true - valueAccent prop entfernt aus Massstab-Dropdown - SegBtn mit Hover-Logik analog View-Toggle: bg → bg-item-hover, color → accent-light, active bleibt accent-fill Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+34
-18
@@ -139,8 +139,9 @@ function BarCombo({
|
|||||||
display: 'inline-flex', alignItems: 'center', gap: 5,
|
display: 'inline-flex', alignItems: 'center', gap: 5,
|
||||||
opacity: disabled ? 0.5 : 1, flexShrink: 0,
|
opacity: disabled ? 0.5 : 1, flexShrink: 0,
|
||||||
}}>
|
}}>
|
||||||
{/* Icon links — fixe Breite fuer X-Axis-Alignment zwischen Reihen */}
|
{/* Icon links — fixe Breite fuer X-Axis-Alignment zwischen Reihen.
|
||||||
{iconClickable ? (
|
Wenn icon=null/undefined wird kein Icon-Slot reserviert. */}
|
||||||
|
{icon && (iconClickable ? (
|
||||||
<button onClick={onIconClick} title={iconTitle}
|
<button onClick={onIconClick} title={iconTitle}
|
||||||
style={{
|
style={{
|
||||||
width: 18, height: BAR_H,
|
width: 18, height: BAR_H,
|
||||||
@@ -158,7 +159,7 @@ function BarCombo({
|
|||||||
}}>
|
}}>
|
||||||
<Icon name={icon} size={13} style={{ color: 'var(--text-muted)' }} />
|
<Icon name={icon} size={13} style={{ color: 'var(--text-muted)' }} />
|
||||||
</span>
|
</span>
|
||||||
)}
|
))}
|
||||||
{/* Combined pill: select + optional gear, gemeinsamer bg + border */}
|
{/* Combined pill: select + optional gear, gemeinsamer bg + border */}
|
||||||
<div title={title}
|
<div title={title}
|
||||||
onMouseEnter={(e) => {
|
onMouseEnter={(e) => {
|
||||||
@@ -601,20 +602,36 @@ export default function OberleisteApp() {
|
|||||||
Reihe 2: [Zoom-Verhaeltnis %] [Buttons]
|
Reihe 2: [Zoom-Verhaeltnis %] [Buttons]
|
||||||
*/}
|
*/}
|
||||||
{(() => {
|
{(() => {
|
||||||
|
// Buttons-Pill: gleiche Logik wie View-Toggle (weiss default,
|
||||||
|
// grün on hover, accent-fill wenn active)
|
||||||
|
const PILL_W = 140 // Gleiche Breite fuer Dropdown + Buttons-Pill
|
||||||
|
const N_BTN = 4
|
||||||
|
const BTN_W = Math.floor(PILL_W / N_BTN) // jeder Button gleich breit
|
||||||
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}
|
||||||
|
onMouseEnter={(e) => {
|
||||||
|
if (disabled || active) return
|
||||||
|
e.currentTarget.style.background = 'var(--bg-item-hover)'
|
||||||
|
e.currentTarget.style.color = 'var(--accent-light)'
|
||||||
|
}}
|
||||||
|
onMouseLeave={(e) => {
|
||||||
|
if (active) return
|
||||||
|
e.currentTarget.style.background = 'var(--bg-input)'
|
||||||
|
e.currentTarget.style.color = 'var(--text-primary)'
|
||||||
|
}}
|
||||||
style={{
|
style={{
|
||||||
height: BAR_H, width: 30,
|
height: BAR_H, width: BTN_W,
|
||||||
background: active ? 'var(--accent)' : 'var(--bg-input)',
|
background: active ? 'var(--accent)' : 'var(--bg-input)',
|
||||||
|
color: active ? 'var(--bg-panel)' : 'var(--text-primary)',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
borderLeft: isFirst ? 'none' : '1px solid var(--border)',
|
borderLeft: isFirst ? 'none' : '1px solid var(--border)',
|
||||||
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
|
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
|
||||||
cursor: disabled ? 'not-allowed' : 'pointer',
|
cursor: disabled ? 'not-allowed' : 'pointer',
|
||||||
opacity: disabled ? 0.4 : 1, flexShrink: 0,
|
opacity: disabled ? 0.4 : 1, flexShrink: 0,
|
||||||
padding: 0,
|
padding: 0,
|
||||||
|
transition: 'background 0.15s, color 0.15s',
|
||||||
}}>
|
}}>
|
||||||
<Icon name={icon} size={13}
|
<Icon name={icon} size={13} />
|
||||||
style={{ color: active ? 'var(--bg-panel)' : 'var(--text-muted)' }} />
|
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
const ratio = (!isPerspective && appliedScale && scaleVal)
|
const ratio = (!isPerspective && appliedScale && scaleVal)
|
||||||
@@ -626,12 +643,12 @@ 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 STAT_W = 70 // Breite der linken Stat-Chips
|
||||||
const statChipStyle = (accentTint) => ({
|
const statChipStyle = (accentTint) => ({
|
||||||
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
|
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
|
||||||
height: BAR_H, width: STAT_W,
|
height: BAR_H, width: STAT_W,
|
||||||
background: accentTint ? 'var(--accent-dim)' : 'var(--bg-input)',
|
background: accentTint ? 'var(--accent-dim)' : 'var(--bg-input)',
|
||||||
color: accentTint ? 'var(--accent-light)' : 'var(--text-muted)',
|
color: accentTint ? 'var(--accent-light)' : 'var(--text-primary)',
|
||||||
border: '1px solid var(--border)',
|
border: '1px solid var(--border)',
|
||||||
borderRadius: 999,
|
borderRadius: 999,
|
||||||
fontFamily: 'DM Mono, monospace', fontSize: 11,
|
fontFamily: 'DM Mono, monospace', fontSize: 11,
|
||||||
@@ -643,12 +660,13 @@ export default function OberleisteApp() {
|
|||||||
display: 'grid', gridTemplateColumns: 'auto auto', gap: '4px 6px',
|
display: 'grid', gridTemplateColumns: 'auto auto', gap: '4px 6px',
|
||||||
alignItems: 'center', flexShrink: 0,
|
alignItems: 'center', flexShrink: 0,
|
||||||
}}>
|
}}>
|
||||||
{/* Reihe 1, Spalte 1: Aktueller Live-Massstab */}
|
{/* Reihe 1, Spalte 1: Aktueller Live-Massstab — weiss, accent bei 100% */}
|
||||||
<div style={statChipStyle(false)}
|
<div style={statChipStyle(atScale)}
|
||||||
title={isPerspective ? 'Perspektive — kein Massstab' : 'Aktueller Live-Massstab'}>
|
title={isPerspective ? 'Perspektive — kein Massstab' : 'Aktueller Live-Massstab'}>
|
||||||
{isPerspective ? '—' : fmtScale(scaleVal)}
|
{isPerspective ? '—' : fmtScale(scaleVal)}
|
||||||
</div>
|
</div>
|
||||||
{/* Reihe 1, Spalte 2: Gesetzter Massstab Dropdown */}
|
{/* Reihe 1, Spalte 2: Gesetzter Massstab Dropdown — KEIN Icon, gleiche
|
||||||
|
Breite wie Buttons-Pill darunter, exakt uebereinander */}
|
||||||
{customMode ? (
|
{customMode ? (
|
||||||
<input
|
<input
|
||||||
ref={customInputRef}
|
ref={customInputRef}
|
||||||
@@ -662,7 +680,7 @@ export default function OberleisteApp() {
|
|||||||
}}
|
}}
|
||||||
onBlur={applyDraft}
|
onBlur={applyDraft}
|
||||||
style={{
|
style={{
|
||||||
height: BAR_H, width: 158,
|
height: BAR_H, width: PILL_W,
|
||||||
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)',
|
||||||
@@ -675,12 +693,10 @@ export default function OberleisteApp() {
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<BarCombo
|
<BarCombo
|
||||||
icon="straighten"
|
|
||||||
value={dropdownValue}
|
value={dropdownValue}
|
||||||
onChange={(v) => applyDropdown(v)}
|
onChange={(v) => applyDropdown(v)}
|
||||||
disabled={isPerspective}
|
disabled={isPerspective}
|
||||||
width={140}
|
width={PILL_W}
|
||||||
valueAccent={appliedScale != null}
|
|
||||||
title="Gesetzter Massstab"
|
title="Gesetzter Massstab"
|
||||||
>
|
>
|
||||||
<option value="__none__">—</option>
|
<option value="__none__">—</option>
|
||||||
@@ -693,16 +709,16 @@ export default function OberleisteApp() {
|
|||||||
<option value="__custom__">Eigener…</option>
|
<option value="__custom__">Eigener…</option>
|
||||||
</BarCombo>
|
</BarCombo>
|
||||||
)}
|
)}
|
||||||
{/* Reihe 2, Spalte 1: Zoom-Verhaeltnis zum gesetzten Massstab */}
|
{/* Reihe 2, Spalte 1: Zoom-Verhaeltnis */}
|
||||||
<div style={statChipStyle(atScale)}
|
<div style={statChipStyle(atScale)}
|
||||||
title={ratio != null
|
title={ratio != null
|
||||||
? `Aktueller Zoom = ${ratioText} des gesetzten Massstabs`
|
? `Aktueller Zoom = ${ratioText} des gesetzten Massstabs`
|
||||||
: (isPerspective ? 'Perspektive' : 'Kein Massstab gesetzt')}>
|
: (isPerspective ? 'Perspektive' : 'Kein Massstab gesetzt')}>
|
||||||
{ratioText}
|
{ratioText}
|
||||||
</div>
|
</div>
|
||||||
{/* Reihe 2, Spalte 2: Buttons-Pill */}
|
{/* Reihe 2, Spalte 2: Buttons-Pill — gleiche Breite wie Dropdown */}
|
||||||
<div style={{
|
<div style={{
|
||||||
display: 'inline-flex',
|
display: 'inline-flex', width: PILL_W,
|
||||||
border: '1px solid var(--border)', borderRadius: 999,
|
border: '1px solid var(--border)', borderRadius: 999,
|
||||||
overflow: 'hidden', flexShrink: 0, justifySelf: 'start',
|
overflow: 'hidden', flexShrink: 0, justifySelf: 'start',
|
||||||
}}>
|
}}>
|
||||||
|
|||||||
Reference in New Issue
Block a user