From 73034a4b98a03d9dee100fdf584d562645ada40b Mon Sep 17 00:00:00 2001 From: Wildan M Date: Sat, 16 May 2026 13:55:11 +0700 Subject: [PATCH] web: Design improvements --- src/web/files.html | 57 ++++++++++++++++++++++++++++++---------------- src/web/style.css | 1 + 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/web/files.html b/src/web/files.html index f4dccde1b..0c9fdd39a 100644 --- a/src/web/files.html +++ b/src/web/files.html @@ -22,11 +22,9 @@
Loading files...
-
+
Files
-
-
-
+
File Content
@@ -46,7 +44,7 @@ /** @type {DB} */ let activeDb = {}; /** @type {string[]} */ - let pathStack = ["/"]; + let pathStack = [""]; /** @type {string[][]} */ let historyStack = []; let currentSearch = ""; @@ -120,14 +118,15 @@ for (const [dirKey, dirNode] of Object.entries(dirs)) { let childHasFiles = false; - for (const val of Object.values(dirNode)) { + let dirNodeValues = Object.values(dirNode); + for (const val of dirNodeValues) { if (typeof val !== 'object') { childHasFiles = true; break; } } - if (!childHasFiles && Object.keys(dirNode).length > 0) { + if (!childHasFiles && dirNodeValues.length > 0 && dirNodeValues.length < 5) { for (const [subKey, subValue] of Object.entries(dirNode)) { newNode[`${dirKey}/${subKey}`] = subValue; } @@ -172,10 +171,10 @@ filePanel.innerHTML = ''; if (isPeeking) { - const peekName = basePathArray[basePathArray.length - 1]; + const peekName = basePathArray.join('/'); fileHeader.innerHTML = `Files (Peeking: ${peekName})`; } else if (lockedFileViewPath) { - const lockName = lockedFileViewPath[lockedFileViewPath.length - 1]; + const lockName = lockedFileViewPath.join('/'); fileHeader.innerHTML = `Files (Selected: ${lockName})`; } else { fileHeader.innerHTML = `Files`; @@ -217,18 +216,21 @@ * @param {HTMLElement} container * @param {DB} node * @param {number} currentDepth - * @param {number} maxDepth + * @param {(depth: number, files: number) => boolean} maxDepthFn * @param {string[]} currentPathArray + * @returns {boolean} */ - function renderDirTree(container, node, currentDepth, maxDepth, currentPathArray) { - if (currentDepth >= maxDepth || !node) return; + function renderDirTree(container, node, currentDepth, maxDepthFn, currentPathArray) { + if (!node) return false; let dirs = []; for (const [key, value] of Object.entries(node)) { if (typeof value === 'object') dirs.push(key); } + if (!maxDepthFn(currentDepth, dirs.length)) { + return false; + } dirs.sort(); - dirs.forEach(dir => { const dirDiv = document.createElement('div'); dirDiv.className = 'list-item'; @@ -255,6 +257,7 @@ } dirDiv.innerHTML = `${dir}`; + dirDiv.setAttribute('data-path', nextPathArray.join('/')); dirDiv.addEventListener('mouseenter', () => { renderFiles(node[dir], nextPathArray, true); @@ -281,8 +284,12 @@ container.appendChild(dirDiv); - renderDirTree(container, node[dir], currentDepth + 1, maxDepth, nextPathArray); + let rendered = renderDirTree(container, node[dir], currentDepth + 1, maxDepthFn, nextPathArray); + if (hasSubDirs) { + dirDiv.innerText += rendered ? " .." : " ..."; + } }); + return true; } function render() { @@ -290,15 +297,16 @@ if (!node) { // reset to root - pathStack = ["/"]; + pathStack = []; historyStack = []; node = getCurrentNode(); lockedFileViewPath = null; if (!node) return; } - dirHeader.innerText = pathStack.join('/').replace('//', '/'); + dirHeader.innerText = pathStack.join('/'); + let lastScroll = dirPanel.scrollTop; dirPanel.innerHTML = ''; if (historyStack.length > 0) { @@ -306,7 +314,7 @@ backDiv.className = 'list-item up-icon'; backDiv.innerHTML = `Back`; backDiv.onclick = () => { - pathStack = historyStack.pop() || ['/']; + pathStack = historyStack.pop() || ['']; lockedFileViewPath = null; clearContentPanel(); render(); @@ -314,7 +322,14 @@ dirPanel.appendChild(backDiv); } - renderDirTree(dirPanel, node, 0, 3, pathStack); + renderDirTree(dirPanel, node, 0, (depth, files) => { + switch (depth) { + case 0: return true; + case 1: return files < 10; + case 2: return files < 5; + default: return false; + } + }, pathStack); if (dirPanel.children.length === 0 || (dirPanel.children.length === 1 && pathStack.length > 1)) { const emptyMsg = document.createElement('div'); @@ -322,6 +337,8 @@ emptyMsg.style.color = '#777'; emptyMsg.innerText = 'No subdirectories'; dirPanel.appendChild(emptyMsg); + } else { + dirPanel.scrollTop = lastScroll; } renderFiles(node, pathStack, false); @@ -334,7 +351,7 @@ * @param {string[]} basePathArray */ function showFileContent(fileName, packages, basePathArray) { - const fullPath = (basePathArray.join('/') + '/' + fileName).replace('//', '/'); + const fullPath = (basePathArray.join('/') + '/' + fileName); contentHeader.innerText = fileName; contentPanel.innerHTML = `
@@ -343,7 +360,7 @@
Provided by:
- ${packages.split(',').map(p => `${p}`).join(', ')} + ${packages.split(',').map(p => `${p}`).join(', ')}
`; } diff --git a/src/web/style.css b/src/web/style.css index 87773f551..5fad81c5a 100644 --- a/src/web/style.css +++ b/src/web/style.css @@ -290,6 +290,7 @@ th { padding: 8px 15px; cursor: pointer; display: flex; + flex-wrap: wrap; align-items: center; user-select: none; }