frontend: Splitter erreicht beide Extreme (Snap zur Titelzeile)

Der Splitter rastet nahe eines Randes in den minimierten Zustand des
jeweiligen Panels ein (gleiche Optik wie die Min-Buttons) und skaliert
dazwischen frei. Damit lassen sich beide Panels per Drag bis zu beiden
Extremen ziehen — in Seiten- wie Stapelmodus.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Michael Hoennig
2026-07-21 11:22:14 +02:00
co-authored by Claude Opus 4.8
parent c9fc505404
commit 1fe86d748c
+26 -10
View File
@@ -686,6 +686,12 @@ document.querySelectorAll('input[name="layout"]').forEach(radio => {
let splitState = 'normal'; let splitState = 'normal';
const editorPanel = document.querySelector('.panel.editor'); const editorPanel = document.querySelector('.panel.editor');
const diagramPanel = document.querySelector('.panel.right'); const diagramPanel = document.querySelector('.panel.right');
function clearCollapse(){
app.classList.remove('collapse-editor','collapse-diagram');
editorPanel.classList.remove('collapsed');
diagramPanel.classList.remove('collapsed');
document.querySelectorAll('.winbtn').forEach(b => b.classList.remove('active'));
}
function applySplit(){ function applySplit(){
/* Preset-/Drag-Größen bei Preset-Wechsel zurücksetzen */ /* Preset-/Drag-Größen bei Preset-Wechsel zurücksetzen */
app.style.removeProperty('--col'); app.style.removeProperty('--col');
@@ -696,6 +702,8 @@ function applySplit(){
editorPanel.classList.toggle('collapsed', splitState==='b'); editorPanel.classList.toggle('collapsed', splitState==='b');
document.querySelectorAll('.winbtn').forEach(b => b.classList.toggle('active', b.dataset.state===splitState)); document.querySelectorAll('.winbtn').forEach(b => b.classList.toggle('active', b.dataset.state===splitState));
} }
/* Setzt einen Minimier-Zustand während des Ziehens nur bei Änderung. */
function snapTo(state){ if(splitState!==state){ splitState = state; applySplit(); } }
document.querySelectorAll('.winbtn').forEach(b => { document.querySelectorAll('.winbtn').forEach(b => {
b.addEventListener('click', () => { splitState = b.dataset.state; applySplit(); }); b.addEventListener('click', () => { splitState = b.dataset.state; applySplit(); });
}); });
@@ -718,23 +726,31 @@ gutter.addEventListener('pointerdown', e => {
document.body.style.userSelect = 'none'; document.body.style.userSelect = 'none';
/* Freies Ziehen hebt Preset und Minimierung auf */ /* Freies Ziehen hebt Preset und Minimierung auf */
splitState = 'custom'; splitState = 'custom';
app.classList.remove('collapse-editor','collapse-diagram'); clearCollapse();
editorPanel.classList.remove('collapsed');
diagramPanel.classList.remove('collapsed');
document.querySelectorAll('.winbtn').forEach(b => b.classList.remove('active'));
e.preventDefault(); e.preventDefault();
}); });
/* Näher als SNAP an einem Rand: in den minimierten Zustand einrasten,
sonst frei skalieren. So sind beide Extreme per Splitter erreichbar. */
const SNAP = 72;
gutter.addEventListener('pointermove', e => { gutter.addEventListener('pointermove', e => {
if(!dragging) return; if(!dragging) return;
const rect = app.getBoundingClientRect(); const rect = app.getBoundingClientRect();
if(app.classList.contains('side')){ if(app.classList.contains('side')){
let w = e.clientX - rect.left; const w = e.clientX - rect.left, maxw = rect.width - 14;
w = Math.max(220, Math.min(rect.width - 280, w)); if(w <= SNAP) snapTo('b'); /* Editor auf Titelzeile */
app.style.setProperty('--col', w + 'px'); else if(w >= maxw - SNAP) snapTo('a'); /* Diagramm auf Titelzeile */
else {
if(splitState!=='custom'){ splitState='custom'; clearCollapse(); }
app.style.setProperty('--col', w + 'px');
}
} else { } else {
let h = e.clientY - rect.top; const h = e.clientY - rect.top, maxh = rect.height - 14;
h = Math.max(120, Math.min(rect.height - 140, h)); if(h <= SNAP) snapTo('a'); /* Diagramm (oben) auf Titelzeile */
app.style.setProperty('--drow', h + 'px'); else if(h >= maxh - SNAP) snapTo('b'); /* Editor (unten) auf Titelzeile */
else {
if(splitState!=='custom'){ splitState='custom'; clearCollapse(); }
app.style.setProperty('--drow', h + 'px');
}
} }
}); });
function endDrag(e){ function endDrag(e){