From 31fc02ddbf434abf82b224ede7760ce7e6c90103 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Sun, 3 May 2026 18:22:03 +0000 Subject: [PATCH] Keep the file extension always visible but discreetly as part of the filename. Fix Escape in rename field. --- frontend/src/App.vue | 4 + frontend/src/components/Gallery.vue | 3 +- frontend/src/components/GalleryFigure.vue | 115 +++++++++++++++++----- 3 files changed, 96 insertions(+), 26 deletions(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index a645071..4083200 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -115,6 +115,8 @@ const globalShortcutHandler = (event: KeyboardEvent) => { if (searchHasText && (dir === 'left' || dir === 'right')) { return // Let browser handle cursor movement } + // Don't intercept arrows for non-search inputs (e.g. rename input) + if (input && !searchInput) return arrow = dir } if (arrow) { @@ -136,6 +138,8 @@ const globalShortcutHandler = (event: KeyboardEvent) => { else if (keyup && event.key === 'Escape') { store.error = '' store.clearToast() + // Keep rename and other non-search inputs isolated from search behavior. + if (input && !searchInput) return headerMain.value!.clearSearch(event) store.focusBreadcrumb() } else if (!input && keyup && event.key === 'Backspace') { diff --git a/frontend/src/components/Gallery.vue b/frontend/src/components/Gallery.vue index 99a12e1..f4720c6 100644 --- a/frontend/src/components/Gallery.vue +++ b/frontend/src/components/Gallery.vue @@ -8,6 +8,7 @@ :editing="editing === doc ? {rename, exit} : null" :style="{ '--gallery-figure-height': rowHeightsByKey[doc.key] ?? '15em' }" @menu="contextMenu($event, doc)" + @rename="editing = doc; store.cursor = doc.key" :class="{ 'folder-start': showFolderBreadcrumb(index) }" /> @@ -310,7 +311,7 @@ let scrolltr: any = null watchEffect(() => { if (store.cursor && store.cursor !== editing.value?.key) editing.value = null if (editing.value) store.cursor = editing.value.key - if (store.cursor) { + if (store.cursor && !editing.value) { const a = document.querySelector( `#file-${store.cursor}` ) as HTMLAnchorElement | null diff --git a/frontend/src/components/GalleryFigure.vue b/frontend/src/components/GalleryFigure.vue index 11cbd04..1924167 100644 --- a/frontend/src/components/GalleryFigure.vue +++ b/frontend/src/components/GalleryFigure.vue @@ -11,17 +11,26 @@
-
{{ doc.ext }}
@@ -45,7 +54,7 @@ import SparseIndicator from './SparseIndicator.vue' const store = useMainStore() type EditingProp = { - rename: (name: string) => void + rename: (doc: Doc, newName: string) => void exit: () => void } @@ -90,19 +99,74 @@ const onclick = (ev: Event) => { .after-name { margin-left: 0.3em; } -.ext-badge { +.filename-row { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0; + flex: 0 1 auto; + min-width: 0; + position: relative; + overflow: visible; + max-width: calc(100% - 4.5em); +} +.filename-row::after { + content: ''; position: absolute; - bottom: 2.5em; - right: 1em; + left: 100%; + top: 0; + width: 1.4em; + height: 100%; +} +.filename-group { + display: inline-flex; + align-items: baseline; + min-width: 0; + max-width: 100%; +} +.filename { + cursor: default; + padding: .5em 0; color: #fff; - font-size: 0.65em; + font-size: 0.8em; font-weight: 600; - letter-spacing: 0.03em; - text-transform: uppercase; text-shadow: 0 0 .2em #000, 0 0 .2em #000; - line-height: 1.4; + text-wrap: nowrap; + text-overflow: ellipsis; + overflow: hidden; + flex: 0 1 auto; + min-width: 0; +} +.file-ext { + color: rgba(255, 255, 255, 0.8); + font-size: 0.8em; + font-weight: 600; + text-shadow: 0 0 .2em #000, 0 0 .2em #000; + padding: 0 .15em 0 0; + white-space: nowrap; + flex: 0 0 auto; +} +.rename-btn { + position: absolute; + left: 100%; + top: 50%; + transform: translate(0.2em, -50%); + z-index: 2; + background: none; + border: none; + padding: 0; + cursor: pointer; + font-size: 0.8em; + line-height: 1; + opacity: 0; + visibility: hidden; pointer-events: none; - user-select: none; + transition: opacity 0.12s ease; +} +.filename-row:hover .rename-btn { + opacity: 1; + visibility: visible; + pointer-events: auto; } figure { height: var(--gallery-figure-height, 15em); @@ -149,18 +213,10 @@ figcaption input[type='checkbox'] { figcaption input[type='checkbox']:checked, figcaption:hover input[type='checkbox'] { opacity: 1; } -figcaption span { - cursor: default; - padding: .5em; - color: #fff; - font-size: 0.8em; - font-weight: 600; - text-shadow: 0 0 .2em #000, 0 0 .2em #000; - text-wrap: nowrap; - text-overflow: ellipsis; - overflow: hidden; +.cursor .filename { + color: var(--accent-color); } -.cursor figcaption span { +.cursor .file-ext { color: var(--accent-color); } figcaption .namespacer { @@ -170,6 +226,15 @@ figcaption .namespacer { } .rename-wrap { font-size: 0.8em; - width: 100%; + width: auto; + min-width: 0; + max-width: 100%; +} +.rename-row { + max-width: calc(100% - 4.5em); +} +.rename-wrap :deep(#FileRenameInput) { + min-width: 0; + max-width: 100%; }