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