wip
This commit is contained in:
30
package-lock.json
generated
30
package-lock.json
generated
@@ -16,7 +16,8 @@
|
|||||||
"primevue": "^4.5.4",
|
"primevue": "^4.5.4",
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@mdi/font": "^7.4.47",
|
"@mdi/font": "^7.4.47",
|
||||||
@@ -5841,6 +5842,33 @@
|
|||||||
"typescript": ">=5.0.0"
|
"typescript": ">=5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vuetify": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-TRyNWd2KlX1KXbKwuHYRfrX24yLHq85AdVKmokfy5llAgVx7MNW4oBPwFmYLeuuSrWvw5ITtDJ5VjdBIKD5WVw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/johnleider"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">=4.7",
|
||||||
|
"vite-plugin-vuetify": ">=2.1.0",
|
||||||
|
"vue": "^3.5.0",
|
||||||
|
"webpack-plugin-vuetify": ">=3.1.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"vite-plugin-vuetify": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"webpack-plugin-vuetify": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|||||||
@@ -23,7 +23,8 @@
|
|||||||
"primevue": "^4.5.4",
|
"primevue": "^4.5.4",
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@mdi/font": "^7.4.47",
|
"@mdi/font": "^7.4.47",
|
||||||
|
|||||||
10
src/App.vue
10
src/App.vue
@@ -2,17 +2,15 @@
|
|||||||
import { useAuthStore } from '@/stores/auth.ts'
|
import { useAuthStore } from '@/stores/auth.ts'
|
||||||
import SignInView from '@/views/SignInView.vue'
|
import SignInView from '@/views/SignInView.vue'
|
||||||
import MainView from '@/views/MainView.vue'
|
import MainView from '@/views/MainView.vue'
|
||||||
import TestView from '@/views/TestView.vue'
|
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-screen bg-gray-200">
|
<div class="h-screen bg-gray-500">
|
||||||
<div class="h-full m-auto p-4">
|
<div class="h-full m-auto py-4 md:w-4/5 sm:w-full w-full">
|
||||||
<!-- <MainView v-if="authStore.isAuth" />-->
|
<MainView v-if="authStore.isAuth" />
|
||||||
<!-- <SignInView v-else />-->
|
<SignInView v-else />
|
||||||
<TestView />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
@import "tailwindcss-primeui";
|
|
||||||
@import "primeicons/primeicons.css";
|
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-family: "Montserrat", sans-serif;
|
font-family: "Montserrat", sans-serif;
|
||||||
font-optical-sizing: auto;
|
font-optical-sizing: auto;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-component, .p-component * {
|
|
||||||
}
|
|
||||||
|
|||||||
13
src/assets/main_.css
Normal file
13
src/assets/main_.css
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
@import "tailwindcss-primeui";
|
||||||
|
@import "primeicons/primeicons.css";
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
font-family: "Montserrat", sans-serif;
|
||||||
|
font-optical-sizing: auto;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-component, .p-component * {}
|
||||||
@@ -9,32 +9,44 @@ interface Props {
|
|||||||
|
|
||||||
const { chat } = defineProps<Props>()
|
const { chat } = defineProps<Props>()
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
const chatsStore = useChatsStore()
|
|
||||||
|
|
||||||
const getChatName = computed(() => {
|
const chatName = computed(() => {
|
||||||
if (chat.type_id === 2) {
|
switch (chat.type_id) {
|
||||||
return chat.name
|
case 1:
|
||||||
} else if (chat.type_id === 1) {
|
|
||||||
const otherUsers = chat.users.filter((user) => user.id !== authStore.me?.id)
|
const otherUsers = chat.users.filter((user) => user.id !== authStore.me?.id)
|
||||||
return otherUsers[0]?.name ?? otherUsers[0]?.email ?? 'unknown'
|
return otherUsers[0]?.name ?? otherUsers[0]?.email ?? 'unknown'
|
||||||
|
case 2:
|
||||||
|
return chat.name
|
||||||
|
default:
|
||||||
|
return 'chat'
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'unknown ID'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const isSelected = computed(() => {
|
const avatarText = computed(() => {
|
||||||
return chatsStore.selected === chat.id
|
return chatName.value.slice(0, 1).toUpperCase()
|
||||||
|
})
|
||||||
|
|
||||||
|
const lastMessageCreatedAt = computed(() => {
|
||||||
|
return new Date().toLocaleTimeString('ru-RU', { timeStyle: 'short' })
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="border p-2" :class="{ 'bg-gray-400': isSelected }">
|
<VListItem :value="chat.id">
|
||||||
<!-- {{ chat }}-->
|
<template v-slot:prepend>
|
||||||
<div>id:{{ chat.id }}</div>
|
<VAvatar color="primary" :text="avatarText" />
|
||||||
<div>name:{{ chat.name }}</div>
|
</template>
|
||||||
<div>type:{{ chat.type_id }}</div>
|
|
||||||
<div>chatName:{{ getChatName }}</div>
|
<template v-slot:append>
|
||||||
|
<div class="flex flex-col justify-end">
|
||||||
|
<div class="text-xs">{{ lastMessageCreatedAt }}</div>
|
||||||
|
<VChip size="small">12</VChip>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<v-list-item-title>{{ chatName }}</v-list-item-title>
|
||||||
|
<v-list-item-subtitle>subtitle</v-list-item-subtitle>
|
||||||
|
</VListItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -2,12 +2,24 @@
|
|||||||
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 ChatListElement from '@/components/ChatListElement.vue'
|
import ChatListElement from '@/components/ChatListElement.vue'
|
||||||
import { onMounted, watchEffect } from 'vue'
|
import { onMounted, ref, watch, watchEffect } from 'vue'
|
||||||
|
import { type SelectedMenu, useMenuStore } from '@/stores/menu.ts'
|
||||||
|
|
||||||
const chatsStore = useChatsStore()
|
const chatsStore = useChatsStore()
|
||||||
const socketsStore = useSocketsStore()
|
const socketsStore = useSocketsStore()
|
||||||
|
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) => {
|
||||||
|
console.log(val)
|
||||||
|
if (val) menuStore.selected = val[0] as SelectedMenu
|
||||||
|
})
|
||||||
|
|
||||||
function getMessages(chatId?: string) {
|
function getMessages(chatId?: string) {
|
||||||
if (!chatId) return
|
if (!chatId) return
|
||||||
@@ -17,28 +29,36 @@ function getMessages(chatId?: string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSelect(id: string) {
|
|
||||||
chatsStore.selected = id
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => console.log('CHAT LIST'))
|
onMounted(() => console.log('CHAT LIST'))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-2 h-full overflow-hidden px-2">
|
<div class="flex flex-col h-full">
|
||||||
<div>chats</div>
|
<VToolbar>
|
||||||
|
<VMenu transition="slide-y-transition">
|
||||||
<!-- <div class="overflow-y-auto">-->
|
<template v-slot:activator="{ props }">
|
||||||
<!-- <div v-for="i in 30" :key="i" class="pa-4 border">bla</div>-->
|
<VBtn icon="mdi-menu" v-bind="props" />
|
||||||
<!-- </div>-->
|
</template>
|
||||||
<div class="flex flex-col gap-2 h-full overflow-y-auto">
|
<VList class="top-1" density="compact" slim v-model:selected="menu">
|
||||||
<chat-list-element
|
<VListItem density="compact" value="profile" prepend-gap="8" title="Profile">
|
||||||
v-for="chat in chatsStore.chats"
|
<template #prepend>
|
||||||
:key="chat.id"
|
<VAvatar color="primary" text="A" />
|
||||||
v-bind="{ chat }"
|
</template>
|
||||||
@click="onSelect(chat.id)"
|
</VListItem>
|
||||||
/>
|
<VDivider class="my-1" />
|
||||||
</div>
|
<VListItem value="users" title="Contacts" prepend-gap="8" prepend-icon="mdi-account" />
|
||||||
|
<VListItem value="settings" title="Settings" prepend-gap="8" prepend-icon="mdi-cog" />
|
||||||
|
<VDivider class="my-1" />
|
||||||
|
<VListItem value="logout" title="Log Out" />
|
||||||
|
</VList>
|
||||||
|
</VMenu>
|
||||||
|
<VSheet class="w-full mx-2">
|
||||||
|
<VTextField prepend-inner-icon="mdi-magnify" label="search chat"></VTextField>
|
||||||
|
</VSheet>
|
||||||
|
</VToolbar>
|
||||||
|
<VList v-model:selected="selected" mandatory>
|
||||||
|
<ChatListElement v-for="chat in chatsStore.chats" :key="chat.id" v-bind="{ chat }" />
|
||||||
|
</VList>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ function getChatName(chat: Chat) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full flex flex-col h-full gap-2">
|
<div class="flex flex-col h-full gap-2">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ watch(messages, async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full h-full bg-blue-200 border">
|
<div class="h-full">
|
||||||
<!-- <button class="position-absolute scroll-down" @click="scrollToBottom">UP</button>-->
|
<!-- <button class="position-absolute scroll-down" @click="scrollToBottom">UP</button>-->
|
||||||
<div class="flex flex-col h-full">
|
<div class="flex flex-col h-full">
|
||||||
<div class="flex h-full flex-col overflow-hidden">
|
<div class="flex h-full flex-col overflow-hidden">
|
||||||
|
|||||||
@@ -30,8 +30,13 @@ function onStartChat(userId: number) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-2 h-full overflow-hidden px-2">
|
<div class="flex flex-col h-full">
|
||||||
<div>contacts</div>
|
<VToolbar>
|
||||||
|
<VBtn icon="mdi-arrow-left"></VBtn>
|
||||||
|
<VSheet class="w-full mx-2">
|
||||||
|
<VTextField prepend-inner-icon="mdi-magnify" label="search contacts"></VTextField>
|
||||||
|
</VSheet>
|
||||||
|
</VToolbar>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2 h-full overflow-y-auto">
|
<div class="flex flex-col gap-2 h-full overflow-y-auto">
|
||||||
<UsersListElement
|
<UsersListElement
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts"></script>
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-16 flex flex-col gap-2 items-stretch p-1 border">
|
<div class="flex flex-col gap-2 items-stretch p-1 border">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
30
src/main.ts
30
src/main.ts
@@ -3,17 +3,39 @@ import './assets/main.css'
|
|||||||
|
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
import PrimeVue from 'primevue/config'
|
// import PrimeVue from 'primevue/config'
|
||||||
|
|
||||||
|
import 'vuetify/styles'
|
||||||
|
import { createVuetify } from 'vuetify'
|
||||||
|
import * as components from 'vuetify/components'
|
||||||
|
import * as directives from 'vuetify/directives'
|
||||||
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import { version } from 'vue'
|
import { version } from 'vue'
|
||||||
import theme from '@/themes/noir.ts'
|
import theme from '@/themes/noir.ts'
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
console.log('version', version)
|
console.log('version', version)
|
||||||
|
|
||||||
app.use(PrimeVue, { theme: theme })
|
// app.use(PrimeVue, { theme: theme })
|
||||||
app.use(createPinia())
|
|
||||||
|
|
||||||
|
const vuetify = createVuetify({
|
||||||
|
components,
|
||||||
|
directives,
|
||||||
|
theme: { defaultTheme: 'light' },
|
||||||
|
icons: {
|
||||||
|
defaultSet: 'mdi',
|
||||||
|
},
|
||||||
|
defaults: {
|
||||||
|
VAvatar: { density: 'compact' },
|
||||||
|
VChip: { density: 'compact' },
|
||||||
|
VBtn: { color: 'black', variant: 'flat' },
|
||||||
|
VSwitch: { color: 'black', hideDetails: true },
|
||||||
|
VOtpInput: { density: 'compact' },
|
||||||
|
VTextField: { color: 'black', density: 'compact', variant: 'outlined', hideDetails: true },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
app.use(vuetify)
|
||||||
|
|
||||||
|
app.use(createPinia())
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ 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:
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted } from 'vue'
|
import { computed, onMounted } from 'vue'
|
||||||
import { useSocketsStore } from '@/stores/sockets.ts'
|
import { useSocketsStore } from '@/stores/sockets.ts'
|
||||||
import AppMenu from '@/components/AppMenu.vue'
|
|
||||||
import LeftPane from '@/components/LeftPane.vue'
|
import LeftPane from '@/components/LeftPane.vue'
|
||||||
import RightPane from '@/components/RightPane.vue'
|
import RightPane from '@/components/RightPane.vue'
|
||||||
import UsersList from '@/components/Users/UsersList.vue'
|
import UsersList from '@/components/Users/UsersList.vue'
|
||||||
@@ -13,6 +12,7 @@ const socketsStore = useSocketsStore()
|
|||||||
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
|
||||||
@@ -32,13 +32,14 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex h-full">
|
<div class="flex h-full">
|
||||||
<div class="flex w-full">
|
<div class="md:w-1/3 sm:w-1/2 w-1/2 bg-white">
|
||||||
<AppMenu />
|
|
||||||
<LeftPane>
|
<LeftPane>
|
||||||
<component :is="component" />
|
<component :is="component" />
|
||||||
</LeftPane>
|
</LeftPane>
|
||||||
</div>
|
</div>
|
||||||
<RightPane />
|
<div class="md:w-2/3 sm:w-1/2 w-1/2">
|
||||||
|
<RightPane></RightPane>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,48 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useAuthStore } from '@/stores/auth.ts'
|
import { useAuthStore } from '@/stores/auth.ts'
|
||||||
import { JustButton, JustInput } from '@/components/simple'
|
// import {
|
||||||
|
// Button,
|
||||||
|
// InputText,
|
||||||
|
// Card,
|
||||||
|
// InputOtp,
|
||||||
|
// ToggleSwitch,
|
||||||
|
// Divider,
|
||||||
|
// IconField,
|
||||||
|
// InputIcon,
|
||||||
|
// } from 'primevue'
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
const email = ref('vadim.olonin@gmail.com')
|
const email = ref('vadim.olonin@gmail.com')
|
||||||
const name = ref('')
|
const name = ref('Vadim')
|
||||||
|
const otp = ref('123456')
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
await authStore.login(email.value)
|
await authStore.login(email.value)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full flex flex-col justify-center items-center">
|
<div class="h-full flex flex-col justify-center items-center px-4">
|
||||||
<div class="bg-white border border-gray-500 p-4 rounded-md w-64">
|
<VCard class="w-full md:w-1/2">
|
||||||
<form @submit.prevent="onSubmit">
|
<template #title>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="text-2xl">Sign in</div>
|
||||||
<div class="">Sign in</div>
|
</template>
|
||||||
<JustInput v-model="email" placeholder="email" type="email" class="" />
|
<template #text>
|
||||||
<input v-if="false" v-model="name" placeholder="name" />
|
<form @submit.prevent="onSubmit" class="flex flex-col gap-4">
|
||||||
<div class="flex justify-end">
|
<VTextField v-model="email" placeholder="email" />
|
||||||
<input type="checkbox" v-if="false" />
|
<VTextField v-model="name" placeholder="name" />
|
||||||
<JustButton type="submit">sign in</JustButton>
|
<div class="flex justify-center">
|
||||||
|
<VOtpInput v-model="otp" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex items-center justify-between gap-2">
|
||||||
|
<VSwitch hide-details label="Keep me signed in" />
|
||||||
|
<VBtn type="submit">Sign In</VBtn>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</template>
|
||||||
|
</VCard>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user