From 982dda42ac872520e270fcd2c53a312b19a1e847 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sat, 16 May 2026 20:12:39 +0300 Subject: [PATCH] fix(browser): align list columns via subgrid and fix icon sizing - Switch .browser-list to CSS grid + subgrid so header and rows share the same column track widths, eliminating misaligned columns when content widths differ between rows. - Apply matching responsive column overrides at the parent grid level. - Override root-folder SVG sizing (hardcoded 24x24 in browser.js) so it fills the 56px icon box instead of rendering at ~43%. - Make compact grid icon fill its thumb wrapper so the emoji centers instead of being stranded in the top-left corner. - Remove premature isConnected bail in loadThumbnail; the img element is intentionally detached when called from renderBrowserGrid/List. Post-await checks already handle navigation-away correctly. --- media_server/static/css/styles.css | 52 +++++++++++++++++++----------- media_server/static/js/browser.js | 7 ++-- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/media_server/static/css/styles.css b/media_server/static/css/styles.css index 114cef6..cb2c1ae 100644 --- a/media_server/static/css/styles.css +++ b/media_server/static/css/styles.css @@ -3077,19 +3077,25 @@ button.primary svg { /* Browser List View */ .browser-list { - display: flex; - flex-direction: column; - gap: 1px; + display: grid; + grid-template-columns: 40px 1fr auto auto auto auto; + column-gap: 1.25rem; + row-gap: 1px; margin-bottom: 1.5rem; min-height: 200px; } +.browser-list > .browser-empty, +.browser-list > .browser-loading { + grid-column: 1 / -1; +} + /* List view column header */ .browser-list-header { display: grid; - grid-template-columns: 40px 1fr auto auto auto auto; + grid-template-columns: subgrid; + grid-column: 1 / -1; align-items: center; - gap: 0.75rem; padding: 0.4rem 0.75rem; font-size: 0.688rem; font-weight: 600; @@ -3107,9 +3113,9 @@ button.primary svg { .browser-list-item { display: grid; - grid-template-columns: 40px 1fr auto auto auto auto; + grid-template-columns: subgrid; + grid-column: 1 / -1; align-items: center; - gap: 0.75rem; padding: 0.5rem 0.75rem; background: transparent; border: 1px solid transparent; @@ -3303,6 +3309,13 @@ button.primary svg { transition: all 0.25s; } +/* Root folder SVG ships with hardcoded width=24 height=24 (browser.js folderSvg), + which renders at ~43% of the 56px icon box. Override to fill it properly. */ +.browser-item.browser-root-folder .browser-icon > svg { + width: 60%; + height: 60%; +} + .browser-item.browser-root-folder:hover .browser-icon { background: rgba(var(--copper-rgb), 0.18); border-color: rgba(var(--copper-rgb), 0.3); @@ -3650,9 +3663,12 @@ button.primary svg { display: none; } - .browser-list-header { + .browser-list { grid-template-columns: 32px 1fr auto auto; - gap: 0.5rem; + column-gap: 0.875rem; + } + + .browser-list-header { padding: 0.35rem 0.5rem; } @@ -3661,8 +3677,6 @@ button.primary svg { } .browser-list-item { - grid-template-columns: 32px 1fr auto auto; - gap: 0.5rem; padding: 0.4rem 0.5rem; } @@ -3732,17 +3746,13 @@ button.primary svg { display: none; } - .browser-list-header { + .browser-list { grid-template-columns: 40px 1fr auto auto auto; } .browser-list-header span:nth-child(3) { display: none; } - - .browser-list-item { - grid-template-columns: 40px 1fr auto auto auto; - } } /* Update Banner */ @@ -7405,9 +7415,15 @@ select option { font-size: 9px; letter-spacing: 0.1em; } +/* Let the compact icon fill its thumb-wrapper (matches grid view behaviour). + The previous 28x28 size left the icon stranded at the wrapper's top-left + because .browser-thumb-wrapper is not a flex container. The wrapper square + is sized by the grid; the emoji inside .browser-icon centers via the base + flex rules. */ .browser-container .browser-grid-compact .browser-icon { - width: 28px; - height: 28px; + width: 100%; + height: 100%; + font-size: 2.25rem; } .browser-container .browser-item { background: transparent !important; diff --git a/media_server/static/js/browser.js b/media_server/static/js/browser.js index f5ae045..247f206 100644 --- a/media_server/static/js/browser.js +++ b/media_server/static/js/browser.js @@ -537,9 +537,10 @@ async function loadThumbnail(imgElement, fileName) { const cacheKey = `${folderId}|${relPath}`; try { if (!hasCredentials()) return; - // If the user navigates away before this fetch resolves, the imgElement - // may already be detached. Bail in that case. - if (!imgElement.isConnected) return; + // Note: the imgElement is intentionally NOT in the DOM yet when + // renderBrowserGrid/renderBrowserList call us — it's still inside a + // detached wrapper. Don't bail on isConnected here; rely on the + // post-await checks below, which correctly catch navigation away. // Check cache first if (thumbnailCache.has(cacheKey)) {