scrolling!

This commit is contained in:
Henry Jameson 2026-07-24 18:24:42 +03:00
commit bc762a9413
6 changed files with 43 additions and 44 deletions

View file

@ -72,6 +72,7 @@ export default (store) => {
() => import('src/components/chat_view/chat_view.vue'), () => import('src/components/chat_view/chat_view.vue'),
), ),
props: true, props: true,
meta: { dontScroll: true },
beforeEnter: validateAuthenticatedRoute, beforeEnter: validateAuthenticatedRoute,
}, },
{ name: 'quotes', path: '/notice/:id/quotes', component: QuotesTimeline }, { name: 'quotes', path: '/notice/:id/quotes', component: QuotesTimeline },

View file

@ -184,11 +184,6 @@ const ChatMessage = {
menuOpened: false, menuOpened: false,
} }
}, },
watch: {
focused: function (value) {
this.scrollIfFocused(value)
},
},
methods: { methods: {
onHover(bool) { onHover(bool) {
this.$emit('hover', { this.$emit('hover', {
@ -224,22 +219,6 @@ const ChatMessage = {
this.hovered = false this.hovered = false
this.menuOpened = false this.menuOpened = false
}, },
scrollIfFocused(focused) {
if (this.$el.getBoundingClientRect == null) return
if (focused) {
const rect = this.$el.getBoundingClientRect()
if (rect.top < 100) {
// Post is above screen, match its top to screen top
window.scrollBy(0, rect.top - 100)
} else if (rect.height >= window.innerHeight - 50) {
// Post we want to see is taller than screen so match its top to screen top
window.scrollBy(0, rect.top - 100)
} else if (rect.bottom > window.innerHeight - 50) {
// Post is below screen, match its bottom to screen bottom
window.scrollBy(0, rect.bottom - window.innerHeight + 50)
}
}
},
}, },
} }

View file

@ -3,6 +3,7 @@
v-if="isMessage" v-if="isMessage"
class="chat-message-wrapper" class="chat-message-wrapper"
:class="[classnames, { 'hovered-message-chain': hoveredMessageChain }]" :class="[classnames, { 'hovered-message-chain': hoveredMessageChain }]"
:id="`chatmessage-${message.id}`"
@mouseover="onHover(true)" @mouseover="onHover(true)"
@mouseleave="onHover(false)" @mouseleave="onHover(false)"
> >

View file

@ -86,9 +86,9 @@ const Chat = {
created() { created() {
if (this.testMode) return if (this.testMode) return
this.startFetching() this.startFetching()
window.addEventListener('resize', this.handleResize)
}, },
mounted() { mounted() {
window.addEventListener('resize', this.handleResize)
window.addEventListener('scroll', this.handleScroll) window.addEventListener('scroll', this.handleScroll)
if (typeof document.hidden !== 'undefined') { if (typeof document.hidden !== 'undefined') {
document.addEventListener( document.addEventListener(
@ -122,14 +122,11 @@ const Chat = {
) )
}, },
isConversation() { isConversation() {
return this.conversationId !== null return this.statusId !== null
}, },
recipient() { recipient() {
return this.chat?.account return this.chat?.account
}, },
recipientId() {
return this.$route.params.recipient_id
},
formPlaceholder() { formPlaceholder() {
if (this.recipient) { if (this.recipient) {
return this.$t('chats.message_user', { return this.$t('chats.message_user', {
@ -166,7 +163,8 @@ const Chat = {
}), }),
}, },
watch: { watch: {
messages() { messages(old, neu) {
if (old.length === neu.length) return
// We don't want to scroll to the bottom on a new message when the user is viewing older messages. // We don't want to scroll to the bottom on a new message when the user is viewing older messages.
// Therefore we need to know whether the scroll position was at the bottom before the DOM update. // Therefore we need to know whether the scroll position was at the bottom before the DOM update.
const bottomedOutBeforeUpdate = isBottomedOut(BOTTOMED_OUT_OFFSET) const bottomedOutBeforeUpdate = isBottomedOut(BOTTOMED_OUT_OFFSET)
@ -180,7 +178,38 @@ const Chat = {
await nextTick() // wait for changes to propagate to postStatusForm await nextTick() // wait for changes to propagate to postStatusForm
this.$refs.postStatusForm.update() this.$refs.postStatusForm.update()
}, },
$route: function () { $route: async function (newVal) {
if (this.messagesIndex[newVal.params.statusId]) {
const focused = document.getElementById(`chatmessage-${this.$route.params.statusId}`)
if (focused?.getBoundingClientRect == null) return
const bottomBoundary = window.innerHeight - this.$refs.footer.clientHeight
const topBoundary = this.$refs.header.clientHeight + document.getElementById('nav').clientHeight
const margin = Number(window.getComputedStyle(this.$refs.messageList.$el).gap.replace('px',''))
const rect = focused.getBoundingClientRect()
const scrollAmount = (() => {
if (rect.top < topBoundary) {
// Post is above screen, match its top to screen top
return rect.top - topBoundary - margin
} else if (rect.height >= bottomBoundary) {
// Post we want to see is taller than screen so match its top to screen top
return rect.top - topBoundary - margin
} else if (rect.bottom > bottomBoundary) {
// Post is below screen, match its bottom to screen bottom
return rect.bottom - bottomBoundary + margin
} else {
return 0
}
})()
if (scrollAmount !== 0) {
window.scrollBy(0, scrollAmount)
}
return
}
this.clear()
this.startFetching() this.startFetching()
}, },
mastoUserSocketStatus(newValue) { mastoUserSocketStatus(newValue) {
@ -295,6 +324,9 @@ const Chat = {
this.addMessages({ messages }) this.addMessages({ messages })
await nextTick() await nextTick()
if (isFirstFetch) {
this.scrollDown()
}
const fetchOlderMessages = !!maxId const fetchOlderMessages = !!maxId
if (fetchOlderMessages) { if (fetchOlderMessages) {

View file

@ -18,7 +18,7 @@
icon="chevron-left" icon="chevron-left"
/> />
</button> </button>
<div class="title text-center"> <div class="title">
<template v-if="isConversation"> <template v-if="isConversation">
<RichContent <RichContent
v-if="messages[0]?.summary" v-if="messages[0]?.summary"
@ -38,6 +38,7 @@
<div class="chat-list-wrapper panel-body"> <div class="chat-list-wrapper panel-body">
<div class="top-spacer" /> <div class="top-spacer" />
<ChatMessageList <ChatMessageList
ref="messageList"
header-date header-date
:messages="messages" :messages="messages"
:pending-messages="pendingMessages" :pending-messages="pendingMessages"

View file

@ -92,19 +92,4 @@
backdrop-filter: var(--__panel-backdrop-filter); backdrop-filter: var(--__panel-backdrop-filter);
} }
} }
.chat-view-reply-form {
position: sticky;
display: flex;
flex-direction: column;
align-items: stretch;
bottom: 0;
padding: 0;
}
.reply-to-text {
line-height: 1.2;
padding-top: 0.5em;
margin-bottom: -0.5em;
}
} }