Merge pull request 'feat/resizable-panels' (#20) from feat/resizable-panels into main
Reviewed-on: #20
This commit was merged in pull request #20.
This commit is contained in:
+79
@@ -1451,6 +1451,14 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ev.key === 'Escape' && $('main').classList.contains('focus-peek')) {
|
||||||
|
exitFocusPeek();
|
||||||
|
state.selectedIndex = -1;
|
||||||
|
renderEntityList();
|
||||||
|
renderDetailPane();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const sel = state.entities[state.selectedIndex];
|
const sel = state.entities[state.selectedIndex];
|
||||||
|
|
||||||
switch (ev.key) {
|
switch (ev.key) {
|
||||||
@@ -1534,6 +1542,17 @@
|
|||||||
|
|
||||||
function toggleZen() {
|
function toggleZen() {
|
||||||
const m = $('main');
|
const m = $('main');
|
||||||
|
|
||||||
|
if (m.classList.contains('focus-peek')) {
|
||||||
|
exitFocusPeek();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.selectedIndex >= 0) {
|
||||||
|
m.classList.add('focus-peek');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const isZen = m.classList.contains('hide-rail') && m.classList.contains('hide-peek');
|
const isZen = m.classList.contains('hide-rail') && m.classList.contains('hide-peek');
|
||||||
if (isZen) {
|
if (isZen) {
|
||||||
m.classList.remove('hide-rail', 'hide-peek');
|
m.classList.remove('hide-rail', 'hide-peek');
|
||||||
@@ -1546,12 +1565,72 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exitFocusPeek() {
|
||||||
|
$('main').classList.remove('focus-peek');
|
||||||
|
}
|
||||||
|
|
||||||
(function restorePanels() {
|
(function restorePanels() {
|
||||||
const m = $('main');
|
const m = $('main');
|
||||||
if (localStorage.getItem('nib:hide-rail')) m.classList.add('hide-rail');
|
if (localStorage.getItem('nib:hide-rail')) m.classList.add('hide-rail');
|
||||||
if (localStorage.getItem('nib:hide-peek')) m.classList.add('hide-peek');
|
if (localStorage.getItem('nib:hide-peek')) m.classList.add('hide-peek');
|
||||||
|
const railW = localStorage.getItem('nib:rail-w');
|
||||||
|
const peekW = localStorage.getItem('nib:peek-w');
|
||||||
|
if (railW) m.style.setProperty('--rail-w', railW + 'px');
|
||||||
|
if (peekW) m.style.setProperty('--peek-w', peekW + 'px');
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// ========== Resize handles ==========
|
||||||
|
|
||||||
|
$$('.resize-handle').forEach(handle => {
|
||||||
|
let startX, startW, panel;
|
||||||
|
|
||||||
|
handle.addEventListener('mousedown', (ev) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
panel = handle.dataset.panel;
|
||||||
|
startX = ev.clientX;
|
||||||
|
const m = $('main');
|
||||||
|
m.classList.add('resizing');
|
||||||
|
handle.classList.add('active');
|
||||||
|
|
||||||
|
if (panel === 'rail') {
|
||||||
|
startW = $('#tag-rail').offsetWidth;
|
||||||
|
} else {
|
||||||
|
startW = $('#detail-pane').offsetWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', onMove);
|
||||||
|
document.addEventListener('mouseup', onUp);
|
||||||
|
});
|
||||||
|
|
||||||
|
function onMove(ev) {
|
||||||
|
const m = $('main');
|
||||||
|
const dx = ev.clientX - startX;
|
||||||
|
let newW;
|
||||||
|
|
||||||
|
if (panel === 'rail') {
|
||||||
|
newW = Math.max(120, Math.min(360, startW + dx));
|
||||||
|
m.style.setProperty('--rail-w', newW + 'px');
|
||||||
|
} else {
|
||||||
|
newW = Math.max(250, Math.min(700, startW - dx));
|
||||||
|
m.style.setProperty('--peek-w', newW + 'px');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUp() {
|
||||||
|
const m = $('main');
|
||||||
|
m.classList.remove('resizing');
|
||||||
|
handle.classList.remove('active');
|
||||||
|
document.removeEventListener('mousemove', onMove);
|
||||||
|
document.removeEventListener('mouseup', onUp);
|
||||||
|
|
||||||
|
if (panel === 'rail') {
|
||||||
|
localStorage.setItem('nib:rail-w', $('#tag-rail').offsetWidth);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('nib:peek-w', $('#detail-pane').offsetWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function scrollSelectedIntoView() {
|
function scrollSelectedIntoView() {
|
||||||
const el = $(`.entity-item[data-index="${state.selectedIndex}"], .card-row[data-index="${state.selectedIndex}"]`);
|
const el = $(`.entity-item[data-index="${state.selectedIndex}"], .card-row[data-index="${state.selectedIndex}"]`);
|
||||||
if (el) el.scrollIntoView({ block: 'nearest' });
|
if (el) el.scrollIntoView({ block: 'nearest' });
|
||||||
|
|||||||
@@ -24,11 +24,13 @@
|
|||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<aside id="tag-rail"></aside>
|
<aside id="tag-rail"></aside>
|
||||||
|
<div class="resize-handle" data-panel="rail"></div>
|
||||||
<section id="entity-panel">
|
<section id="entity-panel">
|
||||||
<div id="month-nav"></div>
|
<div id="month-nav"></div>
|
||||||
<div id="entity-list"></div>
|
<div id="entity-list"></div>
|
||||||
<div id="capture-bar"></div>
|
<div id="capture-bar"></div>
|
||||||
</section>
|
</section>
|
||||||
|
<div class="resize-handle" data-panel="peek"></div>
|
||||||
<aside id="detail-pane">
|
<aside id="detail-pane">
|
||||||
<div class="detail-empty">select an entity</div>
|
<div class="detail-empty">select an entity</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
+29
-7
@@ -177,17 +177,39 @@ nav { display: flex; gap: 2px; }
|
|||||||
/* ── MAIN LAYOUT ────────────────────────────────────── */
|
/* ── MAIN LAYOUT ────────────────────────────────────── */
|
||||||
main {
|
main {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 192px 1fr 400px;
|
grid-template-columns: var(--rail-w, 192px) 4px 1fr 4px var(--peek-w, 400px);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: grid-template-columns var(--t-base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main.hide-rail { grid-template-columns: 0px 1fr 400px; }
|
main.resizing { transition: none; }
|
||||||
main.hide-peek { grid-template-columns: 192px 1fr 0px; }
|
main:not(.resizing) { transition: grid-template-columns var(--t-base); }
|
||||||
main.hide-rail.hide-peek { grid-template-columns: 0px 1fr 0px; }
|
|
||||||
|
|
||||||
main.hide-rail #tag-rail { overflow: hidden; border-right: none; }
|
main.hide-rail { grid-template-columns: 0px 0px 1fr 4px var(--peek-w, 400px); }
|
||||||
main.hide-peek #detail-pane { overflow: hidden; border-left: none; }
|
main.hide-peek { grid-template-columns: var(--rail-w, 192px) 4px 1fr 0px 0px; }
|
||||||
|
main.hide-rail.hide-peek { grid-template-columns: 0px 0px 1fr 0px 0px; }
|
||||||
|
|
||||||
|
main.hide-rail #tag-rail { overflow: hidden; border-right: none; min-width: 0; }
|
||||||
|
main.hide-peek #detail-pane { overflow: hidden; border-left: none; min-width: 0; }
|
||||||
|
main.hide-rail .resize-handle[data-panel="rail"] { visibility: hidden; }
|
||||||
|
main.hide-peek .resize-handle[data-panel="peek"] { visibility: hidden; }
|
||||||
|
|
||||||
|
main.focus-peek { grid-template-columns: 0px 0px 0px 0px 1fr; }
|
||||||
|
main.focus-peek #tag-rail { overflow: hidden; border-right: none; min-width: 0; }
|
||||||
|
main.focus-peek #entity-panel { overflow: hidden; min-width: 0; }
|
||||||
|
main.focus-peek .resize-handle { visibility: hidden; }
|
||||||
|
|
||||||
|
.resize-handle {
|
||||||
|
cursor: col-resize;
|
||||||
|
background: transparent;
|
||||||
|
transition: background var(--t-fast);
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle:hover,
|
||||||
|
.resize-handle.active {
|
||||||
|
background: var(--accent);
|
||||||
|
opacity: .4;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── TAG RAIL ───────────────────────────────────────── */
|
/* ── TAG RAIL ───────────────────────────────────────── */
|
||||||
#tag-rail {
|
#tag-rail {
|
||||||
|
|||||||
Reference in New Issue
Block a user