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.
This commit is contained in:
2026-05-25 17:37:06 +03:00
parent bba84d4194
commit 720b45a9a6
4 changed files with 41 additions and 2 deletions

View File

@@ -141,6 +141,15 @@ h1 {
letter-spacing: 0; letter-spacing: 0;
} }
.file-name {
display: block;
max-width: 100%;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.hero-copy p, .hero-copy p,
.download-subtitle, .download-subtitle,
.panel-header p { .panel-header p {
@@ -429,6 +438,7 @@ button {
.result-item, .result-item,
.download-item { .download-item {
min-width: 0;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.8rem; gap: 0.8rem;
@@ -441,6 +451,7 @@ button {
.result-item > span, .result-item > span,
.download-item > span { .download-item > span {
min-width: 0; min-width: 0;
max-width: 100%;
flex: 1; flex: 1;
} }
@@ -473,6 +484,10 @@ code {
.result-item small, .result-item small,
.download-item small, .download-item small,
code { code {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-top: 0.25rem; margin-top: 0.25rem;
color: var(--muted-foreground); color: var(--muted-foreground);
font-size: 0.78rem; font-size: 0.78rem;
@@ -582,6 +597,7 @@ code {
.file-main { .file-main {
min-width: 0; min-width: 0;
max-width: 100%;
flex: 1; flex: 1;
color: var(--foreground); color: var(--foreground);
text-decoration: none; text-decoration: none;
@@ -603,10 +619,15 @@ code {
.file-browser.is-thumbs .file-card { .file-browser.is-thumbs .file-card {
display: grid; display: grid;
min-width: 0;
align-content: start; align-content: start;
gap: 0.7rem; gap: 0.7rem;
} }
.file-browser.is-thumbs .file-main {
width: 100%;
}
.file-browser.is-thumbs .thumb-link { .file-browser.is-thumbs .thumb-link {
width: 100%; width: 100%;
flex-basis: auto; flex-basis: auto;

View File

@@ -19,6 +19,7 @@
const fileContextMenu = document.querySelector("[data-file-context-menu]"); const fileContextMenu = document.querySelector("[data-file-context-menu]");
let ctrlCopyMode = false; let ctrlCopyMode = false;
let contextFile = null; let contextFile = null;
const contextMenuCloseDistance = 80;
if (fileBrowser) { if (fileBrowser) {
viewButtons.forEach((button) => { 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("resize", hideContextMenu);
window.addEventListener("scroll", hideContextMenu, true); window.addEventListener("scroll", hideContextMenu, true);
} }
@@ -295,7 +303,9 @@
const body = document.createElement("span"); const body = document.createElement("span");
const name = document.createElement("strong"); const name = document.createElement("strong");
name.className = "file-name";
name.textContent = file.name; name.textContent = file.name;
name.title = file.name;
const meta = document.createElement("code"); const meta = document.createElement("code");
meta.textContent = file.meta; meta.textContent = file.meta;
body.append(name, meta); body.append(name, meta);
@@ -428,6 +438,14 @@
contextFile = null; 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) { function openInNewTab(url) {
window.open(url, "_blank", "noopener,noreferrer"); window.open(url, "_blank", "noopener,noreferrer");
} }

View File

@@ -49,7 +49,7 @@
<img src="{{.ThumbnailURL}}" alt="" loading="lazy"> <img src="{{.ThumbnailURL}}" alt="" loading="lazy">
</a> </a>
<a class="file-main" href="{{.DownloadURL}}?inline=1"> <a class="file-main" href="{{.DownloadURL}}?inline=1">
<strong>{{.Name}}</strong> <strong class="file-name" title="{{.Name}}">{{.Name}}</strong>
<small>{{.Size}} · {{.ContentType}}</small> <small>{{.Size}} · {{.ContentType}}</small>
</a> </a>
{{if not $.Data.Locked}} {{if not $.Data.Locked}}

View File

@@ -23,7 +23,7 @@
<img src="{{.Data.File.ThumbnailURL}}" alt=""> <img src="{{.Data.File.ThumbnailURL}}" alt="">
{{end}} {{end}}
</div> </div>
<h1 id="preview-title">{{.Data.File.Name}}</h1> <h1 id="preview-title" class="file-name" title="{{.Data.File.Name}}">{{.Data.File.Name}}</h1>
<p class="download-subtitle">{{.Data.File.Size}} · {{.Data.File.ContentType}}</p> <p class="download-subtitle">{{.Data.File.Size}} · {{.Data.File.ContentType}}</p>
<a class="button button-primary button-wide" href="{{.Data.DownloadURL}}"> <a class="button button-primary button-wide" href="{{.Data.DownloadURL}}">
<svg viewBox="0 0 24 24" role="img" focusable="false" aria-hidden="true"><path d="M12 3v12m0 0 4-4m-4 4-4-4M5 21h14" /></svg> <svg viewBox="0 0 24 24" role="img" focusable="false" aria-hidden="true"><path d="M12 3v12m0 0 4-4m-4 4-4-4M5 21h14" /></svg>