Use full-width editor device drawer

This commit is contained in:
2026-07-28 20:43:08 +02:00
parent feec814dc5
commit edf245a21c
4 changed files with 88 additions and 11 deletions
+6
View File
@@ -167,6 +167,12 @@ Felder und vollständiger Zeilenbestand unverändert sind.
Der Editor erzeugt die vollständigen Move-Zuweisungen aus dem geladenen Tree,
vergibt für neue Ziele vor dem Kommando eine stabile UUID und führt das
Toolbar-Undo/Redo über die projektweite Historie aus.
Die Projektgerätepalette belegt keine permanente Layoutspalte mehr. Sie wird
über die Editor-Toolbar als überlagernder Drawer geöffnet, während das
Stromkreis-Grid standardmäßig die gesamte verfügbare Breite nutzt. Auswahl,
Schnelleinfügen und die vorhandenen Drag-and-drop-Payloads bleiben im Drawer
unverändert verfügbar; während eines aktiven Projektgeräte-Drags kann er nicht
geschlossen werden.
`circuit.reorder-section` speichert die erwartete und neue Sortierposition
jedes Stromkreises eines vollständigen Abschnitts. Forward, Undo und Redo
ändern ausschließlich `sortOrder`; Stromkreisblöcke, Gerätezeilen und BMKs
+45 -7
View File
@@ -71,6 +71,13 @@ body {
opacity: 0.45;
}
.editor-toolbar .project-device-drawer-toggle {
border-color: #2563eb;
background: #2563eb;
color: #fff;
font-weight: 600;
}
.active-view-summary {
display: flex;
flex-wrap: wrap;
@@ -271,12 +278,10 @@ body {
}
.tree-editor-layout {
display: grid;
grid-template-columns: minmax(240px, 320px) minmax(0, 1fr);
gap: 0.75rem;
display: block;
min-height: 560px;
min-width: 0;
align-items: start;
position: relative;
}
.project-device-sidebar {
@@ -404,6 +409,38 @@ body {
cursor: pointer;
}
.project-device-drawer {
position: fixed;
z-index: 1040;
top: 5.5rem;
left: 1rem;
width: min(360px, calc(100vw - 2rem));
max-height: calc(100vh - 7rem);
overflow: auto;
border-radius: 0.5rem;
box-shadow: 0 0.75rem 2rem rgba(31, 41, 55, 0.22);
}
.project-device-drawer-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 0.75rem;
}
.project-device-drawer-header span {
color: #6b7280;
font-size: 0.75rem;
}
.project-device-drawer-header button {
border: 1px solid #c4cddc;
background: #fff;
border-radius: 4px;
padding: 0.25rem 0.4rem;
font-size: 0.78rem;
}
.tree-grid .header-sort-btn:hover span:first-child,
.tree-grid .header-sort-btn:focus-visible span:first-child {
text-decoration: underline;
@@ -783,8 +820,9 @@ body {
margin: 0;
}
@media (max-width: 1200px) {
.tree-editor-layout {
grid-template-columns: 1fr;
@media (max-width: 720px) {
.project-device-drawer {
top: 4.5rem;
max-height: calc(100vh - 5.5rem);
}
}
@@ -8,8 +8,8 @@ export default function CircuitTreeEditPage() {
const params = useParams<{ projectId: string; circuitListId: string }>();
return (
<main className="container py-4">
<div className="d-flex justify-content-between align-items-center mb-3">
<main className="container-fluid px-3 px-xxl-4 py-4">
<div className="d-flex flex-wrap justify-content-between align-items-center gap-3 mb-3">
<div>
<h1 className="h4 mb-1">Stromkreisliste</h1>
<p className="text-secondary mb-0">Stromkreise und zugeordnete Geräte bearbeiten.</p>
@@ -196,6 +196,8 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
const [activeSectionId, setActiveSectionId] = useState<string | null>(null);
const [isSaving, setIsSaving] = useState(false);
const [projectDevices, setProjectDevices] = useState<ProjectDeviceDto[]>([]);
const [isProjectDeviceDrawerOpen, setIsProjectDeviceDrawerOpen] =
useState(false);
const [projectDeviceSearch, setProjectDeviceSearch] = useState("");
const [selectedProjectDeviceId, setSelectedProjectDeviceId] = useState<string | null>(null);
const [targetSectionId, setTargetSectionId] = useState<string | null>(null);
@@ -2537,6 +2539,19 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
<button type="button" onClick={toggleColumnSettingsMenu} aria-expanded={isColumnMenuOpen}>
Spalten
</button>
<button
aria-controls="project-device-drawer"
aria-expanded={isProjectDeviceDrawerOpen}
className="project-device-drawer-toggle"
type="button"
onClick={() =>
setIsProjectDeviceDrawerOpen((current) => !current)
}
>
{isProjectDeviceDrawerOpen
? "Projektgeräte schließen"
: `Projektgeräte öffnen (${projectDevices.length})`}
</button>
<button
type="button"
onClick={clearSortAndFilters}
@@ -2566,8 +2581,25 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
) : null}
{isSaving ? <div className="notice info">Wird gespeichert </div> : null}
<div className="tree-editor-layout">
<aside className="project-device-sidebar">
<h3>Projektgeräte</h3>
{isProjectDeviceDrawerOpen ? (
<aside
className="project-device-sidebar project-device-drawer"
id="project-device-drawer"
>
<div className="project-device-drawer-header">
<div>
<h3>Projektgeräte</h3>
<span>{projectDevices.length} verfügbar</span>
</div>
<button
aria-label="Projektgeräte schließen"
disabled={draggingProjectDeviceId !== null}
onClick={() => setIsProjectDeviceDrawerOpen(false)}
type="button"
>
Schließen
</button>
</div>
<input
type="text"
placeholder="Name oder Anzeigename suchen …"
@@ -2668,6 +2700,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
</button>
</div>
</aside>
) : null}
<div
className="tree-grid-wrap"
ref={containerRef}