From 48be921b8d1a440d88b94f7ce94cc6472a4f27e2 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 6 Jul 2026 15:25:04 -0400 Subject: [PATCH] fix(ui): tag-rail no longer scroll-jumps on accept/reject; keep suggestions clear of the toast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TagAutocomplete: focus the inner input with preventScroll so handing focus back after an accept/reject stops yanking the rail up to the field (which sits above the suggestions list — you had to scroll back down every time). Applies to both the image modal and the Explore rail. - ExploreView: pad the right rail's scroll bottom (88px) so the bottom-right snackbar floats over empty space instead of covering the last suggestions and their accept/reject controls. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM --- frontend/src/components/modal/TagAutocomplete.vue | 11 ++++++++++- frontend/src/views/ExploreView.vue | 6 +++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/modal/TagAutocomplete.vue b/frontend/src/components/modal/TagAutocomplete.vue index 8d368fc..7888bba 100644 --- a/frontend/src/components/modal/TagAutocomplete.vue +++ b/frontend/src/components/modal/TagAutocomplete.vue @@ -127,7 +127,16 @@ const suggestions = useSuggestionsStore() const inputRef = ref(null) function focusInput () { if (window.matchMedia?.('(max-width: 900px)')?.matches) return - nextTick(() => inputRef.value?.focus?.()) + // Focus the inner with preventScroll: handing focus back after an + // accept/reject must NOT yank the rail's scroll up to this field, which sits + // above the suggestions list (operator-flagged 2026-07-06 — "I have to scroll + // back down every time I apply/reject"). Vuetify's own .focus() forwards no + // options, so reach the element directly; fall back to it if it's not there. + nextTick(() => { + const el = inputRef.value?.$el?.querySelector?.('input') + if (el) el.focus({ preventScroll: true }) + else inputRef.value?.focus?.() + }) } onMounted(focusInput) // Exposed so the parent (TagPanel) can hand focus back to this field after an diff --git a/frontend/src/views/ExploreView.vue b/frontend/src/views/ExploreView.vue index 17ea79b..bb893d5 100644 --- a/frontend/src/views/ExploreView.vue +++ b/frontend/src/views/ExploreView.vue @@ -350,10 +350,14 @@ onUnmounted(() => { } .fc-ex__artist { padding: 10px 16px 0; font-weight: 600; } -/* Right rail = the modal's tag panel, hosted on the anchor. */ +/* Right rail = the modal's tag panel, hosted on the anchor. The bottom padding + keeps the scrollable content from reaching the viewport floor, so the + bottom-right snackbar floats over empty space instead of covering the last + suggestions / their accept-reject controls (operator-flagged 2026-07-06). */ .fc-ex__rail { background: rgb(var(--v-theme-surface)); overflow-y: auto; + padding-bottom: 88px; } .fc-ex__spinner {