mirror of
https://github.com/danbulant/Nertivia-Client
synced 2026-06-14 12:01:06 +00:00
merged server and dm tab component
This commit is contained in:
parent
7f527a8627
commit
fabbdc57c0
17 changed files with 419 additions and 555 deletions
|
|
@ -1,62 +1,61 @@
|
|||
<template>
|
||||
<div class="left-panel">
|
||||
<navigation />
|
||||
<div class="content">
|
||||
<MyMiniInformation />
|
||||
<div class="tabs">
|
||||
<div
|
||||
class="tab"
|
||||
:class="{ notify: friendRequestExists, selected: currentTab === 0 }"
|
||||
@click="currentTab = 0"
|
||||
>
|
||||
<div class="material-icons">group</div>
|
||||
Friends
|
||||
</div>
|
||||
<div
|
||||
class="tab"
|
||||
:class="{ notify: DMNotification, selected: currentTab === 1 }"
|
||||
@click="currentTab = 1"
|
||||
>
|
||||
<div class="material-icons">access_time</div>
|
||||
Recents
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="currentTab === 0" class="list">
|
||||
<pending-friends />
|
||||
<online-friends />
|
||||
<offline-friends />
|
||||
</div>
|
||||
<div v-else class="list">
|
||||
<recent-friends />
|
||||
<div class="friend-left-panel">
|
||||
<!-- <navigation /> -->
|
||||
<MyMiniInformation />
|
||||
<div class="tabs">
|
||||
<div
|
||||
class="tab"
|
||||
:class="{ notify: friendRequestExists, selected: currentTab === 0 }"
|
||||
@click="currentTab = 0"
|
||||
>
|
||||
<div class="material-icons">group</div>
|
||||
Friends
|
||||
</div>
|
||||
<div
|
||||
class="button"
|
||||
:class="{ selected: uniqueIDSelected }"
|
||||
@click="saveNotesBtn"
|
||||
class="tab"
|
||||
:class="{ notify: DMNotification, selected: currentTab === 1 }"
|
||||
@click="currentTab = 1"
|
||||
>
|
||||
<div class="material-icons">notes</div>
|
||||
<div class="name">Saved Notes</div>
|
||||
<div class="material-icons">access_time</div>
|
||||
Recents
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="currentTab === 0" class="list">
|
||||
<!-- <pending-friends />
|
||||
<online-friends />
|
||||
<offline-friends /> -->
|
||||
<friends-tab />
|
||||
</div>
|
||||
<div v-else class="list">
|
||||
<recent-friends-tab />
|
||||
</div>
|
||||
<div
|
||||
class="button"
|
||||
:class="{ selected: uniqueIDSelected }"
|
||||
@click="saveNotesBtn"
|
||||
>
|
||||
<div class="material-icons">notes</div>
|
||||
<div class="name">Saved Notes</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MyMiniInformation from "../../components/app/MyMiniInformation.vue";
|
||||
import PendingFriends from "./relationships/PendingFriends.vue";
|
||||
import OnlineFriends from "./relationships/OnlineFriends.vue";
|
||||
import OfflineFriends from "./relationships/OfflineFriends.vue";
|
||||
import RecentFriends from "./relationships/RecentFriends.vue";
|
||||
import Navigation from "@/components/app/Navigation";
|
||||
// import PendingFriends from "./relationships/PendingFriends.vue";
|
||||
// import OnlineFriends from "./relationships/OnlineFriends.vue";
|
||||
// import OfflineFriends from "./relationships/OfflineFriends.vue";
|
||||
import RecentFriendsTab from "./relationships/RecentFriendsTab.vue";
|
||||
import FriendsTab from "./relationships/FriendsTab.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MyMiniInformation,
|
||||
PendingFriends,
|
||||
OnlineFriends,
|
||||
OfflineFriends,
|
||||
RecentFriends,
|
||||
Navigation
|
||||
// PendingFriends,
|
||||
// OnlineFriends,
|
||||
// OfflineFriends,
|
||||
FriendsTab,
|
||||
RecentFriendsTab
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -119,23 +118,17 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.left-panel {
|
||||
.friend-left-panel {
|
||||
height: 100%;
|
||||
width: 340px;
|
||||
max-width: calc(100% - 60px);
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
z-index: 1;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
z-index: 1;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
background: rgba(0, 0, 0, 0.14);
|
||||
border-top-left-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.list {
|
||||
flex: 1;
|
||||
|
|
@ -165,7 +158,7 @@ export default {
|
|||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
.tab:hover{
|
||||
.tab:hover {
|
||||
color: white;
|
||||
}
|
||||
.tab.selected {
|
||||
|
|
@ -259,7 +252,7 @@ export default {
|
|||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.content {
|
||||
.friend-left-panel {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="navigation" ref="navigation">
|
||||
<div class="main navigation" ref="navigation">
|
||||
<div
|
||||
class="tool-tip"
|
||||
ref="toolTip"
|
||||
|
|
|
|||
|
|
@ -167,7 +167,6 @@ export default {
|
|||
width: 300px;
|
||||
max-width: calc(100% - 60px);
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.14);
|
||||
}
|
||||
.header {
|
||||
height: 50px;
|
||||
|
|
|
|||
|
|
@ -125,16 +125,15 @@ export default {
|
|||
margin-right: 10px;
|
||||
margin-left: 5px;
|
||||
flex-shrink: 0;
|
||||
transition: 0.3s;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
.clickable {
|
||||
color: white;
|
||||
transition: 0.3s;
|
||||
cursor: default;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
transition: 0.2s;
|
||||
cursor: pointer;
|
||||
}
|
||||
.clickable:hover {
|
||||
color: rgb(219, 219, 219);
|
||||
text-decoration: underline;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@media (max-width: 949px) {
|
||||
|
|
|
|||
|
|
@ -1,35 +1,33 @@
|
|||
<template>
|
||||
<div class="left-panel">
|
||||
<navigation />
|
||||
<div class="right">
|
||||
<MyMiniInformation />
|
||||
<div
|
||||
class="server-banner"
|
||||
@mouseenter="bannerHover = true"
|
||||
@mouseleave="bannerHover = false"
|
||||
:class="{ extendBanner: server && server.banner }"
|
||||
v-if="selectedServerID"
|
||||
>
|
||||
<img
|
||||
class="banner-image"
|
||||
@click="bannerImageClicked"
|
||||
v-if="server && server.banner"
|
||||
:src="
|
||||
`${bannerDomain}${server.banner}${bannerHover ? '' : '?type=webp'}`
|
||||
"
|
||||
/>
|
||||
<div class="sub-banner">
|
||||
<div class="text" :title="servers[selectedServerID].name">
|
||||
{{ servers[selectedServerID].name }}
|
||||
</div>
|
||||
<div class="options-button material-icons" @click="openServerContext">
|
||||
more_vert
|
||||
</div>
|
||||
<div class="server-left-panel">
|
||||
<!-- <navigation /> -->
|
||||
<MyMiniInformation />
|
||||
<div
|
||||
class="server-banner"
|
||||
@mouseenter="bannerHover = true"
|
||||
@mouseleave="bannerHover = false"
|
||||
:class="{ extendBanner: server && server.banner }"
|
||||
v-if="selectedServerID"
|
||||
>
|
||||
<img
|
||||
class="banner-image"
|
||||
@click="bannerImageClicked"
|
||||
v-if="server && server.banner"
|
||||
:src="
|
||||
`${bannerDomain}${server.banner}${bannerHover ? '' : '?type=webp'}`
|
||||
"
|
||||
/>
|
||||
<div class="sub-banner">
|
||||
<div class="text" :title="servers[selectedServerID].name">
|
||||
{{ servers[selectedServerID].name }}
|
||||
</div>
|
||||
<div class="options-button material-icons" @click="openServerContext">
|
||||
more_vert
|
||||
</div>
|
||||
</div>
|
||||
<div class="channels-list">
|
||||
<channels-list v-if="selectedServerID" :server-i-d="selectedServerID" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="channels-list">
|
||||
<channels-list v-if="selectedServerID" :server-i-d="selectedServerID" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -37,14 +35,12 @@
|
|||
<script>
|
||||
import MyMiniInformation from "@/components/app/MyMiniInformation.vue";
|
||||
import ChannelsList from "@/components/app/ServerTemplate/ChannelsList.vue";
|
||||
import Navigation from "@/components/app/Navigation.vue";
|
||||
import config from "@/config";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MyMiniInformation,
|
||||
ChannelsList,
|
||||
Navigation
|
||||
ChannelsList
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -120,22 +116,17 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.left-panel {
|
||||
.server-left-panel {
|
||||
height: 100%;
|
||||
width: 340px;
|
||||
max-width: calc(100% - 60px);
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: column;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.seperater {
|
||||
height: 1px;
|
||||
width: calc(100% - 10px);
|
||||
align-self: center;
|
||||
background-color: #a0c8d5;
|
||||
flex-shrink: 0;
|
||||
flex: 1;
|
||||
background: rgba(0, 0, 0, 0.14);
|
||||
overflow: hidden;
|
||||
border-top-left-radius: 10px;
|
||||
}
|
||||
|
||||
.channels-list {
|
||||
|
|
@ -144,17 +135,6 @@ export default {
|
|||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: rgba(0, 0, 0, 0.14);
|
||||
border-top-left-radius: 10px;
|
||||
}
|
||||
|
||||
.server-banner {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
|
|
@ -228,7 +208,7 @@ export default {
|
|||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.right {
|
||||
.server-left-panel {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,85 +0,0 @@
|
|||
<template>
|
||||
<div class="direct-message-tab" :class="{ darken: showLeftPanel }">
|
||||
<transition name="slidein">
|
||||
<friends-list
|
||||
v-show="($mq === 'mobile' && showLeftPanel) || $mq !== 'mobile'"
|
||||
v-click-outside="hideLeftPanel"
|
||||
class="left-panel"
|
||||
/>
|
||||
</transition>
|
||||
<message-panel :type="0" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { bus } from "@/main";
|
||||
|
||||
import FriendsList from "@/components/app/FriendsList.vue";
|
||||
import MessagePanel from "@/components/app/MessagePanel.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FriendsList,
|
||||
MessagePanel
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showLeftPanel: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
bus.$on("toggleLeftMenu", () => {
|
||||
this.showLeftPanel = !this.showLeftPanel;
|
||||
});
|
||||
bus.$on("closeLeftMenu", () => {
|
||||
this.showLeftPanel = false;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
hideLeftPanel(event) {
|
||||
if (this.showLeftPanel) {
|
||||
if (event.target.closest(".show-menu-button") == null) {
|
||||
this.showLeftPanel = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.direct-message-tab {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.left-panel {
|
||||
z-index: 2;
|
||||
}
|
||||
.slidein-enter-active,
|
||||
.slidein-leave-active {
|
||||
transition: 0.5s;
|
||||
}
|
||||
.slidein-enter, .slidein-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
||||
/* margin-left: -300px; */
|
||||
transform: translateX(-340px);
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.left-panel {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
z-index: 2;
|
||||
background: linear-gradient(to bottom, #00477e 0, #016dc0);
|
||||
}
|
||||
.darken::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -371,6 +371,9 @@ export default {
|
|||
background: linear-gradient(to bottom, #00477e 0, #016dc0);
|
||||
height: 100%;
|
||||
}
|
||||
.left-panel .content {
|
||||
border-radius: 0;
|
||||
}
|
||||
.darken::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
|
|
@ -382,4 +385,5 @@ export default {
|
|||
background: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -3,18 +3,23 @@
|
|||
class="direct-message-tab"
|
||||
:class="{ darken: showLeftPanel || showMembersPanel }"
|
||||
>
|
||||
<transition name="slide-left">
|
||||
<server-list
|
||||
<transition :name="$mq === 'mobile' ? 'slide-left' : null">
|
||||
<div
|
||||
class="left-panel"
|
||||
v-show="($mq === 'mobile' && showLeftPanel) || $mq !== 'mobile'"
|
||||
v-click-outside="hideLeftPanel"
|
||||
class="left-panel"
|
||||
/>
|
||||
>
|
||||
<navigation />
|
||||
<server-list v-if="currentTab === 2" />
|
||||
<friends-list v-if="currentTab === 1" />
|
||||
</div>
|
||||
</transition>
|
||||
<message-panel :type="1" />
|
||||
<message-panel :type="currentTab === 1 ? 0 : currentTab === 2 ? 1 : null" />
|
||||
<transition :name="$mq !== 'desktop' ? 'slide-right' : 'none'">
|
||||
<members-list
|
||||
v-if="
|
||||
selectedServerID &&
|
||||
currentTab === 2 &&
|
||||
((($mq === 'members_panel' || $mq === 'mobile') &&
|
||||
showMembersPanel) ||
|
||||
$mq === 'desktop')
|
||||
|
|
@ -28,16 +33,20 @@
|
|||
|
||||
<script>
|
||||
import { bus } from "@/main";
|
||||
|
||||
import ServerList from "@/components/app/ServerList.vue";
|
||||
import MessagePanel from "@/components/app/MessagePanel.vue";
|
||||
import MembersList from "@/components/app/MembersList.vue";
|
||||
import Navigation from "@/components/app/Navigation.vue";
|
||||
|
||||
const FriendsList = () => import("@/components/app/FriendsList.vue");
|
||||
const MembersList = () => import("@/components/app/MembersList.vue");
|
||||
const ServerList = () => import("@/components/app/ServerList.vue");
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ServerList,
|
||||
FriendsList,
|
||||
MessagePanel,
|
||||
MembersList
|
||||
MembersList,
|
||||
Navigation
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -59,7 +68,9 @@ export default {
|
|||
methods: {
|
||||
hideLeftPanel(event) {
|
||||
if (this.showLeftPanel) {
|
||||
if (event.target.closest(".show-menu-button") == null) {
|
||||
const closestMenuBtn = event.target.closest(".show-menu-button");
|
||||
const closestNavBtn = event.target.closest(".main.navigation");
|
||||
if (closestMenuBtn === null && closestNavBtn === null) {
|
||||
this.showLeftPanel = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -73,6 +84,9 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
currentTab() {
|
||||
return this.$store.getters.currentTab;
|
||||
},
|
||||
selectedServerID() {
|
||||
return this.$store.getters["servers/selectedServerID"];
|
||||
}
|
||||
|
|
@ -86,6 +100,13 @@ export default {
|
|||
}
|
||||
.left-panel {
|
||||
z-index: 2;
|
||||
height: 100%;
|
||||
width: 340px;
|
||||
max-width: calc(100% - 60px);
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.slide-left-enter-active,
|
||||
181
src/components/app/relationships/FriendsTab.vue
Normal file
181
src/components/app/relationships/FriendsTab.vue
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
<template>
|
||||
<div class="friends">
|
||||
<virtual-list :size="50" :remain="15" v-if="loaded" :variable="true">
|
||||
<div class="tab" v-if="friends[0].length" :style="{ height: '25px' }">
|
||||
Pending
|
||||
</div>
|
||||
<pending-template
|
||||
v-for="friend of friends[0]"
|
||||
:key="friend.recipient.uniqueID"
|
||||
:friend="friend"
|
||||
:style="{ height: '55px' }"
|
||||
/>
|
||||
<div class="tab" v-if="friends[1].length || friends[2].length">
|
||||
Online
|
||||
</div>
|
||||
<div
|
||||
class="none-online"
|
||||
:style="{ height: '29px' }"
|
||||
v-if="!friends[1].length && friends[2].length"
|
||||
>
|
||||
All of your friends are offline.
|
||||
</div>
|
||||
<friends-template
|
||||
v-for="friend of friends[1]"
|
||||
:key="friend.recipient.uniqueID"
|
||||
:friend="friend"
|
||||
:recipient="friend.recipient"
|
||||
:style="{ height: '50px' }"
|
||||
/>
|
||||
<div class="tab">Offline</div>
|
||||
<div
|
||||
class="none-online"
|
||||
:style="{ height: '29px' }"
|
||||
v-if="!friends[2].length && !friends[1].length"
|
||||
>
|
||||
Add some friends.
|
||||
</div>
|
||||
<friends-template
|
||||
v-for="friend of friends[2]"
|
||||
:key="friend.recipient.uniqueID"
|
||||
:friend="friend"
|
||||
:recipient="friend.recipient"
|
||||
:style="{ height: '50px' }"
|
||||
/>
|
||||
</virtual-list>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VirtualList from "vue-virtual-scroll-list";
|
||||
import FriendsTemplate from "./FriendsTemplate.vue";
|
||||
import PendingTemplate from "./PendingTemplate.vue";
|
||||
export default {
|
||||
components: {
|
||||
FriendsTemplate,
|
||||
PendingTemplate,
|
||||
VirtualList
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loaded: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
setTimeout(() => (this.loaded = true));
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.getters.user;
|
||||
},
|
||||
channels() {
|
||||
const json = this.$store.getters.channels;
|
||||
const notifications = this.$store.getters.notifications;
|
||||
|
||||
const keys = Object.keys(json);
|
||||
let result = [];
|
||||
keys.forEach(key => {
|
||||
if (
|
||||
json[key].recipients &&
|
||||
json[key].recipients.length > 0 &&
|
||||
!json[key].server_id &&
|
||||
json[key].recipients[0].uniqueID !== this.user.uniqueID
|
||||
)
|
||||
result.push(json[key]);
|
||||
});
|
||||
|
||||
result.sort(function(a, b) {
|
||||
const notificationA = notifications.find(item => {
|
||||
return item.channelID === a.channelID;
|
||||
});
|
||||
const notificationB = notifications.find(item => {
|
||||
return item.channelID === b.channelID;
|
||||
});
|
||||
// make notifications more prority.
|
||||
if (notificationA) return -1;
|
||||
if (notificationB) return 1;
|
||||
if (a.lastMessaged === undefined) return 1;
|
||||
if (b.lastMessaged === undefined) return -1;
|
||||
return b.lastMessaged - a.lastMessaged;
|
||||
});
|
||||
|
||||
// gets unopened dms
|
||||
const notificationsFiltered = notifications.filter(item => {
|
||||
if (json[item.channelID] && json[item.channelID].server_id) return;
|
||||
const find = result.find(resFind => {
|
||||
return resFind.channelID === item.channelID;
|
||||
});
|
||||
if (!find) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (let index in notificationsFiltered) {
|
||||
notificationsFiltered[index].creator = "dummy";
|
||||
notificationsFiltered[index].recipients = [
|
||||
notificationsFiltered[index].sender
|
||||
];
|
||||
}
|
||||
result = notificationsFiltered.concat(result);
|
||||
return result;
|
||||
},
|
||||
friends() {
|
||||
const allFriends = Object.values(this.$store.getters.user.friends);
|
||||
const members = this.$store.getters["members/members"];
|
||||
const presences = this.$store.getters["members/presences"];
|
||||
|
||||
let pendingFriends = [];
|
||||
let onlineFriends = [];
|
||||
let offlineFriends = [];
|
||||
for (let index = 0; index < allFriends.length; index++) {
|
||||
let friend = allFriends[index];
|
||||
const presence = presences[friend.uniqueID];
|
||||
friend.recipient = members[friend.uniqueID];
|
||||
|
||||
if (friend.status < 2) {
|
||||
pendingFriends.push(friend);
|
||||
continue;
|
||||
}
|
||||
if (!presence || presence === 0) {
|
||||
offlineFriends.push(friend);
|
||||
continue;
|
||||
}
|
||||
onlineFriends.push(friend);
|
||||
}
|
||||
return [pendingFriends, onlineFriends, offlineFriends];
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.friends {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
user-select: none;
|
||||
transition: 0.3s;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 25px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
padding-left: 10px;
|
||||
}
|
||||
.none-online {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
align-self: center;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.spacer {
|
||||
display: flex;
|
||||
height: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,36 +1,38 @@
|
|||
<template>
|
||||
<div
|
||||
class="friend"
|
||||
:class="{ selected: uniqueIDSelected, tree }"
|
||||
@click="openChat"
|
||||
@mouseover="mouseOverEvent"
|
||||
@mouseleave="hover = false"
|
||||
>
|
||||
<div class="friend">
|
||||
<div
|
||||
class="profile-picture"
|
||||
:style="`border-color: ${status.statusColor};`"
|
||||
@click="openUserInformation"
|
||||
class="wrapper"
|
||||
:class="{ selected: uniqueIDSelected }"
|
||||
@click="openChat"
|
||||
@mouseover="mouseOverEvent"
|
||||
@mouseleave="hover = false"
|
||||
>
|
||||
<img
|
||||
class="avatar"
|
||||
:src="`${userAvatar}${hover || !isGif ? '' : '?type=webp'}`"
|
||||
/>
|
||||
<div
|
||||
class="status"
|
||||
:style="`background-image: url(${status.statusURL})`"
|
||||
/>
|
||||
</div>
|
||||
<div class="information">
|
||||
<div class="username">{{ recipient.username }}</div>
|
||||
<div class="status-name">{{ status.statusName }}</div>
|
||||
</div>
|
||||
<div v-if="notifications && notifications > 0" class="notification">
|
||||
<div class="notification-inner">{{ notifications }}</div>
|
||||
</div>
|
||||
<!-- doesnt work properly. if both channels closed, the chat gets wiped. -->
|
||||
<!-- <div v-else-if="recents" class="material-icons close-button" @click="closeChannel">
|
||||
class="profile-picture"
|
||||
:style="`border-color: ${status.statusColor};`"
|
||||
@click="openUserInformation"
|
||||
>
|
||||
<img
|
||||
class="avatar"
|
||||
:src="`${userAvatar}${hover || !isGif ? '' : '?type=webp'}`"
|
||||
/>
|
||||
<div
|
||||
class="status"
|
||||
:style="`background-image: url(${status.statusURL})`"
|
||||
/>
|
||||
</div>
|
||||
<div class="information">
|
||||
<div class="username">{{ recipient.username }}</div>
|
||||
<div class="status-name">{{ status.statusName }}</div>
|
||||
</div>
|
||||
<div v-if="notifications && notifications > 0" class="notification">
|
||||
<div class="notification-inner">{{ notifications }}</div>
|
||||
</div>
|
||||
<!-- doesnt work properly. if both channels closed, the chat gets wiped. -->
|
||||
<!-- <div v-else-if="recents" class="material-icons close-button" @click="closeChannel">
|
||||
close
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -41,16 +43,7 @@ import statuses from "@/utils/statuses";
|
|||
import { bus } from "@/main";
|
||||
|
||||
export default {
|
||||
// tree will add padding to the left.
|
||||
props: [
|
||||
"username",
|
||||
"tag",
|
||||
"channelID",
|
||||
"uniqueID",
|
||||
"recipient",
|
||||
"tree",
|
||||
"recents"
|
||||
],
|
||||
props: ["friend", "recents", "recipient"],
|
||||
data() {
|
||||
return {
|
||||
hover: false,
|
||||
|
|
@ -62,15 +55,18 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
notifications() {
|
||||
const channelID = this.$props.channelID;
|
||||
const channels = this.$store.getters.channels;
|
||||
const recipient = this.recipient;
|
||||
|
||||
const notifications = this.$store.getters.notifications.find(function(e) {
|
||||
if (channels[e.channelID] && channels[e.channelID].server_id) return;
|
||||
return e.channelID == channelID;
|
||||
const channel = channels[e.channelID];
|
||||
if (channel && channel.server_id) return;
|
||||
return e.sender.uniqueID === recipient.uniqueID;
|
||||
});
|
||||
|
||||
if (
|
||||
!notifications ||
|
||||
(this.$props.channelID === this.$store.getters.selectedChannelID &&
|
||||
(this.friend.channelID === this.$store.getters.selectedChannelID &&
|
||||
document.hasFocus())
|
||||
)
|
||||
return;
|
||||
|
|
@ -107,8 +103,7 @@ export default {
|
|||
}
|
||||
},
|
||||
async closeChannel() {
|
||||
this.channelID;
|
||||
await channelService.delete(this.channelID);
|
||||
await channelService.delete(this.friend.channelID);
|
||||
},
|
||||
async openChat(event) {
|
||||
if (
|
||||
|
|
@ -125,12 +120,12 @@ export default {
|
|||
document.hasFocus()
|
||||
) {
|
||||
this.$socket.client.emit("notification:dismiss", {
|
||||
channelID: this.channelID
|
||||
channelID: this.friend.channelID
|
||||
});
|
||||
}
|
||||
this.$store.dispatch("openChat", {
|
||||
uniqueID: this.recipient.uniqueID,
|
||||
channelID: this.channelID,
|
||||
channelID: this.friend.channelID,
|
||||
channelName: this.recipient.username
|
||||
});
|
||||
},
|
||||
|
|
@ -149,26 +144,32 @@ export default {
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
.friend {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
padding: 5px;
|
||||
height: 50px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
height: 34px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
.wrapper {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
display: flex;
|
||||
height: 45px;
|
||||
width: 100%;
|
||||
transition: 0.3s;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
margin: 5px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.tree {
|
||||
padding-left: 22px;
|
||||
padding-left: 10px;
|
||||
margin-left: 3px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.friend:hover {
|
||||
.wrapper:hover {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
color: white;
|
||||
}
|
||||
.friend.selected {
|
||||
.wrapper.selected {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
color: white;
|
||||
}
|
||||
|
|
@ -227,7 +228,7 @@ export default {
|
|||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.friend:hover .status {
|
||||
.wrapper:hover .status {
|
||||
opacity: 1;
|
||||
bottom: -4px;
|
||||
}
|
||||
|
|
@ -239,7 +240,7 @@ export default {
|
|||
color: #b7cbce;
|
||||
height: 0;
|
||||
}
|
||||
.friend:hover .status-name {
|
||||
.wrapper:hover .status-name {
|
||||
opacity: 1;
|
||||
height: 13px;
|
||||
}
|
||||
|
|
@ -256,7 +257,7 @@ export default {
|
|||
.close-button:hover {
|
||||
color: white;
|
||||
}
|
||||
.friend:hover .close-button {
|
||||
.wrapper:hover .close-button {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,78 +0,0 @@
|
|||
<template>
|
||||
<div class="friends">
|
||||
<Tab
|
||||
@click.native="expanded = !expanded"
|
||||
:expanded="expanded"
|
||||
tabname="Offline"
|
||||
/>
|
||||
<transition name="list">
|
||||
<div v-if="expanded" class="list">
|
||||
<FriendsTemplate
|
||||
v-for="(friend, key) of friends"
|
||||
:key="key"
|
||||
:channel-i-d="friend.channelID"
|
||||
:recipient="friends[key].recipient"
|
||||
:tree="true"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tab from "./Tab.vue";
|
||||
import FriendsTemplate from "./FriendsTemplate.vue";
|
||||
export default {
|
||||
components: {
|
||||
Tab,
|
||||
FriendsTemplate
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: true
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
friends() {
|
||||
const allFriend = this.$store.getters.user.friends;
|
||||
const members = this.$store.getters["members/members"];
|
||||
const presences = this.$store.getters["members/presences"];
|
||||
const result = Object.keys(allFriend).map(function(key) {
|
||||
allFriend[key].recipient = members[allFriend[key].uniqueID];
|
||||
return allFriend[key];
|
||||
});
|
||||
return result.filter(
|
||||
friend =>
|
||||
friend.status == 2 &&
|
||||
(!presences[friend.uniqueID] || presences[friend.uniqueID] == 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.list-enter-active,
|
||||
.list-leave-active {
|
||||
transition: 0.3s;
|
||||
}
|
||||
.list-enter, .list-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
||||
transform: translateY(-20px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.friends {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
user-select: none;
|
||||
padding-bottom: 3px;
|
||||
border-radius: 5px;
|
||||
transition: 0.3s;
|
||||
}
|
||||
.tab {
|
||||
transition: 0.3s;
|
||||
margin: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.tab:hover {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
<template>
|
||||
<div class="friends">
|
||||
<Tab
|
||||
@click.native="expanded = !expanded"
|
||||
:expanded="expanded"
|
||||
tabname="Online"
|
||||
/>
|
||||
<transition name="list">
|
||||
<div v-if="expanded" class="list">
|
||||
<FriendsTemplate
|
||||
v-for="(friend, key) of friends"
|
||||
:key="key"
|
||||
:channel-i-d="friend.channelID"
|
||||
:recipient="friends[key].recipient"
|
||||
:tree="true"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tab from "./Tab.vue";
|
||||
import FriendsTemplate from "./FriendsTemplate.vue";
|
||||
export default {
|
||||
components: {
|
||||
Tab,
|
||||
FriendsTemplate
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: true
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
friends() {
|
||||
const allFriend = this.$store.getters.user.friends;
|
||||
const members = this.$store.getters["members/members"];
|
||||
const presences = this.$store.getters["members/presences"];
|
||||
const notifications = this.$store.getters.notifications;
|
||||
const channels = this.$store.getters.channels;
|
||||
|
||||
const result = Object.keys(allFriend).map(function(key) {
|
||||
const friend = allFriend[key];
|
||||
friend.recipient = members[friend.uniqueID];
|
||||
|
||||
const findNotification = notifications.find(e => {
|
||||
return (
|
||||
e.sender.uniqueID === friend.recipient.uniqueID &&
|
||||
!channels[e.channelID].server_id
|
||||
);
|
||||
});
|
||||
|
||||
if (findNotification) {
|
||||
friend.channelID = findNotification.channelID;
|
||||
}
|
||||
|
||||
return friend;
|
||||
});
|
||||
return result.filter(
|
||||
friend =>
|
||||
friend.status == 2 &&
|
||||
presences[friend.uniqueID] &&
|
||||
presences[friend.uniqueID] > 0
|
||||
);
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.list-enter-active,
|
||||
.list-leave-active {
|
||||
transition: 0.3s;
|
||||
}
|
||||
.list-enter, .list-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
||||
transform: translateY(-20px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.friends {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
user-select: none;
|
||||
padding-bottom: 3px;
|
||||
transition: 0.3s;
|
||||
}
|
||||
.tab {
|
||||
transition: 0.3s;
|
||||
margin: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.tab:hover {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
<template>
|
||||
<div class="pending-friends" v-if="friends && friends.length">
|
||||
<Tab
|
||||
@click.native="expanded = !expanded"
|
||||
:expanded="expanded"
|
||||
tabname="Pending requests"
|
||||
/>
|
||||
<transition name="list">
|
||||
<div v-if="expanded" class="list">
|
||||
<PendingTemplate
|
||||
v-for="(friend, key) of friends"
|
||||
:key="key"
|
||||
:unique-i-d="friend.recipient.uniqueID"
|
||||
:status="friend.status"
|
||||
:username="friend.recipient.username"
|
||||
:tag="friend.recipient.tag"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tab from "./Tab.vue";
|
||||
import PendingTemplate from "./PendingTemplate.vue";
|
||||
export default {
|
||||
components: {
|
||||
Tab,
|
||||
PendingTemplate
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: true
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
friends() {
|
||||
const allFriend = this.$store.getters.user.friends;
|
||||
const members = this.$store.getters["members/members"];
|
||||
const result = Object.keys(allFriend).map(function(key) {
|
||||
allFriend[key].recipient = members[allFriend[key].uniqueID];
|
||||
return allFriend[key];
|
||||
});
|
||||
return result.filter(friend => friend.status < 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.list-enter-active,
|
||||
.list-leave-active {
|
||||
transition: 0.3s;
|
||||
}
|
||||
.list-enter, .list-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
||||
transform: translateY(-20px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.pending-friends {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
user-select: none;
|
||||
padding-bottom: 3px;
|
||||
transition: 0.3s;
|
||||
}
|
||||
.tab {
|
||||
transition: 0.3s;
|
||||
margin: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.tab:hover {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -7,13 +7,13 @@
|
|||
/>
|
||||
<div class="information">
|
||||
<div class="username">
|
||||
{{ $props.username }}
|
||||
{{ friend.recipient.username }}
|
||||
</div>
|
||||
<div class="tag">@{{ $props.tag }}</div>
|
||||
<div class="tag">@{{ friend.recipient.tag }}</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<div
|
||||
:class="{ button: true, accept: true, hide: $props.status == 0 }"
|
||||
:class="{ button: true, accept: true, hide: friend.status == 0 }"
|
||||
@click="accept"
|
||||
>
|
||||
<i class="material-icons">
|
||||
|
|
@ -34,10 +34,11 @@ import RelationshipService from "@/services/RelationshipService.js";
|
|||
import config from "@/config.js";
|
||||
|
||||
export default {
|
||||
props: ["username", "tag", "status", "uniqueID"],
|
||||
props: ["friend"],
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.getters.user.friends[this.$props.uniqueID].recipient;
|
||||
return this.$store.getters.user.friends[this.friend.recipient.uniqueID]
|
||||
.recipient;
|
||||
},
|
||||
userAvatar() {
|
||||
return config.domain + "/avatars/" + this.user.avatar;
|
||||
|
|
@ -45,13 +46,16 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
deny() {
|
||||
RelationshipService.delete(this.$props.uniqueID);
|
||||
RelationshipService.delete(this.friend.recipient.uniqueID);
|
||||
},
|
||||
accept() {
|
||||
RelationshipService.put(this.$props.uniqueID);
|
||||
RelationshipService.put(this.friend.recipient.uniqueID);
|
||||
},
|
||||
openUserInformation() {
|
||||
this.$store.dispatch("setUserInformationPopout", this.uniqueID);
|
||||
this.$store.dispatch(
|
||||
"setUserInformationPopout",
|
||||
this.friend.recipient.uniqueID
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -59,7 +63,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.username {
|
||||
width: 80px;
|
||||
width: 119px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
|
@ -67,16 +71,11 @@ export default {
|
|||
}
|
||||
.pending-friend {
|
||||
color: white;
|
||||
padding: 5px;
|
||||
padding-left: 22px;
|
||||
padding-left: 15px;
|
||||
display: flex;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.pending-friend:hover {
|
||||
background-color: rgba(0, 0, 0, 0.246);
|
||||
}
|
||||
|
||||
.profile-picture {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
|
|
@ -88,6 +87,7 @@ export default {
|
|||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.information {
|
||||
margin: auto;
|
||||
|
|
@ -96,18 +96,17 @@ export default {
|
|||
flex: 1;
|
||||
}
|
||||
.tag {
|
||||
color: rgb(173, 173, 173);
|
||||
color: rgba(173, 173, 173, 0.8);
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
margin: auto;
|
||||
margin-right: 5px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 4px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
|
|
@ -119,14 +118,15 @@ export default {
|
|||
.hide {
|
||||
display: none;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: rgba(0, 255, 0, 0.281);
|
||||
}
|
||||
.button .material-icons {
|
||||
margin: auto;
|
||||
color: rgba(255, 255, 255, 0.747);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.button.decline:hover {
|
||||
background-color: rgba(255, 0, 0, 0.281);
|
||||
.button:hover .material-icons {
|
||||
color: white;
|
||||
}
|
||||
.button.decline:hover .material-icons {
|
||||
color: rgb(255, 80, 80);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<template>
|
||||
<div class="recents">
|
||||
<virtual-list :size="49" :remain="20">
|
||||
<virtual-list :size="50" :remain="20" v-if="loaded" >
|
||||
<FriendsTemplate
|
||||
v-for="(channel, key) of channels"
|
||||
:key="key"
|
||||
:recents="true"
|
||||
:channel-i-d="channel.channelID"
|
||||
:friend="channel.channelID"
|
||||
:recipient="channel.recipients[0]"
|
||||
/>
|
||||
</virtual-list>
|
||||
|
|
@ -20,6 +20,14 @@ export default {
|
|||
FriendsTemplate,
|
||||
VirtualList
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loaded: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
setTimeout(() => (this.loaded = true));
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.getters.user;
|
||||
|
|
@ -78,8 +86,6 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
|
||||
.recents {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
user-select: none;
|
||||
|
|
@ -97,4 +103,8 @@ export default {
|
|||
.tab:hover {
|
||||
background-color: rgba(0, 0, 0, 0.123);
|
||||
}
|
||||
.spacer {
|
||||
display: flex;
|
||||
height: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,4 +1,11 @@
|
|||
const config = [
|
||||
{
|
||||
version: "1.0.2",
|
||||
title: "More performance improvements!",
|
||||
shortTitle: "",
|
||||
date: "17/02/2020",
|
||||
fix: ["Improved performance by making code more efficient."]
|
||||
},
|
||||
{
|
||||
version: "1.0.1",
|
||||
title: "Grouped messages + message performance",
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@
|
|||
<main-nav />
|
||||
<div class="panel-layout">
|
||||
<news v-if="currentTab == 3" />
|
||||
<direct-message v-if="currentTab == 1" />
|
||||
<servers v-if="currentTab == 2" />
|
||||
<servers v-if="currentTab == 1 || currentTab == 2" />
|
||||
<!-- <servers v-if="currentTab == 2" /> -->
|
||||
<explore v-if="currentTab == 0" />
|
||||
<admin-panel v-if="currentTab == 4" />
|
||||
</div>
|
||||
|
|
@ -43,14 +43,14 @@ const ElectronFrameButtons = () =>
|
|||
const News = () =>
|
||||
import(/* webpackChunkName: "News" */ "./../components/app/Tabs/News.vue");
|
||||
|
||||
const DirectMessage = () => ({
|
||||
component: import("./../components/app/Tabs/DirectMessage.vue"),
|
||||
loading: Spinner,
|
||||
delay: 0
|
||||
});
|
||||
// const DirectMessage = () => ({
|
||||
// component: import("./../components/app/Tabs/DirectMessage.vue"),
|
||||
// loading: Spinner,
|
||||
// delay: 0
|
||||
// });
|
||||
|
||||
const Servers = () => ({
|
||||
component: import("./../components/app/Tabs/Servers.vue"),
|
||||
component: import("./../components/app/Tabs/ServerAndDMTab"),
|
||||
loading: Spinner,
|
||||
delay: 0
|
||||
});
|
||||
|
|
@ -69,7 +69,7 @@ const AdminPanel = () => ({
|
|||
export default {
|
||||
name: "app",
|
||||
components: {
|
||||
DirectMessage,
|
||||
// DirectMessage,
|
||||
Servers,
|
||||
ConnectingScreen,
|
||||
Popouts,
|
||||
|
|
|
|||
Loading…
Reference in a new issue