From 720b45a9a6caf4f614ba4a704ecc4a37333fb37b Mon Sep 17 00:00:00 2001 From: Daniel Legt Date: Mon, 25 May 2026 17:37:06 +0300 Subject: [PATCH] feat(ui): truncate long file names and auto-close context menu - Add `.file-name` class with ellipsis truncation for long file names to prevent layout overflow. - Apply truncation to metadata and file items in download and preview pages. - Add `title` attributes to truncated names to show the full text on hover. - Automatically close the file context menu when the mouse moves more than 80px away from it. --- backend/static/css/app.css | 21 +++++++++++++++++++++ backend/static/js/app.js | 18 ++++++++++++++++++ backend/templates/pages/download.html | 2 +- backend/templates/pages/preview.html | 2 +- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/backend/static/css/app.css b/backend/static/css/app.css index ade26d0..6302c1f 100644 --- a/backend/static/css/app.css +++ b/backend/static/css/app.css @@ -141,6 +141,15 @@ h1 { letter-spacing: 0; } +.file-name { + display: block; + max-width: 100%; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + .hero-copy p, .download-subtitle, .panel-header p { @@ -429,6 +438,7 @@ button { .result-item, .download-item { + min-width: 0; display: flex; align-items: center; gap: 0.8rem; @@ -441,6 +451,7 @@ button { .result-item > span, .download-item > span { min-width: 0; + max-width: 100%; flex: 1; } @@ -473,6 +484,10 @@ code { .result-item small, .download-item small, code { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; margin-top: 0.25rem; color: var(--muted-foreground); font-size: 0.78rem; @@ -582,6 +597,7 @@ code { .file-main { min-width: 0; + max-width: 100%; flex: 1; color: var(--foreground); text-decoration: none; @@ -603,10 +619,15 @@ code { .file-browser.is-thumbs .file-card { display: grid; + min-width: 0; align-content: start; gap: 0.7rem; } +.file-browser.is-thumbs .file-main { + width: 100%; +} + .file-browser.is-thumbs .thumb-link { width: 100%; flex-basis: auto; diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 0e3c457..3e3f038 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -19,6 +19,7 @@ const fileContextMenu = document.querySelector("[data-file-context-menu]"); let ctrlCopyMode = false; let contextFile = null; + const contextMenuCloseDistance = 80; if (fileBrowser) { viewButtons.forEach((button) => { @@ -79,6 +80,13 @@ } }); + document.addEventListener("mousemove", (event) => { + if (fileContextMenu.hidden || isPointerNearContextMenu(event.clientX, event.clientY)) { + return; + } + hideContextMenu(); + }); + window.addEventListener("resize", hideContextMenu); window.addEventListener("scroll", hideContextMenu, true); } @@ -295,7 +303,9 @@ const body = document.createElement("span"); const name = document.createElement("strong"); + name.className = "file-name"; name.textContent = file.name; + name.title = file.name; const meta = document.createElement("code"); meta.textContent = file.meta; body.append(name, meta); @@ -428,6 +438,14 @@ contextFile = null; } + function isPointerNearContextMenu(x, y) { + const rect = fileContextMenu.getBoundingClientRect(); + return x >= rect.left - contextMenuCloseDistance && + x <= rect.right + contextMenuCloseDistance && + y >= rect.top - contextMenuCloseDistance && + y <= rect.bottom + contextMenuCloseDistance; + } + function openInNewTab(url) { window.open(url, "_blank", "noopener,noreferrer"); } diff --git a/backend/templates/pages/download.html b/backend/templates/pages/download.html index 341193a..c56fa65 100644 --- a/backend/templates/pages/download.html +++ b/backend/templates/pages/download.html @@ -49,7 +49,7 @@ - {{.Name}} + {{.Name}} {{.Size}} · {{.ContentType}} {{if not $.Data.Locked}} diff --git a/backend/templates/pages/preview.html b/backend/templates/pages/preview.html index d229958..03b69d1 100644 --- a/backend/templates/pages/preview.html +++ b/backend/templates/pages/preview.html @@ -23,7 +23,7 @@ {{end}} -

{{.Data.File.Name}}

+

{{.Data.File.Name}}

{{.Data.File.Size}} · {{.Data.File.ContentType}}