Layout: Befehlszeile in die Mitte-Spalte (nur Viewport-breit, Docks gewinnen Hoehe)

This commit is contained in:
2026-07-05 14:48:37 +02:00
parent c5b5ca600c
commit c794feef9e
2 changed files with 64 additions and 48 deletions
+52 -48
View File
@@ -3168,6 +3168,10 @@ export default function App() {
/> />
)} )}
{/* Mitte-Spalte: Hauptansicht + Befehlszeile DARUNTER. So ist die
Befehlszeile nur so breit wie der Viewport (nicht die ganze App),
und die Docks nehmen die volle Body-Höhe ein (inkl. der Zeile). */}
<div className="center-col">
{/* Hauptansicht (Mitte) — füllt den verbleibenden Platz. Die Plan- {/* Hauptansicht (Mitte) — füllt den verbleibenden Platz. Die Plan-
Ansicht meldet Cursor + Zoom an die Status-/Oberleiste und nimmt Ansicht meldet Cursor + Zoom an die Status-/Oberleiste und nimmt
das Zoom-Handle entgegen. */} das Zoom-Handle entgegen. */}
@@ -3232,6 +3236,54 @@ export default function App() {
onEdit3dWallTop={onEdit3dWallTop} onEdit3dWallTop={onEdit3dWallTop}
onEdit3dEnd={onEdit3dEnd} onEdit3dEnd={onEdit3dEnd}
/> />
{/* Command-Line (Rhino-artig) UNTER dem Viewport — nur Viewport-breit.
Prompt + klickbare Inline-Optionen + Texteingabe + Autocomplete. */}
<CommandLine
ref={commandLineRef}
// (c) Während eines Vertex-Griff-Drags belegt der Feld-Controller das
// Befehlsfeld (Länge/Winkel). Läuft eine Auswahl-Transformation (Drehen
// etc.), belegt sie Prompt + U/I/O/P + Winkel-/Distanzfeld. Sonst gilt die
// Engine (Zeichnen/Ruhe). Griff-Drag hat Vorrang (schließen sich sonst aus).
active={gripEdit ? true : activeTransform ? true : engineView.active}
promptKey={
gripEdit
? "cmd.edit.point"
: activeTransform
? `transform.hint.${activeTransform.op}.${Math.min(
activeTransform.points.length,
activeTransform.op === "rotate" ? 2 : 1,
)}`
: engineView.promptKey
}
options={gripEdit ? [] : activeTransform ? transformOptions() : engineView.options}
fields={
gripEdit ? gripEditFields() : activeTransform ? transformFields() : engineView.fields
}
onSubmit={(text) => {
if (gripEdit) {
const v = parseFloat(text.replace(",", "."));
if (isFinite(v)) submitGripEditValue(v);
return;
}
if (activeTransform) {
const v = parseFloat(text.replace(",", "."));
if (isFinite(v)) submitTransformValue(v);
return;
}
engine.submitText(text);
}}
onOption={(id) =>
activeTransform ? onTransformMode(id as CopyMode) : engine.chooseOption(id)
}
onCycleField={() =>
gripEdit ? cycleGripEditField() : activeTransform ? undefined : engine.cycleField()
}
onCancel={() =>
gripEdit ? setGripEdit(null) : activeTransform ? cancelTransform() : engine.cancel()
}
suggest={(prefix) => engine.suggest(prefix)}
/>
</div>
{/* Rechtes Dock: standardmäßig leer (Ressourcen ist ein schwebendes {/* Rechtes Dock: standardmäßig leer (Ressourcen ist ein schwebendes
Fenster). Nur gerendert, wenn es Gruppen hat — sonst nutzt die Mitte Fenster). Nur gerendert, wenn es Gruppen hat — sonst nutzt die Mitte
@@ -3300,54 +3352,6 @@ export default function App() {
{/* Drag-Overlay (Geist + Tab-Einfüge-Caret) während eines Tab-Ziehens. */} {/* Drag-Overlay (Geist + Tab-Einfüge-Caret) während eines Tab-Ziehens. */}
<DragOverlay drag={drag} /> <DragOverlay drag={drag} />
{/* Command-Line (Rhino-artig) ÜBER der Statusleiste: Prompt + klickbare
Inline-Optionen + Texteingabe + Autocomplete. Tab fokussiert sie. */}
<CommandLine
ref={commandLineRef}
// (c) Während eines Vertex-Griff-Drags belegt der Feld-Controller das
// Befehlsfeld (Länge/Winkel). Läuft eine Auswahl-Transformation (Drehen
// etc.), belegt sie Prompt + U/I/O/P + Winkel-/Distanzfeld. Sonst gilt die
// Engine (Zeichnen/Ruhe). Griff-Drag hat Vorrang (schließen sich sonst aus).
active={gripEdit ? true : activeTransform ? true : engineView.active}
promptKey={
gripEdit
? "cmd.edit.point"
: activeTransform
? `transform.hint.${activeTransform.op}.${Math.min(
activeTransform.points.length,
activeTransform.op === "rotate" ? 2 : 1,
)}`
: engineView.promptKey
}
options={gripEdit ? [] : activeTransform ? transformOptions() : engineView.options}
fields={
gripEdit ? gripEditFields() : activeTransform ? transformFields() : engineView.fields
}
onSubmit={(text) => {
if (gripEdit) {
const v = parseFloat(text.replace(",", "."));
if (isFinite(v)) submitGripEditValue(v);
return;
}
if (activeTransform) {
const v = parseFloat(text.replace(",", "."));
if (isFinite(v)) submitTransformValue(v);
return;
}
engine.submitText(text);
}}
onOption={(id) =>
activeTransform ? onTransformMode(id as CopyMode) : engine.chooseOption(id)
}
onCycleField={() =>
gripEdit ? cycleGripEditField() : activeTransform ? undefined : engine.cycleField()
}
onCancel={() =>
gripEdit ? setGripEdit(null) : activeTransform ? cancelTransform() : engine.cancel()
}
suggest={(prefix) => engine.suggest(prefix)}
/>
{/* Footer / Status-Leiste (unten). Werte rein aus Modell + View-State. {/* Footer / Status-Leiste (unten). Werte rein aus Modell + View-State.
Cursor/Zoom nur, wenn eine Plan-Ansicht aktiv ist (sonst „—"). */} Cursor/Zoom nur, wenn eine Plan-Ansicht aktiv ist (sonst „—"). */}
<StatusBar <StatusBar
+12
View File
@@ -1463,6 +1463,18 @@ body {
min-width: 0; min-width: 0;
} }
/* Mitte-Spalte: Viewport (.content) + Befehlszeile (.cmdline) darunter. Nimmt in
der horizontalen .body den Platz ZWISCHEN den Docks ein und stapelt vertikal
so ist die Befehlszeile nur so breit wie der Viewport, und die Docks reichen
über die volle Body-Höhe (inkl. der Befehlszeilen-Zeile). */
.center-col {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
min-height: 0;
}
/* Dokument-Tabs Zeichnungen/Blätter" Kopfzeile über der Zeichenfläche. /* Dokument-Tabs Zeichnungen/Blätter" Kopfzeile über der Zeichenfläche.
Leiste auf Ebene 1 (--panel), der aktive Tab hebt sich auf Ebene 2 an und Leiste auf Ebene 1 (--panel), der aktive Tab hebt sich auf Ebene 2 an und
verschmilzt unten mit dem Grund der Zeichenfläche darunter (--bg), wie bei verschmilzt unten mit dem Grund der Zeichenfläche darunter (--bg), wie bei