Satelliten-Dialoge: embedded-Mode + GeschossDialog auch als echtes Fenster

Zwei Dinge:

1. embedded-Mode in den Dialog-Komponenten — wenn TRUE, kein Backdrop +
   keine MaxWidth-Constraint, das Dialog fuellt das ganze WebView statt
   wie ein kleines zentriertes Fenster IN dem WebView gerendert zu werden
   (= "Fenster im Fenster"-Effekt). Betroffen:
   - GeschossSettingsDialog
   - EbenenSettingsDialog
   - GeschossDialog
   Satelliten-Apps (GeschossSettingsApp, EbenenSettingsApp,
   GeschossDialogApp) passen jetzt `embedded` durch.

2. GeschossDialog (= der grosse Mehrfach-Editor hinter dem Pencil-Button)
   laeuft jetzt auch als Satelliten-Fenster — selbe Architektur wie die
   Settings-Dialoge. Backend hat neuen Handler _open_geschoss_dialog und
   neuen Message OPEN_GESCHOSS_DIALOG. Auf Save: ganze z-Liste replace
   + _apply(save_z=True).

GeschossManager braucht den inline-Dialog-State nicht mehr; Pencil-Button
ruft openGeschossDialog(zeichnungsebenen).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 01:30:28 +02:00
parent 1ba0bda429
commit b1b2090b3e
10 changed files with 184 additions and 94 deletions
+32 -17
View File
@@ -35,7 +35,7 @@ function Toggle({ label, checked, onChange, hint }) {
)
}
export default function GeschossSettingsDialog({ geschoss, onSave, onClose }) {
export default function GeschossSettingsDialog({ geschoss, onSave, onClose, embedded = false }) {
const [draft, setDraft] = useState({ ...geschoss })
const set = (patch) => setDraft({ ...draft, ...patch })
@@ -46,22 +46,37 @@ export default function GeschossSettingsDialog({ geschoss, onSave, onClose }) {
const okff = draft.okff ?? 0
const clipZ = (okff + schnitt).toFixed(2)
// embedded=true: in einem Satelliten-Fenster gerendert — kein Backdrop,
// keine Width-Constraint, fuellt das ganze WebView.
const Wrapper = embedded ? 'div' : 'div'
const wrapperStyle = embedded ? {
width: '100%', height: '100%',
background: 'var(--bg-dialog)',
display: 'flex', flexDirection: 'column',
overflow: 'hidden',
} : {
position: 'absolute', inset: 0, zIndex: 150,
background: 'var(--bg-overlay)',
display: 'flex', alignItems: 'flex-start', justifyContent: 'center',
paddingTop: 30,
}
const innerStyle = embedded ? {
width: '100%', height: '100%',
display: 'flex', flexDirection: 'column',
overflow: 'hidden',
} : {
background: 'var(--bg-dialog)',
border: '1px solid var(--border)',
borderRadius: 'var(--r-lg)',
boxShadow: 'var(--shadow-3)',
width: 'calc(100% - 16px)', maxWidth: 280,
display: 'flex', flexDirection: 'column',
overflow: 'hidden',
}
return (
<div style={{
position: 'absolute', inset: 0, zIndex: 150,
background: 'var(--bg-overlay)',
display: 'flex', alignItems: 'flex-start', justifyContent: 'center',
paddingTop: 30,
}}>
<div style={{
background: 'var(--bg-dialog)',
border: '1px solid var(--border)',
borderRadius: 'var(--r-lg)',
boxShadow: 'var(--shadow-3)',
width: 'calc(100% - 16px)', maxWidth: 280,
display: 'flex', flexDirection: 'column',
overflow: 'hidden',
}}>
<Wrapper style={wrapperStyle}>
<div style={innerStyle}>
{/* Header */}
<div style={{
display: 'flex', alignItems: 'center', gap: 6,
@@ -155,6 +170,6 @@ export default function GeschossSettingsDialog({ geschoss, onSave, onClose }) {
}}>Übernehmen</button>
</div>
</div>
</div>
</Wrapper>
)
}