diff --git a/frontend/apps/main/src/features/conversation/message/MessageList.vue b/frontend/apps/main/src/features/conversation/message/MessageList.vue
index b3a82ce1..3d44c751 100644
--- a/frontend/apps/main/src/features/conversation/message/MessageList.vue
+++ b/frontend/apps/main/src/features/conversation/message/MessageList.vue
@@ -29,7 +29,7 @@
@@ -95,10 +95,8 @@ const contentEl = ref(null)
const emitter = useEmitter()
const unReadMessages = ref(0)
let currentConversationUUID = ''
-let pendingScrollTo = null
-const { hasUserScrolled, scrollToBottom, handleScroll } = useStickyScroll(threadEl, contentEl, {
- skipAutoScroll: () => !!pendingScrollTo,
+const { hasUserScrolled, scrollToBottom, scrollToOffset, handleScroll } = useStickyScroll(threadEl, contentEl, {
onArriveBottom: () => { unReadMessages.value = 0 }
})
@@ -107,18 +105,14 @@ const handleScrollToBottom = () => {
scrollToBottom()
}
-const scrollToMessage = (messageUUID) => {
- if (!messageUUID) return scrollToBottom()
- const thread = threadEl.value
- const messageEl = thread?.querySelector(`[data-message-uuid="${messageUUID}"]`)
- if (!messageEl || !thread) {
- scrollToBottom()
- return
+const vScrollTarget = {
+ mounted (el, binding) {
+ if (binding.value !== route.query.scrollTo || !threadEl.value) return
+ hasUserScrolled.value = true
+ scrollToOffset(Math.max(0, el.offsetTop - threadEl.value.clientHeight / 3 + el.offsetHeight / 2))
+ el.classList.add('highlight-mention')
+ setTimeout(() => el.classList.remove('highlight-mention'), 2500)
}
- // Position message at ~1/3 from top of viewport for better visibility
- thread.scrollTop = Math.max(0, messageEl.offsetTop - thread.clientHeight / 3 + messageEl.offsetHeight / 2)
- messageEl.classList.add('highlight-mention')
- setTimeout(() => messageEl.classList.remove('highlight-mention'), 2500)
}
const newMessageHandler = (data) => {
@@ -144,21 +138,14 @@ watch(
if (!newUUID || newUUID === currentConversationUUID) return
currentConversationUUID = newUUID
unReadMessages.value = 0
- pendingScrollTo = route.query.scrollTo || null
- hasUserScrolled.value = !!pendingScrollTo
+ hasUserScrolled.value = !!route.query.scrollTo
}
)
watch(
() => conversationStore.conversationMessages.length,
(newLen, oldLen) => {
- if (pendingScrollTo && newLen > 0) {
- const target = pendingScrollTo
- pendingScrollTo = null
- nextTick(() => scrollToMessage(target))
- return
- }
- if (oldLen === 0 && newLen > 0) {
+ if (oldLen === 0 && newLen > 0 && !route.query.scrollTo) {
hasUserScrolled.value = false
nextTick(scrollToBottom)
}
diff --git a/frontend/shared-ui/composables/useStickyScroll.js b/frontend/shared-ui/composables/useStickyScroll.js
index 35fd9159..491511ae 100644
--- a/frontend/shared-ui/composables/useStickyScroll.js
+++ b/frontend/shared-ui/composables/useStickyScroll.js
@@ -22,6 +22,13 @@ export function useStickyScroll (scrollEl, contentEl, options = {}) {
el.scrollTop = el.scrollHeight
}
+ const scrollToOffset = (top) => {
+ const el = scrollEl.value
+ if (!el) return
+ isProgrammaticScroll = true
+ el.scrollTop = top
+ }
+
const handleScroll = () => {
if (isProgrammaticScroll) {
isProgrammaticScroll = false
@@ -50,5 +57,5 @@ export function useStickyScroll (scrollEl, contentEl, options = {}) {
if (resizeObserver) resizeObserver.disconnect()
})
- return { hasUserScrolled, scrollToBottom, handleScroll }
+ return { hasUserScrolled, scrollToBottom, scrollToOffset, handleScroll }
}