init
This commit is contained in:
@@ -17,7 +17,7 @@ const userStore = useUserStore();
|
||||
const {renderMarkdown} = useMarkdown()
|
||||
|
||||
const messageContainer = ref<HTMLElement | null>(null);
|
||||
const {messages, loading, loadingBefore, loadingAfter} = storeToRefs(messageStore);
|
||||
const {messages, loading, loadingBefore, loadingAfter, hasMoreAfter, isAtBottom} = storeToRefs(messageStore);
|
||||
const newMessage = ref('');
|
||||
|
||||
const SCROLL_LOAD_THRESHOLD = 120;
|
||||
@@ -26,6 +26,10 @@ const paginationLock = ref<'before' | 'after' | null>(null);
|
||||
const paginationLockScrollTop = ref(0);
|
||||
const lastScrollTop = ref(0);
|
||||
|
||||
const showRecentMessagesButton = computed(() =>
|
||||
!loading.value && (hasMoreAfter.value || !isAtBottom.value),
|
||||
);
|
||||
|
||||
interface ScrollAnchor {
|
||||
id: string;
|
||||
top: number;
|
||||
@@ -36,6 +40,8 @@ const scrollToBottom = async () => {
|
||||
if (messageContainer.value) {
|
||||
messageContainer.value.scrollTop = messageContainer.value.scrollHeight;
|
||||
messageStore.setAtBottom(true);
|
||||
paginationLock.value = null;
|
||||
lastScrollTop.value = messageContainer.value.scrollTop;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -153,6 +159,12 @@ const sendMessage = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const returnToRecentMessages = async () => {
|
||||
paginationLock.value = null;
|
||||
await messageStore.fetchMessages(channelId.value);
|
||||
await scrollToBottom();
|
||||
};
|
||||
|
||||
// Only explicit initial loads and realtime messages received while at the
|
||||
// bottom request an automatic scroll. Pagination restores its own anchor.
|
||||
watch(messages, async () => {
|
||||
@@ -169,7 +181,7 @@ watch(channelId, async (newChannelId) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-container class="pa-0 fill-height d-flex flex-column" fluid>
|
||||
<v-container class="pa-0 fill-height d-flex flex-column channel-layout" fluid>
|
||||
<div
|
||||
ref="messageContainer"
|
||||
class="flex-grow-1 overflow-y-auto w-100 message-container"
|
||||
@@ -211,6 +223,22 @@ watch(channelId, async (newChannelId) => {
|
||||
<v-progress-linear v-if="loadingAfter" color="primary" indeterminate />
|
||||
</div>
|
||||
|
||||
<div v-if="showRecentMessagesButton" class="recent-messages-button">
|
||||
<v-tooltip location="top" text="Revenir aux messages récents">
|
||||
<template #activator="{ props: tooltipProps }">
|
||||
<v-btn
|
||||
v-bind="tooltipProps"
|
||||
aria-label="Revenir aux messages récents"
|
||||
color="primary"
|
||||
elevation="4"
|
||||
icon="mdi-arrow-down-bold"
|
||||
:loading="loading"
|
||||
@click="returnToRecentMessages"
|
||||
/>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
|
||||
<v-sheet class="pa-4 flex-shrink-0" width="100%">
|
||||
<v-textarea
|
||||
v-model="newMessage"
|
||||
@@ -244,6 +272,17 @@ watch(channelId, async (newChannelId) => {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.channel-layout {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.recent-messages-button {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
bottom: 92px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.markdown-content :deep(p) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user