feat(browse): double-click a folder to navigate into it

Single-click still expands the folder inline; double-click swaps the
view's root onto the folder. In server mode it loads the folder's URL
(zddc-server returns a fresh browse instance scoped there); in FS-API
mode it re-roots state.rootHandle onto the folder's handle and re-
enumerates. Files and zips are unchanged — files have a single-click
preview, zips have inline JSZip expansion.

Help panel updated to document the new behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZDDC 2026-05-07 13:43:17 -05:00
parent 0ad47561ed
commit 562b105550
2 changed files with 52 additions and 0 deletions

View file

@ -202,6 +202,54 @@
// Browser handles target=_blank natively for middle
// click; don't preventDefault, just don't intercept.
});
// Double-click on a folder → "navigate into" it. Distinct
// from single-click (which expands inline) so users keep
// both UX models. Server mode jumps to the folder URL —
// zddc-server returns a fresh browse instance scoped to
// that directory. FS-API mode swaps state.rootHandle to
// the folder's handle and re-loads, so the user sees
// only that subtree at the root level.
//
// Files: dblclick is left alone — the single-click preview
// is already a "look at this file" action; a separate
// navigate-into doesn't apply.
// ZIPs: skipped too — they're inspected via inline
// expansion (JSZip), not navigated into.
tbody.addEventListener('dblclick', function (e) {
var row = e.target.closest('tr.tree-row');
if (!row) return;
if (row.dataset.isdir !== 'true') return;
var id = parseInt(row.dataset.id, 10);
var node = state.nodes.get(id);
if (!node) return;
e.preventDefault();
navigateIntoFolder(node);
});
}
}
async function navigateIntoFolder(node) {
if (state.source === 'server') {
var url = window.app.modules.tree.pathFor(node);
if (!url.endsWith('/')) url += '/';
window.location.assign(url);
return;
}
if (state.source === 'fs') {
if (!node.handle || node.handle.kind !== 'directory') return;
state.rootHandle = node.handle;
state.currentPath = node.handle.name + '/';
var raw;
try {
raw = await loader.fetchFsChildren(node.handle);
} catch (e) {
statusError('Failed to enter ' + node.name + ': ' + e.message);
return;
}
tree.setRoot(raw);
tree.render();
statusInfo('Entered ' + node.name);
}
}

View file

@ -126,6 +126,10 @@
<dl>
<dt>Click a folder</dt>
<dd>Toggle expand/collapse on that folder.</dd>
<dt>Double-click a folder</dt>
<dd>Navigate into the folder — it becomes the new root of the
view. Server mode loads the folder's URL; local mode re-roots
onto that folder's handle.</dd>
<dt>Shift-click a folder</dt>
<dd>Recursive expand or collapse — applies to the whole subtree.</dd>
<dt>Click a file</dt>