wip
This commit is contained in:
8
package-lock.json
generated
8
package-lock.json
generated
@@ -17,7 +17,7 @@
|
|||||||
"tailwindcss": "^4.2.1",
|
"tailwindcss": "^4.2.1",
|
||||||
"tailwindcss-primeui": "^0.6.1",
|
"tailwindcss-primeui": "^0.6.1",
|
||||||
"vue": "^3.5.28",
|
"vue": "^3.5.28",
|
||||||
"vuetify": "^4.0.0"
|
"vuetify": "^4.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@mdi/font": "^7.4.47",
|
"@mdi/font": "^7.4.47",
|
||||||
@@ -5843,9 +5843,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vuetify": {
|
"node_modules/vuetify": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-4.0.2.tgz",
|
||||||
"integrity": "sha512-TRyNWd2KlX1KXbKwuHYRfrX24yLHq85AdVKmokfy5llAgVx7MNW4oBPwFmYLeuuSrWvw5ITtDJ5VjdBIKD5WVw==",
|
"integrity": "sha512-klgSGmfXoLajdTuuxreilzDQjp0ojzL2U5v6Z3ZbMYtpihPPXT9rkd/FxWL3dIGevnWdgaP2Kpwoz6aS/MISDA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"tailwindcss": "^4.2.1",
|
"tailwindcss": "^4.2.1",
|
||||||
"tailwindcss-primeui": "^0.6.1",
|
"tailwindcss-primeui": "^0.6.1",
|
||||||
"vue": "^3.5.28",
|
"vue": "^3.5.28",
|
||||||
"vuetify": "^4.0.0"
|
"vuetify": "^4.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@mdi/font": "^7.4.47",
|
"@mdi/font": "^7.4.47",
|
||||||
|
|||||||
@@ -5,7 +5,12 @@ const menuStore = useMenuStore()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VBtn icon="mdi-arrow-left" size="small" @click="menuStore.selected = 'chats'" />
|
<VBtn
|
||||||
|
icon="mdi-arrow-left"
|
||||||
|
color="default"
|
||||||
|
size="small"
|
||||||
|
@click="menuStore.selected = ['chats']"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type Chat } from '@/stores/chats.ts'
|
import { type Chat, useChatsStore } from '@/stores/chats.ts'
|
||||||
import { useAuthStore } from '@/stores/auth.ts'
|
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -8,18 +7,10 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { chat } = defineProps<Props>()
|
const { chat } = defineProps<Props>()
|
||||||
const authStore = useAuthStore()
|
const chatsStore = useChatsStore()
|
||||||
|
|
||||||
const chatName = computed(() => {
|
const chatName = computed(() => {
|
||||||
switch (chat.typeId) {
|
return chatsStore.getChatInfo(chat).name
|
||||||
case 1:
|
|
||||||
const otherUsers = chat.users.filter((user) => user.id !== authStore.me?.id)
|
|
||||||
return otherUsers[0]?.name ?? otherUsers[0]?.email ?? 'unknown'
|
|
||||||
case 2:
|
|
||||||
return chat.name
|
|
||||||
default:
|
|
||||||
return 'chat'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const lastMessage = computed(() => {
|
const lastMessage = computed(() => {
|
||||||
|
|||||||
@@ -1,44 +1,34 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useChatsStore } from '@/stores/chats.ts'
|
import { useChatsStore } from '@/stores/chats.ts'
|
||||||
import { SocketDataReq, useSocketsStore } from '@/stores/sockets.ts'
|
import { SocketDataReq, useSocketsStore } from '@/stores/sockets.ts'
|
||||||
import { onMounted, ref, watch, watchEffect } from 'vue'
|
import { watchEffect } from 'vue'
|
||||||
import { type SelectedMenu, useMenuStore } from '@/stores/menu.ts'
|
import { useMenuStore } from '@/stores/menu.ts'
|
||||||
import ChatListElement from '@/components/Chats/ChatListElement.vue'
|
import ChatListElement from '@/components/Chats/ChatListElement.vue'
|
||||||
|
|
||||||
const chatsStore = useChatsStore()
|
const chatsStore = useChatsStore()
|
||||||
const socketsStore = useSocketsStore()
|
const socketsStore = useSocketsStore()
|
||||||
const menuStore = useMenuStore()
|
const menuStore = useMenuStore()
|
||||||
const selected = ref<string[]>()
|
|
||||||
const menu = ref<string[]>()
|
|
||||||
|
|
||||||
watchEffect(() => getMessages(chatsStore.selected))
|
watchEffect(() => getMessages(chatsStore.selected))
|
||||||
watch(selected, (val) => {
|
|
||||||
if (val) chatsStore.selected = val[0]
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(menu, (val) => {
|
function getMessages([selected]: string[]) {
|
||||||
if (val) menuStore.selected = val[0] as SelectedMenu
|
if (selected) {
|
||||||
})
|
|
||||||
|
|
||||||
function getMessages(chatId?: string) {
|
|
||||||
if (!chatId) return
|
|
||||||
socketsStore.send({
|
socketsStore.send({
|
||||||
type: SocketDataReq.GET_MESSAGES,
|
type: SocketDataReq.GET_MESSAGES,
|
||||||
data: { chatId: chatId },
|
data: { chatId: selected },
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => console.log('CHAT LIST'))
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col h-full">
|
<div class="flex flex-col h-full">
|
||||||
<VToolbar class="px-2">
|
<VToolbar theme="dark" class="px-2">
|
||||||
<VMenu transition="slide-y-transition">
|
<VMenu transition="slide-y-transition">
|
||||||
<template v-slot:activator="{ props }">
|
<template v-slot:activator="{ props }">
|
||||||
<VBtn size="small" icon="mdi-menu" class="mr-2" v-bind="props" />
|
<VBtn size="small" icon="mdi-menu" class="mr-2" color="white" v-bind="props" />
|
||||||
</template>
|
</template>
|
||||||
<VList class="top-1" density="compact" slim v-model:selected="menu">
|
<VList class="top-1" density="compact" slim v-model:selected="menuStore.selected">
|
||||||
<VListItem value="users" title="Contacts" prepend-gap="8" prepend-icon="mdi-account" />
|
<VListItem value="users" title="Contacts" prepend-gap="8" prepend-icon="mdi-account" />
|
||||||
<VListItem value="settings" title="Settings" prepend-gap="8" prepend-icon="mdi-cog" />
|
<VListItem value="settings" title="Settings" prepend-gap="8" prepend-icon="mdi-cog" />
|
||||||
<VDivider class="my-1" />
|
<VDivider class="my-1" />
|
||||||
@@ -46,10 +36,10 @@ onMounted(() => console.log('CHAT LIST'))
|
|||||||
</VList>
|
</VList>
|
||||||
</VMenu>
|
</VMenu>
|
||||||
|
|
||||||
<VTextField bg-color="white" prepend-inner-icon="mdi-magnify" placeholder="search chat" />
|
<VTextField bg-color="black" prepend-inner-icon="mdi-magnify" placeholder="search chat" />
|
||||||
</VToolbar>
|
</VToolbar>
|
||||||
<VList v-model:selected="selected" mandatory lines="one">
|
<VList theme="dark" v-model:selected="chatsStore.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" :chat />
|
||||||
</VList>
|
</VList>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import SettingsList from '@/components/Settings/SettingsList.vue'
|
|||||||
const menuStore = useMenuStore()
|
const menuStore = useMenuStore()
|
||||||
|
|
||||||
const component = computed(() => {
|
const component = computed(() => {
|
||||||
switch (menuStore.selected) {
|
switch (menuStore.selected[0]) {
|
||||||
case 'chats':
|
case 'chats':
|
||||||
return ChatsList
|
return ChatsList
|
||||||
case 'users':
|
case 'users':
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { User } from '@/stores/users.ts'
|
interface Props {
|
||||||
|
name: string
|
||||||
|
image?: string
|
||||||
|
}
|
||||||
|
|
||||||
const {user} = defineProps<{ user: User }>()
|
const { name, image } = defineProps<Props>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VToolbar class="px-2">
|
<VToolbar theme="dark" class="px-2">
|
||||||
<VAvatar text="A" color="primary" />
|
<VAvatar text="A" color="primary" />
|
||||||
<VToolbarTitle :text="user.name" />
|
<VToolbarTitle :text="name" />
|
||||||
</VToolbar>
|
</VToolbar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -2,33 +2,27 @@
|
|||||||
import { computed, nextTick, ref, 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'
|
import type { User } from '@/stores/users.ts'
|
||||||
|
import { useChatsStore } from '@/stores/chats.ts'
|
||||||
|
|
||||||
const area = useTemplateRef('messageArea')
|
const chatsStore = useChatsStore()
|
||||||
|
|
||||||
|
// 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() {
|
// async function scrollToBottom() {
|
||||||
// await nextTick()
|
// await nextTick()
|
||||||
// if (area.value) y.value = area.value?.scrollHeight
|
// if (area.value) y.value = area.value?.scrollHeight
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const user = ref<User>({
|
|
||||||
id: 1,
|
|
||||||
name: 'test',
|
|
||||||
email: 'test@test.ru',
|
|
||||||
})
|
|
||||||
|
|
||||||
const messages = ref([])
|
const messages = ref([])
|
||||||
</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" v-if="chatsStore.selectedChat">
|
||||||
<slot name="toolbar" :user="user" />
|
<slot name="toolbar" :toolBarData="chatsStore.getChatInfo(chatsStore.selectedChat)" />
|
||||||
</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 :messages="messages" />
|
<slot :messages="messages" />
|
||||||
|
|||||||
@@ -7,29 +7,6 @@ const { messages } = defineProps<{ messages: Message[] }>()
|
|||||||
|
|
||||||
<template>
|
<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>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>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
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 MessagesList from '@/components/Messages/MessagesList.vue'
|
import MessagesList from '@/components/Messages/MessagesList.vue'
|
||||||
|
import { useChatsStore } from '@/stores/chats.ts'
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const chatsStore = useChatsStore()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full bg-gray-100">
|
<div class="h-full bg-gray-100">
|
||||||
<div class="flex flex-col h-full">
|
<div class="flex flex-col h-full">
|
||||||
<MessagesForm>
|
<MessagesForm v-if="chatsStore.selected.length">
|
||||||
<template #toolbar="{ user }">
|
<template #toolbar="{ toolBarData }">
|
||||||
<MessageToolbar :user />
|
<MessageToolbar :name="toolBarData.name" />
|
||||||
</template>
|
</template>
|
||||||
<template #default="{ messages }">
|
<template #default="{ messages }">
|
||||||
<MessagesList :messages />
|
<MessagesList :messages />
|
||||||
|
|||||||
@@ -23,20 +23,17 @@ function onStartChat(userId: number) {
|
|||||||
|
|
||||||
socketsStore.send({
|
socketsStore.send({
|
||||||
type: SocketDataReq.CREATE_CHAT,
|
type: SocketDataReq.CREATE_CHAT,
|
||||||
data: {
|
data: { userId: userId },
|
||||||
userId: userId,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col h-full">
|
<div class="flex flex-col h-full">
|
||||||
<VToolbar class="px-2">
|
<VToolbar theme="dark" class="px-2">
|
||||||
<BackToChats class="mr-2" />
|
<BackToChats class="mr-2" />
|
||||||
<VSheet class="w-full">
|
|
||||||
<VTextField prepend-inner-icon="mdi-magnify" placeholder="search contacts" />
|
<VTextField bg-color="black" prepend-inner-icon="mdi-magnify" placeholder="search contacts" />
|
||||||
</VSheet>
|
|
||||||
</VToolbar>
|
</VToolbar>
|
||||||
|
|
||||||
<VList>
|
<VList>
|
||||||
|
|||||||
@@ -33,7 +33,12 @@ const avatarText = computed(() => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<VBtn icon="mdi-message" color="default" slim size="small" @click="emit('click', user.id)" />
|
<VBtn
|
||||||
|
icon="mdi-message-outline"
|
||||||
|
variant="plain"
|
||||||
|
size="small"
|
||||||
|
@click="emit('click', user.id)"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import type { User } from '@/stores/users.ts'
|
import type { User } from '@/stores/users.ts'
|
||||||
import type { Message } from '@/stores/messages.ts'
|
import type { Message } from '@/stores/messages.ts'
|
||||||
|
import { useAuthStore } from '@/stores/auth.ts'
|
||||||
|
|
||||||
export interface Chat {
|
export interface Chat {
|
||||||
id: string
|
id: string
|
||||||
@@ -12,8 +13,31 @@ export interface Chat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useChatsStore = defineStore('chats', () => {
|
export const useChatsStore = defineStore('chats', () => {
|
||||||
|
const authStore = useAuthStore()
|
||||||
const chats = ref<Chat[]>([])
|
const chats = ref<Chat[]>([])
|
||||||
const selected = ref<string>()
|
const selected = ref<string[]>([])
|
||||||
|
|
||||||
return { chats, selected }
|
const selectedChat = computed(() => {
|
||||||
|
const chatId = selected.value[0]
|
||||||
|
|
||||||
|
return chats.value.find((chat: Chat) => {
|
||||||
|
return chat.id === chatId
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function getChatInfo(chat: Chat) {
|
||||||
|
switch (chat.typeId) {
|
||||||
|
case 1:
|
||||||
|
const user = chat.users.find((user) => {
|
||||||
|
return user.id !== authStore.me?.id
|
||||||
|
})
|
||||||
|
return user ?? chat
|
||||||
|
case 2:
|
||||||
|
return chat
|
||||||
|
default:
|
||||||
|
return chat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { chats, selected, selectedChat, getChatInfo }
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
export type SelectedMenu = 'chats' | 'users' | 'settings'
|
export type MenuItems = 'chats' | 'users' | 'settings'
|
||||||
|
|
||||||
export const useMenuStore = defineStore('menu', () => {
|
export const useMenuStore = defineStore('menu', () => {
|
||||||
const selected = ref<SelectedMenu>('chats')
|
const selected = ref<MenuItems[]>(['chats'])
|
||||||
|
|
||||||
return { selected }
|
return { selected }
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -76,8 +76,9 @@ export const useSocketsStore = defineStore('sockets', () => {
|
|||||||
const idx = chatsStore.chats.findIndex((chat) => chat.id === data.id)
|
const idx = chatsStore.chats.findIndex((chat) => chat.id === data.id)
|
||||||
if (idx < 0) chatsStore.chats.push(data)
|
if (idx < 0) chatsStore.chats.push(data)
|
||||||
|
|
||||||
menuStore.selected = 'chats'
|
console.log(data.id)
|
||||||
chatsStore.selected = data.id
|
menuStore.selected = ['chats']
|
||||||
|
chatsStore.selected = [data.id]
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
@@ -114,6 +115,7 @@ export const useSocketsStore = defineStore('sockets', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const send = (data: unknown) => {
|
const send = (data: unknown) => {
|
||||||
|
console.log(COMMAND.SEND, data)
|
||||||
postMessage(COMMAND.SEND, data)
|
postMessage(COMMAND.SEND, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ onMounted(() => {
|
|||||||
</LeftPane>
|
</LeftPane>
|
||||||
</div>
|
</div>
|
||||||
<div class="md:w-2/3 sm:w-1/2 w-1/2">
|
<div class="md:w-2/3 sm:w-1/2 w-1/2">
|
||||||
<RightPane></RightPane>
|
<RightPane />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user