@@ -52,9 +52,14 @@ struct ContentView: View {
5252 }
5353 // iPhone UX: Einfügemarke + Inspector einklappen beim Einfügen.
5454 @ State private var insertTarget : DiagramInsertTarget ? = nil
55- @ State private var hideInspectorOnPhone : Bool = false
55+ /// iPhone: Inspector startet eingeklappt, damit das Diagramm Platz hat.
56+ @ State private var hideInspectorOnPhone : Bool = true
5657 // iPhone UX: Palette automatisch einklappen beim Text-Editieren.
57- @ State private var showPaletteOnPhone : Bool = true
58+ /// iPhone: Palette als Sheet über dem Editor (statt fest über der Navigationsleiste).
59+ @ State private var showPaletteOnPhone : Bool = false
60+ /// iPhone: Diagrammtitel wird in einem kleinen Dialog bearbeitet statt in einem eigenen Feld über dem Diagramm.
61+ @ State private var showPhoneTitleEditor : Bool = false
62+ @ State private var phoneTitleDraft : String = " "
5863 // In-App Zwischenablage für Diagramm-Elemente (Copy/Cut/Paste).
5964 @ State private var elementClipboard : VisuStructElement ? = nil
6065 #if canImport( UIKit )
@@ -160,7 +165,7 @@ struct ContentView: View {
160165 . navigationSplitViewStyle ( . balanced )
161166 } else {
162167 VStack ( spacing : 0 ) {
163- if ! isPhone || showPaletteOnPhone {
168+ if ! isPhone {
164169 paletteListPanel
165170 . frame ( maxHeight : 300 , alignment : . top )
166171 . background ( Color ( . secondarySystemGroupedBackground ) )
@@ -170,6 +175,14 @@ struct ContentView: View {
170175 mainEditorNavigationStack
171176 . frame ( maxWidth : . infinity , maxHeight : . infinity )
172177 }
178+ . sheet ( isPresented : phonePaletteSheetBinding ) {
179+ paletteListPanel
180+ . environment ( \. appLanguage , lang )
181+ . presentationDetents ( [ . medium , . large ] )
182+ // Diagramm bleibt bedienbar, z. B. um eine Einfügestelle zu wählen.
183+ . presentationBackgroundInteraction ( . enabled ( upThrough : . medium ) )
184+ . presentationDragIndicator ( . visible )
185+ }
173186 }
174187 }
175188 #if canImport( UIKit )
@@ -329,6 +342,11 @@ struct ContentView: View {
329342 refreshLineEditor ( )
330343 DiagramCommandCenter . shared . update ( file : diagramFileActions , edit : diagramEditActions )
331344 }
345+ . onChange ( of : insertTarget ) { _ , newTarget in
346+ // iPhone: Einfügestelle gewählt → Palette öffnen, damit gleich ein Element gewählt werden kann.
347+ guard isPhone , newTarget != nil else { return }
348+ showPaletteOnPhone = true
349+ }
332350 . onChange ( of : focusedField ) { _ , newVal in
333351 // iPhone: Sobald Textbearbeitung startet, Palette einklappen für mehr Platz.
334352 guard isPhone else { return }
@@ -686,21 +704,25 @@ struct ContentView: View {
686704 let blockCorner : CGFloat = horizontalSizeClass == . regular ? 14 : 12
687705
688706 return VStack ( alignment : . leading , spacing : 0 ) {
689- VStack ( alignment : . leading , spacing : 8 ) {
690- Text ( lang . tr ( " diagram_title_label " ) )
691- . font ( horizontalSizeClass == . regular ? . caption : . subheadline )
692- . foregroundStyle ( . secondary )
693- TextField ( lang . tr ( " diagram_title_placeholder " ) , text : captionBinding )
694- . font ( horizontalSizeClass == . regular ? . subheadline : . body )
695- . textFieldStyle ( . roundedBorder )
696- . textInputAutocapitalization ( . never )
697- . autocorrectionDisabled ( true )
698- . focused ( $focusedField , equals : . caption )
707+ if isPhone {
708+ phoneCaptionRow
709+ } else {
710+ VStack ( alignment : . leading , spacing : 8 ) {
711+ Text ( lang . tr ( " diagram_title_label " ) )
712+ . font ( horizontalSizeClass == . regular ? . caption : . subheadline )
713+ . foregroundStyle ( . secondary )
714+ TextField ( lang . tr ( " diagram_title_placeholder " ) , text : captionBinding )
715+ . font ( horizontalSizeClass == . regular ? . subheadline : . body )
716+ . textFieldStyle ( . roundedBorder )
717+ . textInputAutocapitalization ( . never )
718+ . autocorrectionDisabled ( true )
719+ . focused ( $focusedField , equals : . caption )
720+ }
721+ . frame ( maxWidth : . infinity , alignment : . leading )
722+ . padding ( . horizontal , 14 )
723+ . padding ( . top , 8 )
724+ . padding ( . bottom , 6 )
699725 }
700- . frame ( maxWidth : . infinity , alignment : . leading )
701- . padding ( . horizontal , 14 )
702- . padding ( . top , 8 )
703- . padding ( . bottom , 6 )
704726 // Innerer Trennstrich — Titel zählt zum Diagramm-„Blatt“, nicht als losgelöster Bereich oberhalb.
705727 Rectangle ( )
706728 . fill ( Color . primary . opacity ( 0.1 ) )
@@ -740,6 +762,47 @@ struct ContentView: View {
740762 }
741763 }
742764
765+ /// iPhone: Titel als eine kompakte Zeile; Tippen öffnet einen Dialog zum Bearbeiten.
766+ private var phoneCaptionRow : some View {
767+ Button {
768+ phoneTitleDraft = document . caption
769+ showPhoneTitleEditor = true
770+ } label : {
771+ HStack ( spacing : 6 ) {
772+ Text ( document . caption . isEmpty ? lang . tr ( " diagram_title_placeholder " ) : document . caption )
773+ . font ( . subheadline . weight ( . semibold ) )
774+ . foregroundStyle ( document . caption . isEmpty ? . secondary : . primary )
775+ . lineLimit ( 1 )
776+ Image ( systemName : " pencil " )
777+ . font ( . caption )
778+ . foregroundStyle ( . secondary )
779+ }
780+ . frame ( maxWidth : . infinity , alignment : . leading )
781+ . contentShape ( Rectangle ( ) )
782+ }
783+ . buttonStyle ( . plain )
784+ . accessibilityLabel ( lang . tr ( " diagram_title_label " ) )
785+ . padding ( . horizontal , 14 )
786+ . padding ( . vertical , 8 )
787+ . alert ( lang . tr ( " diagram_title_label " ) , isPresented : $showPhoneTitleEditor ) {
788+ TextField ( lang . tr ( " diagram_title_placeholder " ) , text : $phoneTitleDraft )
789+ . textInputAutocapitalization ( . never )
790+ . autocorrectionDisabled ( true )
791+ Button ( lang . tr ( " phone_title_done " ) ) {
792+ if phoneTitleDraft != document . caption {
793+ captionBinding . wrappedValue = phoneTitleDraft
794+ }
795+ }
796+ }
797+ }
798+
799+ private var phonePaletteSheetBinding : Binding < Bool > {
800+ Binding (
801+ get : { isPhone && showPaletteOnPhone } ,
802+ set : { showPaletteOnPhone = $0 }
803+ )
804+ }
805+
743806 // MARK: - Bindings (Dokument, Caption)
744807
745808 private var documentBinding : Binding < VisuStructDocument > {
@@ -1073,7 +1136,11 @@ struct ContentView: View {
10731136 insertTargetActive : insertTarget != nil ,
10741137 hideInspectorOnPhone : hideInspectorOnPhone ,
10751138 onCancelInsert : { insertTarget = nil } ,
1076- onShowInspector : { hideInspectorOnPhone = false }
1139+ onShowInspector : { hideInspectorOnPhone = false } ,
1140+ onHideInspector : {
1141+ focusedField = nil
1142+ hideInspectorOnPhone = true
1143+ }
10771144 ) {
10781145 inspectorPanel
10791146 }
@@ -1336,6 +1403,7 @@ struct ContentView: View {
13361403 private func insertPaletteItem ( _ item : ElementPalette . PaletteItem ) {
13371404 if isPhone {
13381405 hideInspectorOnPhone = true
1406+ showPaletteOnPhone = false
13391407 }
13401408 let el = ElementPalette . element ( for : item , lang : lang )
13411409 let doc = document
0 commit comments