frontend: Bereiche per Splitter (Drag) aufteilen

Verschiebbarer Gutter zwischen Editor und Diagramm:
- seitlich (vertikal/kompakt): zieht die Editor-Spaltenbreite (--col).
- gestapelt (horizontal): begrenzt die Diagrammhöhe (--diagram-h), das
  Diagramm scrollt dann intern.

Umgesetzt über ein Gutter-Grid-Feld und Pointer-Events (mit
setPointerCapture); Grenzen via min/max. Kein neues Framework.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Michael Hoennig
2026-07-21 10:41:31 +02:00
co-authored by Claude Opus 4.8
parent 593f81e50b
commit 707f50a223
+65 -7
View File
@@ -34,22 +34,44 @@
header p{margin-top:4px;color:var(--muted);font-size:.9rem}
/* Horizontal (Toggle aus): Diagramm oben, Editor unten — je volle Breite.
Vertikal (Toggle an, .side): Editor links, Diagramm rechts. */
Vertikal (Toggle an, .side): Editor links, Diagramm rechts.
Zwischen beiden liegt ein verschiebbarer Gutter (Splitter). */
.app{
max-width:1200px;margin:0 auto;
display:grid;grid-template-columns:1fr;gap:20px;
grid-template-areas:"diagram" "editor";
display:grid;gap:0;
grid-template-columns:1fr;
grid-template-areas:"diagram" "gutter" "editor";
align-items:start;
}
.app.side{
grid-template-columns:360px 1fr;
grid-template-areas:"editor diagram";
grid-template-columns:var(--col,360px) 14px 1fr;
grid-template-areas:"editor gutter diagram";
}
.panel.editor{grid-area:editor}
.panel.right{grid-area:diagram}
.gutter{grid-area:gutter}
/* Im gestapelten Modus die Diagrammhöhe per Gutter begrenzen (scrollt intern). */
.app:not(.side) .diagram{max-height:var(--diagram-h,none)}
@media (max-width:820px){
.app.side{grid-template-columns:1fr;grid-template-areas:"editor" "diagram"}
.app.side{
grid-template-columns:1fr;
grid-template-areas:"diagram" "gutter" "editor";
}
}
/* Splitter/Gutter: stapelweise horizontal, seitlich vertikal. */
.gutter{
position:relative;align-self:stretch;justify-self:stretch;
height:14px;cursor:row-resize;touch-action:none;
}
.app.side .gutter{height:auto;width:14px;cursor:col-resize}
.gutter::before{
content:'';position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
width:46px;height:4px;border-radius:999px;background:rgba(36,52,71,.16);
transition:background .15s;
}
.app.side .gutter::before{width:4px;height:46px}
.gutter:hover::before,.gutter.dragging::before{background:var(--or)}
/* Editor-Innenaufbau: Textarea + aufklappbare Agenda.
Horizontal nebeneinander, vertikal (.side) untereinander. */
@@ -145,7 +167,7 @@
.diagram{
padding:28px 16px 24px;
overflow-x:auto;
overflow:auto;
background:transparent;
}
.panel.right{background:rgba(255,255,255,.6)}
@@ -362,6 +384,8 @@
</div>
</div>
<div class="gutter" id="gutter" role="separator" aria-label="Bereiche größenverändern" title="Ziehen zum Verschieben"></div>
<div class="panel right">
<div class="panel-head">
<span>Diagramm</span>
@@ -551,6 +575,40 @@ document.querySelectorAll('input[name="layout"]').forEach(radio => {
radio.addEventListener('change', () => { if(radio.checked) applyLayout(radio.value); });
});
/* ---------- Splitter: Bereiche per Drag verteilen ---------- */
const gutter = document.getElementById('gutter');
const diagramEl = document.querySelector('.diagram');
let dragging = false;
gutter.addEventListener('pointerdown', e => {
dragging = true;
gutter.classList.add('dragging');
gutter.setPointerCapture(e.pointerId);
document.body.style.userSelect = 'none';
e.preventDefault();
});
gutter.addEventListener('pointermove', e => {
if(!dragging) return;
if(app.classList.contains('side')){
const rect = app.getBoundingClientRect();
let w = e.clientX - rect.left;
w = Math.max(220, Math.min(rect.width - 280, w));
app.style.setProperty('--col', w + 'px');
} else {
let h = e.clientY - diagramEl.getBoundingClientRect().top;
h = Math.max(140, h);
app.style.setProperty('--diagram-h', h + 'px');
}
});
function endDrag(e){
if(!dragging) return;
dragging = false;
gutter.classList.remove('dragging');
document.body.style.userSelect = '';
try{ gutter.releasePointerCapture(e.pointerId); }catch(_){}
}
gutter.addEventListener('pointerup', endDrag);
gutter.addEventListener('pointercancel', endDrag);
const showc = document.getElementById('showc');
showc.addEventListener('change', render);