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, 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 vergibt für neue Ziele vor dem Kommando eine stabile UUID und führt das
Toolbar-Undo/Redo über die projektweite Historie aus. 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 `circuit.reorder-section` speichert die erwartete und neue Sortierposition
jedes Stromkreises eines vollständigen Abschnitts. Forward, Undo und Redo jedes Stromkreises eines vollständigen Abschnitts. Forward, Undo und Redo
ändern ausschließlich `sortOrder`; Stromkreisblöcke, Gerätezeilen und BMKs ändern ausschließlich `sortOrder`; Stromkreisblöcke, Gerätezeilen und BMKs
+45 -7
View File
@@ -71,6 +71,13 @@ body {
opacity: 0.45; opacity: 0.45;
} }
.editor-toolbar .project-device-drawer-toggle {
border-color: #2563eb;
background: #2563eb;
color: #fff;
font-weight: 600;
}
.active-view-summary { .active-view-summary {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@@ -271,12 +278,10 @@ body {
} }
.tree-editor-layout { .tree-editor-layout {
display: grid; display: block;
grid-template-columns: minmax(240px, 320px) minmax(0, 1fr);
gap: 0.75rem;
min-height: 560px; min-height: 560px;
min-width: 0; min-width: 0;
align-items: start; position: relative;
} }
.project-device-sidebar { .project-device-sidebar {
@@ -404,6 +409,38 @@ body {
cursor: pointer; 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:hover span:first-child,
.tree-grid .header-sort-btn:focus-visible span:first-child { .tree-grid .header-sort-btn:focus-visible span:first-child {
text-decoration: underline; text-decoration: underline;
@@ -783,8 +820,9 @@ body {
margin: 0; margin: 0;
} }
@media (max-width: 1200px) { @media (max-width: 720px) {
.tree-editor-layout { .project-device-drawer {
grid-template-columns: 1fr; top: 4.5rem;
max-height: calc(100vh - 5.5rem);
} }
} }
@@ -8,8 +8,8 @@ export default function CircuitTreeEditPage() {
const params = useParams<{ projectId: string; circuitListId: string }>(); const params = useParams<{ projectId: string; circuitListId: string }>();
return ( return (
<main className="container py-4"> <main className="container-fluid px-3 px-xxl-4 py-4">
<div className="d-flex justify-content-between align-items-center mb-3"> <div className="d-flex flex-wrap justify-content-between align-items-center gap-3 mb-3">
<div> <div>
<h1 className="h4 mb-1">Stromkreisliste</h1> <h1 className="h4 mb-1">Stromkreisliste</h1>
<p className="text-secondary mb-0">Stromkreise und zugeordnete Geräte bearbeiten.</p> <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 [activeSectionId, setActiveSectionId] = useState<string | null>(null);
const [isSaving, setIsSaving] = useState(false); const [isSaving, setIsSaving] = useState(false);
const [projectDevices, setProjectDevices] = useState<ProjectDeviceDto[]>([]); const [projectDevices, setProjectDevices] = useState<ProjectDeviceDto[]>([]);
const [isProjectDeviceDrawerOpen, setIsProjectDeviceDrawerOpen] =
useState(false);
const [projectDeviceSearch, setProjectDeviceSearch] = useState(""); const [projectDeviceSearch, setProjectDeviceSearch] = useState("");
const [selectedProjectDeviceId, setSelectedProjectDeviceId] = useState<string | null>(null); const [selectedProjectDeviceId, setSelectedProjectDeviceId] = useState<string | null>(null);
const [targetSectionId, setTargetSectionId] = 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}> <button type="button" onClick={toggleColumnSettingsMenu} aria-expanded={isColumnMenuOpen}>
Spalten Spalten
</button> </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 <button
type="button" type="button"
onClick={clearSortAndFilters} onClick={clearSortAndFilters}
@@ -2566,8 +2581,25 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
) : null} ) : null}
{isSaving ? <div className="notice info">Wird gespeichert </div> : null} {isSaving ? <div className="notice info">Wird gespeichert </div> : null}
<div className="tree-editor-layout"> <div className="tree-editor-layout">
<aside className="project-device-sidebar"> {isProjectDeviceDrawerOpen ? (
<aside
className="project-device-sidebar project-device-drawer"
id="project-device-drawer"
>
<div className="project-device-drawer-header">
<div>
<h3>Projektgeräte</h3> <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 <input
type="text" type="text"
placeholder="Name oder Anzeigename suchen …" placeholder="Name oder Anzeigename suchen …"
@@ -2668,6 +2700,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
</button> </button>
</div> </div>
</aside> </aside>
) : null}
<div <div
className="tree-grid-wrap" className="tree-grid-wrap"
ref={containerRef} ref={containerRef}