-
Notifications
You must be signed in to change notification settings - Fork 10
/
Chat.vue
100 lines (93 loc) · 2.73 KB
/
Chat.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<script setup lang="ts">
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
import { ReceivedMessage, WrappedSocket } from '../common'
import Message from './Message.vue'
const { socket, channel, self } = defineProps<{
socket: WrappedSocket,
channel: string,
self: string
}>()
const messageContainerContainerRef = ref<{ $el: HTMLElement } | null>(null)
const messages = ref<ReceivedMessage[]>([])
const listener = (data: ReceivedMessage) => {
messages.value.push(data)
const isAtScrollEndBeforeRender = messageContainerContainerRef.value ? (messageContainerContainerRef.value.$el.scrollTop + messageContainerContainerRef.value?.$el.clientHeight === messageContainerContainerRef.value.$el.scrollHeight) : false
nextTick(() => {
if (messageContainerContainerRef.value) {
const el = messageContainerContainerRef.value.$el
if (isAtScrollEndBeforeRender || data.sender === self) {
el.scrollTop = el.scrollHeight
}
}
})
}
onMounted(() => {
socket.onMessage(listener)
socket.joinChannel(channel)
})
onUnmounted(() => {
socket.offMessage(listener)
socket.leaveChannel(channel)
})
const inputMessage = ref('')
const sendMessage = () => {
if (!inputMessage.value) return
socket.sendMessage(channel, {
type: 'text',
text: inputMessage.value,
})
inputMessage.value = ''
}
const uploadFile = async () => {
const [fileHandle] = await (<any>window).showOpenFilePicker()
const file: File = await fileHandle.getFile()
if (file.size > 1024 * 1024) {
alert('File too large')
return
}
const buf: ArrayBuffer = await new Promise(resolve => {
const fr = new FileReader()
fr.onload = () => resolve(<ArrayBuffer>fr.result)
fr.readAsArrayBuffer(file)
})
const { uuid } = await socket.uploadFile(file.name, buf)
socket.sendMessage(channel, {
type: 'file',
filename: file.name,
uuid: uuid,
})
}
</script>
<template>
<v-container class="container">
<v-row class="chat-area">
<v-col :cols="12" class="chat-area-inner" ref="messageContainerContainerRef">
<Message v-for="m in messages" :key="m.time" :message="m" />
</v-col>
</v-row>
<v-row class="flex-grow-0" style="justify-self: end; height: 100px;">
<v-col :cols="12">
<v-text-field v-model="inputMessage" label="Message" append-icon="mdi-send" @click:append="sendMessage"
@keydown.enter="sendMessage" prepend-icon="mdi-attachment" @click:prepend="uploadFile" required
autofocus></v-text-field>
</v-col>
</v-row>
</v-container>
</template>
<style scoped>
.container {
height: calc(100vh - 64px);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.chat-area {
height: calc(100vh - 64px - 110px);
max-height: calc(100vh - 64px - 110px);
flex: 0 0 auto;
}
.chat-area-inner {
overflow-y: scroll;
max-height: 100%;
}
</style>