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 {