This commit is contained in:
2026-03-12 20:50:31 +03:00
parent 5a188b80e3
commit 43366a5089
9 changed files with 90 additions and 49 deletions

View File

@@ -45,9 +45,8 @@ onMounted(() => console.log('CHAT LIST'))
<VListItem value="logout" title="Log Out" /> <VListItem value="logout" title="Log Out" />
</VList> </VList>
</VMenu> </VMenu>
<VSheet class="w-full">
<VTextField prepend-inner-icon="mdi-magnify" placeholder="search chat" /> <VTextField bg-color="white" prepend-inner-icon="mdi-magnify" placeholder="search chat" />
</VSheet>
</VToolbar> </VToolbar>
<VList v-model:selected="selected" mandatory lines="one"> <VList v-model:selected="selected" mandatory lines="one">
<ChatListElement v-for="chat in chatsStore.chats" :key="chat.id" v-bind="{ chat }" /> <ChatListElement v-for="chat in chatsStore.chats" :key="chat.id" v-bind="{ chat }" />

View File

@@ -8,7 +8,6 @@ import SettingsList from '@/components/Settings/SettingsList.vue'
const menuStore = useMenuStore() const menuStore = useMenuStore()
const component = computed(() => { const component = computed(() => {
console.log(menuStore.selected)
switch (menuStore.selected) { switch (menuStore.selected) {
case 'chats': case 'chats':
return ChatsList return ChatsList

View File

@@ -2,10 +2,10 @@
import { computed } from 'vue' import { computed } from 'vue'
const props = withDefaults( const props = withDefaults(
defineProps<{ createdAt?: string; username?: string; my?: boolean; text?: string }>(), defineProps<{ createdAt?: string; username?: string; onRightSide?: boolean; message?: string }>(),
{ {
my: false, my: false,
text: 'foobar', message: 'foobar',
username: 'robot', username: 'robot',
}, },
) )
@@ -35,14 +35,14 @@ const avatarLetter = computed(() => {
<!-- </div>--> <!-- </div>-->
<!-- </div>--> <!-- </div>-->
<div class="flex gap-2 border" :class="{ 'flex-row-reverse': props.my }"> <div class="flex gap-2" :class="{ 'flex-row-reverse': props.onRightSide }">
<!-- <v-avatar size="36" color="deep-purple-lighten-4">--> <!-- <v-avatar size="36" color="deep-purple-lighten-4">-->
<!-- <span class="text-deep-purple-darken-2">{{ avatarLetter }}</span>--> <!-- <span class="text-deep-purple-darken-2">{{ avatarLetter }}</span>-->
<!-- </v-avatar>--> <!-- </v-avatar>-->
<!-- :class="props.my ? 'message-shaped-right' : 'message-shaped'"--> <!-- :class="props.my ? 'message-shaped-right' : 'message-shaped'"-->
<div class="pa-4" :class="props.my ? 'bg-blue-400' : 'bg-white'"> <div class="pa-4" :class="props.onRightSide ? 'bg-blue-400' : 'bg-white'">
<span class="">{{ props.text }}</span> <span class="">{{ props.message }}</span>
<span class="">{{ createdAt }}</span> <span class="">{{ createdAt }}</span>
</div> </div>
</div> </div>

View File

@@ -27,13 +27,18 @@ const isEmptyText = computed(() => {
</script> </script>
<template> <template>
<div class="d-flex ga-2 border pa-4"> <div class="flex gap-2 pa-2 items-center">
<input v-model="text" placeholder="message" @keyup.enter="sendMessage" /> <VTextField
<button><span class="mdi mdi-emoticon-outline"></span></button> prepend-inner-icon="mdi-emoticon-outline"
<button><span class="mdi mdi-paperclip"></span></button> append-inner-icon="mdi-paperclip"
<button :disabled="isEmptyText" @click="sendMessage"> bg-color="white"
<span class="mdi mdi-send"></span> v-model="text"
</button> placeholder="message"
density="default"
@keyup.enter="sendMessage"
/>
<VBtn :disabled="isEmptyText" icon="mdi-send" @click="sendMessage" color="primary" />
</div> </div>
</template> </template>

View File

@@ -1,9 +1,13 @@
<script setup lang="ts"></script> <script setup lang="ts">
import type { User } from '@/stores/users.ts'
const {user} = defineProps<{ user: User }>()
</script>
<template> <template>
<VToolbar class="px-2"> <VToolbar class="px-2">
<VAvatar text="A" color="primary" /> <VAvatar text="A" color="primary" />
<VToolbarTitle text="Message title" /> <VToolbarTitle :text="user.name" />
</VToolbar> </VToolbar>
</template> </template>

View File

@@ -1,28 +1,37 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, nextTick, useTemplateRef, watch } from 'vue' import { computed, nextTick, ref, useTemplateRef, watch } from 'vue'
import { useScroll } from '@vueuse/core' import { useScroll } from '@vueuse/core'
import type { User } from '@/stores/users.ts'
const area = useTemplateRef('messageArea') const area = useTemplateRef('messageArea')
const { y, arrivedState } = useScroll(area) // const { y, arrivedState } = useScroll(area)
const messages = computed(() => { // const messages = computed(() => {
// return [...messagesStore.messages] // return [...messagesStore.messages]
// })
// async function scrollToBottom() {
// await nextTick()
// if (area.value) y.value = area.value?.scrollHeight
// }
const user = ref<User>({
id: 1,
name: 'test',
email: 'test@test.ru',
}) })
async function scrollToBottom() { const messages = ref([])
await nextTick()
if (area.value) y.value = area.value?.scrollHeight
}
</script> </script>
<template> <template>
<div class="flex h-full flex-col overflow-hidden"> <div class="flex h-full flex-col overflow-hidden">
<div class="grow-0"> <div class="grow-0">
<slot name="toolbar" /> <slot name="toolbar" :user="user" />
</div> </div>
<div class="px-8 gap-2 grow flex flex-col-reverse overflow-y-auto" ref="messageArea"> <div class="px-8 gap-2 grow flex flex-col-reverse overflow-y-auto" ref="messageArea">
<slot /> <slot :messages="messages" />
</div> </div>
<div class="grow-0"> <div class="grow-0">
<slot name="input" /> <slot name="input" />

View File

@@ -0,0 +1,35 @@
<script setup lang="ts">
import MessageData from '@/components/Messages/MessageData.vue'
import type { Message } from '@/stores/messages.ts'
const { messages } = defineProps<{ messages: Message[] }>()
</script>
<template>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData on-right-side>Hello world</MessageData>
<MessageData on-right-side>Hello world</MessageData>
<MessageData on-right-side>Hello world</MessageData>
<MessageData on-right-side>Hello world</MessageData>
<MessageData on-right-side>Hello world</MessageData>
<MessageData on-right-side>Hello world</MessageData>
<MessageData on-right-side>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
<MessageData>Hello world</MessageData>
</template>
<style scoped></style>

View File

@@ -3,34 +3,20 @@ import { useAuthStore } from '@/stores/auth.ts'
import MessagesForm from '@/components/Messages/MessagesForm.vue' import MessagesForm from '@/components/Messages/MessagesForm.vue'
import MessageToolbar from '@/components/Messages/MessageToolbar.vue' import MessageToolbar from '@/components/Messages/MessageToolbar.vue'
import MessageInput from '@/components/Messages/MessageInput.vue' import MessageInput from '@/components/Messages/MessageInput.vue'
import MessageData from '@/components/Messages/MessageData.vue' import MessagesList from '@/components/Messages/MessagesList.vue'
import { ref } from 'vue'
import type { Message } from '@/stores/messages.ts'
const authStore = useAuthStore() const authStore = useAuthStore()
// watch(messages, async () => {
// await scrollToBottom()
// })
const messages = ref<Message[]>([])
</script> </script>
<template> <template>
<div class="h-full bg-gray-300"> <div class="h-full bg-gray-100">
<div class="flex flex-col h-full"> <div class="flex flex-col h-full">
<MessagesForm> <MessagesForm>
<template #toolbar> <template #toolbar="{ user }">
<MessageToolbar /> <MessageToolbar :user />
</template> </template>
<template #default> <template #default="{ messages }">
<MessageData <MessagesList :messages />
v-for="message in messages"
:key="message.id"
:text="message.message"
:my="authStore.me?.id === message.userId"
:created-at="message.createdAt"
/>
</template> </template>
<template #input> <template #input>
<MessageInput /> <MessageInput />

View File

@@ -58,16 +58,18 @@ export const useSocketsStore = defineStore('sockets', () => {
worker.value.port.onmessage = (event) => { worker.value.port.onmessage = (event) => {
const { type, data, connected, message } = event.data const { type, data, connected, message } = event.data
console.log('Received message', data)
switch (type) { switch (type) {
case SocketDataRes.USERS: case SocketDataRes.USERS:
console.log('Received from back: USERS', data)
usersStore.users = data usersStore.users = data
break break
case SocketDataRes.USER: case SocketDataRes.USER:
console.log('Received from back: USER', data)
authStore.me = data authStore.me = data
break break
case SocketDataRes.CHATS: case SocketDataRes.CHATS:
console.log('Received from back: CHATS', data)
if (Array.isArray(data)) { if (Array.isArray(data)) {
chatsStore.chats = data chatsStore.chats = data
} else { } else {
@@ -80,12 +82,14 @@ export const useSocketsStore = defineStore('sockets', () => {
break break
case SocketDataRes.MESSAGES: case SocketDataRes.MESSAGES:
console.log('Received from back: MESSAGES', data)
messagesStore.messages = data messagesStore.messages = data
// if (options.onMessage) { // if (options.onMessage) {
// options.onMessage(data) // options.onMessage(data)
// } // }
break break
case SocketDataRes.MESSAGE: case SocketDataRes.MESSAGE:
console.log('Received from back: MESSAGE', data)
messagesStore.messages.unshift(data) messagesStore.messages.unshift(data)
break break
case SocketDataRes.STATUS: case SocketDataRes.STATUS: