120 lines
2.7 KiB
Vue
120 lines
2.7 KiB
Vue
<template>
|
|
<div class="chat-messages">
|
|
<div v-if="messageGroups.length" ref="scroll" class="chat-messages__list">
|
|
<ChatMessageGroup
|
|
v-for="group in messageGroups"
|
|
:key="`group-${group.messages[0].id}`"
|
|
:group="group"
|
|
/>
|
|
</div>
|
|
|
|
<ChadSpinner v-if="isFetching" class="chat-messages__spinner" />
|
|
|
|
<div v-if="!arrivedState.start" class="chat-messages__floating-actions">
|
|
<div v-if="hasUnreadMessages" class="chat-messages__has-unread-messages">
|
|
New messages
|
|
</div>
|
|
|
|
<ChadToBottom
|
|
class="chat-messages__scroll-to-bottom"
|
|
@click="scrollToStart()"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import ChadSpinner from '@shared/components/ui/Spinner.vue'
|
|
import ChadToBottom from '@shared/components/ui/ToBottom.vue'
|
|
import { useEventBus } from '@shared/composables/use-event-bus.ts'
|
|
import { useChatScroll } from '@widgets/chat/composables/use-chat-scroll.ts'
|
|
import ChatMessageGroup from '@widgets/chat/ui/ChatMessageGroup.vue'
|
|
import { onUnmounted, ref, useTemplateRef, watch } from 'vue'
|
|
import { useChatHistory } from '../composables/use-chat-history'
|
|
|
|
const eventBus = useEventBus()
|
|
|
|
const scrollRef = useTemplateRef('scroll')
|
|
|
|
const { messageGroups, hasMoreMessages, loadMoreMessages, isFetching } = useChatHistory()
|
|
|
|
const hasUnreadMessages = ref(false)
|
|
|
|
const { arrivedState, scrollToStart } = useChatScroll(scrollRef, {
|
|
startOffset: 100,
|
|
endOffset: 100,
|
|
})
|
|
|
|
watch(() => arrivedState.end, (arrived) => {
|
|
if (!arrived)
|
|
return
|
|
|
|
if (hasMoreMessages.value) {
|
|
loadMoreMessages()
|
|
}
|
|
})
|
|
|
|
watch(() => arrivedState.start, () => {
|
|
hasUnreadMessages.value = false
|
|
})
|
|
|
|
eventBus.on('chat:new-message', onNewChatMessage)
|
|
|
|
onUnmounted(() => {
|
|
eventBus.off('chat:new-message', onNewChatMessage)
|
|
})
|
|
|
|
function onNewChatMessage() {
|
|
if (!arrivedState.start) {
|
|
hasUnreadMessages.value = true
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.chat-messages {
|
|
position: relative;
|
|
overflow: hidden;
|
|
|
|
&__spinner {
|
|
position: absolute;
|
|
top: var(--space-4);
|
|
left: 50%;
|
|
translate: -50% 0;
|
|
z-index: 1;
|
|
}
|
|
|
|
&__list {
|
|
overflow-x: hidden;
|
|
overflow-y: auto;
|
|
overflow-y: overlay;
|
|
overflow-anchor: none;
|
|
|
|
position: relative;
|
|
max-height: 100%;
|
|
}
|
|
|
|
&__floating-actions {
|
|
position: absolute;
|
|
display: inline-flex;
|
|
align-items: flex-end;
|
|
gap: var(--space-2);
|
|
bottom: var(--space-4);
|
|
right: var(--space-4);
|
|
pointer-events: none;
|
|
}
|
|
|
|
&__has-unread-messages {
|
|
@include font-micro;
|
|
|
|
background-color: var(--yellow);
|
|
padding: var(--space-1) var(--space-2);
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
&__scroll-to-bottom {
|
|
pointer-events: auto;
|
|
}
|
|
}
|
|
</style>
|