tabs and user info

This commit is contained in:
supertiger1234 2019-04-08 15:40:56 +01:00
parent 7bcb6c9c12
commit 52c57ebd06
22 changed files with 293 additions and 35 deletions

2
.gitignore vendored
View file

@ -18,4 +18,4 @@ yarn-error.log*
*.ntvs*
*.njsproj
*.sln
*.sw*
*.sw*

View file

@ -0,0 +1,8 @@
{
"ExpandedNodes": [
"",
"\\src"
],
"SelectedNode": "\\src\\main.js",
"PreviewInSolutionExplorer": false
}

BIN
.vs/slnx.sqlite Normal file

Binary file not shown.

View file

@ -1,16 +1,16 @@
<template>
<div :class="`profile-picture ${adminType ? adminType.name : ''}`">
<img v-if="adminType" class="emote" :src="adminType.emotePath">
<div :class="`profile-picture ${adminType ? adminType.name : ''}`" :style="`padding: ${$props.animationPadding || '3px'}`">
<img v-if="adminType" class="emote" :src="adminType.emotePath" :style="`width: ${$props.emoteSize || '20px'}; height: ${$props.emoteSize ||'20px'}`">
<div
class="inner-profile-picture"
:style="`height: ${$props.height}; width: ${$props.width}; background-image: url(${$props.url})`"
:class="`inner-profile-picture ${$props.hover ? 'hoverable' : ''}`"
:style="`height: ${$props.size}; width: ${$props.size}; background-image: url(${$props.url})`"
></div>
</div>
</template>
<script>
export default {
props: ["url", "height", "width", "admin"],
props: ["url", "size","emoteSize", "admin", "hover", 'animationPadding'],
data() {
return {
crown: require("twemoji/2/svg/1f451.svg"),
@ -38,7 +38,6 @@ export default {
<style scoped>
.profile-picture {
position: relative;
padding: 3px;
border-radius: 50%;
}
.inner-profile-picture {
@ -48,6 +47,10 @@ export default {
background-size: cover;
background-repeat: no-repeat;
display: flex;
transition: 0.2s;
}
.hoverable:hover{
filter: brightness(80%);
}
.creator {
margin-right: 5px;
@ -92,6 +95,7 @@ export default {
top: -3px;
left: -3px;
}
@keyframes Anime {
0% {
background-position: 0% 50%;

View file

@ -1,12 +1,12 @@
<template>
<div :class="{message: true, ownMessage: user.uniqueID === $props.uniqueID}">
<profile-picture :admin="$props.admin" :url="userAvatar" height="50px" width="50px"/>
<profile-picture :hover="true" :admin="$props.admin" :url="userAvatar" size="50px" @click.native="openUserInformation"/>
<div class="triangle">
<div class="triangle-inner"></div>
</div>
<div class="content">
<div class="user-info">
<div class="username">{{this.$props.username}}</div>
<div class="username" @click="openUserInformation">{{this.$props.username}}</div>
<div class="date">{{getDate}}</div>
</div>
<div class="content-message" v-html="formatMessage"></div>
@ -54,6 +54,9 @@ export default {
"admin"
],
methods: {
openUserInformation() {
this.$store.dispatch('setUserInformationPopout', this.uniqueID)
},
imageClicked(event) {
this.$store.dispatch("setImagePreviewURL", event.target.src);
}
@ -121,6 +124,7 @@ export default {
}
.ownMessage .triangle-inner {
transition: 0.5s;
border-right: 7px solid rgba(184, 184, 184, 0.219);
}
.ownMessage .content {
@ -240,6 +244,11 @@ export default {
margin: auto;
margin-left: 0;
margin-right: 0;
transition: 0.1s;
cursor: default;
}
.username:hover{
color: rgb(199, 199, 199);
}
.date {
color: rgb(161, 161, 161);

View file

@ -1,6 +1,6 @@
<template>
<div class="my-mini-information">
<profile-picture :url="avatar" :admin="user.admin" height="50px" width="50px"/>
<profile-picture :url="avatar" :admin="user.admin" size="50px"/>
<div class="information">
<div class="name">{{user.username}}</div>
<div class="tag">@{{user.tag}}</div>

View file

@ -6,6 +6,7 @@
<GDriveLinkMenu key="GDriveLinkMenu" v-if="popouts.GDLinkMenu"/>
<image-large-preview key="ilp" v-if="popouts.ImagePreviewURL"/>
<drag-drop-file-upload-dialog key="ddfud" v-if="showUploadDrapDrop"/>
<user-information-popout key="uip" v-if="popouts.userInformationPopoutID"/>
</transition-group>
</div>
</template>
@ -13,6 +14,7 @@
<script>
import { bus } from "@/main";
//popouts
import userInformationPopout from "@/components/app/userInformationPopout.vue";
import Settings from "@/components/app/Settings.vue";
import uploadDialog from "@/components/app/uploadDialog.vue";
import GDriveLinkMenu from "@/components/app/GDriveLinkMenu.vue";
@ -24,6 +26,7 @@ export default {
Settings,
uploadDialog,
GDriveLinkMenu,
userInformationPopout,
DragDropFileUploadDialog,
imageLargePreview
},

View file

@ -154,6 +154,7 @@ input {
margin-top: 0;
margin-bottom: 0;
background: none;
width: calc(100% - 30px);
}
input:hover {
background: rgba(26, 26, 26, 0.24);
@ -172,6 +173,7 @@ input:focus {
width: 50px;
position: relative;
overflow: hidden;
flex-shrink: 0;
}
.delete-button .material-icons {
margin: auto;

View file

@ -1,6 +1,8 @@
<template>
<div class="my-profile-panel">
<profile-picture :url="avatar" :admin="user.admin" height="100px" width="100px" />
<div class="profile-picture-outer">
<profile-picture :url="avatar" :admin="user.admin" size="100px" emoteSize="30px" animationPadding="5px"/>
</div>
<div class="information">
<div class="username">
<strong>Username:</strong>
@ -35,7 +37,7 @@ import AvatarUpload from "@/services/AvatarUpload.js";
import config from "@/config.js";
import { bus } from "@/main";
import path from "path";
import {mapState} from 'vuex'
import { mapState } from "vuex";
export default {
components: {
@ -99,7 +101,7 @@ export default {
}
},
computed: {
...mapState('settingsModule', ['GDriveLinked']),
...mapState("settingsModule", ["GDriveLinked"]),
user() {
return this.$store.getters.user;
},
@ -119,6 +121,10 @@ export default {
height: 100px;
margin-top: 10px;
}
.profile-picture-outer{
display: flex;
z-index: 99999;
}
.profile-picture {
margin-left: 20px;
}

View file

@ -1,10 +1,10 @@
<template>
<div :class="{friend: true, notifyAnimation: (notifications && notifications > 0) }" :style="`background: ${status.bgColor};`" @click="openChat">
<div class="profile-picture" :style="`border-color: ${status.statusColor}; background-image: url(${userAvatar})`">
<div class="profile-picture" @click="openUserInformation" :style="`border-color: ${status.statusColor}; background-image: url(${userAvatar})`">
<div class="status" :style="`background-image: url(${status.statusURL})`" ></div>
</div>
<div class="information">
<div class="username">{{$props.username}}</div>
<div class="username">{{recipient.username}}</div>
<div class="status-name" :style="`color: ${status.statusColor}`">{{status.statusName}}</div>
</div>
<div class="notification" v-if="notifications && notifications >0">
@ -23,7 +23,7 @@ import statuses from '@/utils/statuses';
import {bus} from '@/main'
export default {
props: ['username', 'tag', 'channelID', 'uniqueID', ],
props: ['username', 'tag', 'channelID', 'uniqueID', 'recipient'],
methods: {
async getMessages() {
const {ok, error, result} = await messagesService.get(this.$props.channelID);
@ -34,14 +34,19 @@ export default {
console.log (error.response)
}
},
async openChat() {
async openChat(event) {
if (event.target.classList[0] === "profile-picture") return;
bus.$emit('closeLeftMenu');
// dismiss notification if exists
if (this.notifications && this.notifications >= 1 && document.hasFocus()) {
this.$socket.emit('notification:dismiss', {channelID: this.channelID});
}
// this.$store.dispatch('openChat', {
// channelID: this.channelID,
// channelName: this.channel
// })
this.$store.dispatch('selectedChannelID', this.$props.channelID);
this.$store.dispatch('setChannelName', this.$props.username);
this.$store.dispatch('setChannelName', this.recipient.username);
if (this.$store.getters.messages[this.$props.channelID]) return;
if (this.$store.getters.channels[this.$props.channelID] && !this.$store.getters.messages[this.$props.channelID]) return this.getMessages();
const {ok, error, result} = await channelService.post(this.$props.channelID);
@ -52,6 +57,9 @@ export default {
// TODO handle this
console.log(error)
}
},
openUserInformation() {
this.$store.dispatch('setUserInformationPopout', this.recipient.uniqueID)
}
},
computed: {
@ -63,14 +71,15 @@ export default {
if (!notifications || (this.$props.channelID === this.$store.getters.selectedChannelID && document.hasFocus())) return;
return notifications.count;
},
user() {
return this.$store.getters.user.friends[this.$props.uniqueID].recipient;
},
userAvatar() {
return config.domain + "/avatars/" + this.user.avatar
return config.domain + "/avatars/" + this.recipient.avatar
},
status() {
const status = this.$store.getters.user.friends[this.$props.uniqueID].recipient.status || 0
let status = 0;
if (this.$store.getters.user.friends[this.recipient.uniqueID]) {
status = this.$store.getters.user.friends[this.recipient.uniqueID].recipient.status || 0
}
return {
statusName: statuses[parseInt(status)].name,
statusURL: statuses[parseInt(status)].url,

View file

@ -5,7 +5,7 @@
</div>
<transition name="list" appear>
<div class="list" v-if="expanded">
<FriendsTemplate v-for="(friend, key) of friends" :key="key" :channelID="friend.channelID" :uniqueID="friends[key].recipient.uniqueID" :username="friend.recipient.username" :tag="friend.recipient.tag"/>
<FriendsTemplate v-for="(friend, key) of friends" :key="key" :channelID="friend.channelID" :recipient="friends[key].recipient" />
</div>
</transition>
</div>

View file

@ -5,7 +5,7 @@
</div>
<transition name="list" appear>
<div class="list" v-if="expanded">
<FriendsTemplate v-for="(friend, key) of friends" :key="key" :channelID="friend.channelID" :uniqueID="friends[key].recipient.uniqueID" :username="friend.recipient.username" :tag="friend.recipient.tag"/>
<FriendsTemplate v-for="(friend, key) of friends" :key="key" :channelID="friend.channelID" :recipient="friends[key].recipient"/>
</div>
</transition>
</div>

View file

@ -1,6 +1,6 @@
<template>
<div class="pending-friend">
<div class="profile-picture" :style="`background-image: url(${userAvatar})`"></div>
<div class="profile-picture" @click="openUserInformation" :style="`background-image: url(${userAvatar})`"></div>
<div class="information">
<div class="username">{{$props.username}}</div>
<div class="tag">@{{$props.tag}}</div>
@ -32,6 +32,9 @@ export default {
},
accept() {
RelationshipService.put(this.$props.uniqueID)
},
openUserInformation() {
this.$store.dispatch('setUserInformationPopout', this.uniqueID)
}
},
computed: {

View file

@ -3,7 +3,7 @@
<transition name="list" appear>
<div class="list">
<FriendsTemplate v-for="(channel, key) of channels" :key="key" notifications="1" :channelID="channel.channelID" :uniqueID="channel.recipients[0].uniqueID" :username="channel.recipients[0].username" :tag="channel.recipients[0].tag"/>
<FriendsTemplate v-for="(channel, key) of channels" :key="key" notifications="1" :channelID="channel.channelID" :recipient="channel.recipients[0]"/>
</div>
</transition>
</div>
@ -21,9 +21,11 @@ export default {
const json = this.$store.getters.channels;
const notifications = this.$store.getters.notifications;
const keys = Object.keys(json);
let result = [];
keys.forEach(function(key){
if (json[key].recipients.length > 0)
result.push(json[key]);
});

View file

@ -0,0 +1,198 @@
<template>
<div class="drop-background" @click="backgroundClickEvent">
<div class="box">
<spinner v-if="!user"/>
<div class="inner" v-else>
<div class="top">
<div class="profile-picture-outer">
<profile-picture
size="90px"
emoteSize="28px"
animationPadding="5px"
:admin="user.admin"
:url="`${avatarDomain}${user.avatar}`"
/>
</div>
<div class="info">
<div class="username">{{user.username}}</div>
<div class="tag">@{{user.tag}}</div>
</div>
</div>
<div class="bottom" v-if="selfUniqueID !== user.uniqueID">
<div class="button valid" v-if="this.relationshipStatus == null" @click="AddFriendButton">
<div class="material-icons">person_add</div>Add friend
</div>
<div class="button valid" v-if="this.relationshipStatus == 0" @click="RemoveFriendButton">
<div class="material-icons">person_add</div>Request Sent!
</div>
<div class="button valid" v-if="this.relationshipStatus == 1" @click="AcceptFriendButton">
<div class="material-icons">person_add</div>Accept Friend
</div>
<div class="button warn" v-if="this.relationshipStatus == 2" @click="RemoveFriendButton">
<div class="material-icons">person_add_disabled</div>End Friendship
</div>
<div class="button">
<div class="material-icons">chat</div>Send Message
</div>
<div class="button warn">
<div class="material-icons">block</div>Block
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import config from "@/config.js";
import Spinner from "@/components/Spinner.vue";
import profilePicture from "@/components/ProfilePictureTemplate.vue";
import userService from "@/services/userService.js";
import relationshipService from "@/services/RelationshipService.js";
export default {
components: { Spinner, profilePicture },
data() {
return {
user: null,
avatarDomain: config.domain + "/avatars/"
};
},
methods: {
backgroundClickEvent(event) {
if (event.target.classList.contains("drop-background")) {
this.$store.dispatch("setUserInformationPopout", null);
}
},
async AddFriendButton() {
const {ok, error, result} = await relationshipService.post({username: this.user.username, tag: this.user.tag});
},
async AcceptFriendButton() {
const {ok, error, result} = await relationshipService.put(this.uniqueID);
},
async RemoveFriendButton() {
const {ok, error, result} = await relationshipService.delete(this.uniqueID);
}
},
async mounted() {
const { ok, error, result } = await userService.get(this.uniqueID);
if (ok) {
this.user = result.data.user;
}
},
computed: {
selfUniqueID() {
return this.$store.getters.user.uniqueID;
},
uniqueID() {
return this.$store.getters.popouts.userInformationPopoutID;
},
relationshipStatus() {
const userUniqueID = this.$store.getters.popouts.userInformationPopoutID;
const allFriend = this.$store.getters.user.friends;
if (!allFriend[userUniqueID]) return null
return allFriend[userUniqueID].status
}
}
};
</script>
<style scoped>
.drop-background {
position: absolute;
background: rgba(0, 0, 0, 0.521);
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
display: flex;
}
.box {
margin: auto;
height: 330px;
width: 500px;
background: rgba(31, 31, 31, 0.904);
border-radius: 5px;
color: white;
display: flex;
flex-direction: column;
user-select: none;
overflow: hidden;
}
.inner {
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
}
.top {
display: flex;
flex-direction: column;
background: rgba(22, 22, 22, 0.918);
width: 100%;
height: 170px;
}
.bottom {
display: flex;
height: 100%;
width: calc(100% - 20px);
margin: auto;
}
.button {
background: rgba(49, 49, 49, 0.815);
display: flex;
flex-direction: column;
align-content: center;
align-items: center;
justify-content: center;
border-radius: 5px;
flex: 1;
margin: 30px;
margin-left: 20px;
margin-right: 20px;
transition: 0.3s;
}
.button .material-icons {
margin-bottom: 10px;
font-size: 40px;
}
.button:hover {
background: rgb(61, 61, 61);
}
.button.valid {
background: #09ff002d;
}
.button.valid:hover {
background: #09ff00ab;
}
.button.warn {
background: #ff00002d;
}
.button.warn:hover {
background: #ff0000ab;
}
.profile-picture-outer {
display: flex;
z-index: 9999;
margin: auto;
margin-bottom: 0px;
}
.info {
margin-top: 1px;
margin: auto;
font-size: 20px;
display: flex;
user-select: text;
}
.tag {
color: grey;
}
</style>

View file

@ -2,7 +2,7 @@
<div class="logged-in">
<div class="card">
<div class="avatar-outer">
<profile-picture :url="avatar" :admin="user.admin" height="90px" width="90px" />
<profile-picture :url="avatar" :admin="user.admin" size="90px" emoteSize="27px" />
</div>
<div class="info">
<div class="username">{{user.username}}<span class="tag">@{{user.tag}}</span></div>

View file

@ -1,7 +1,7 @@
<template>
<div class="right-panel-home">
<div class="right-panel-inner">
<img class="logo" src="./../../assets/logo.svg"></img>
<img class="logo" src="./../../assets/logo.svg" />
<div class="title">Nertivia</div>
<spinner :msg="spinnerMessage" v-if="previouslyLoggedIn && user == null && tokenExists" />

View file

@ -8,6 +8,6 @@ export default {
return wrapper(instance().post('user/login', credentials));
},
user () {
return wrapper(instance().get('user/details'))
return wrapper(instance().get('user'))
}
}

View file

@ -1,5 +1,7 @@
import {instance, wrapper} from './Api';
export default {
get (uniqueID) {
return wrapper(instance().get(`user/${uniqueID}`))
}
}

View file

@ -11,6 +11,8 @@ const state = {
uploadDialog: false,
ImagePreviewURL: null,
userInformationPopoutID: null,
dragDropFileUploadDialog: false,
settings: false,
GDLinkMenu: false,
@ -24,6 +26,9 @@ const getters = {
}
const actions = {
setUserInformationPopout({commit}, id){
commit('setUserInformationPopout', id)
},
setPopoutVisibility(context, data) {
context.commit('setPopoutVisibility', data)
},
@ -36,6 +41,9 @@ const actions = {
}
const mutations = {
setUserInformationPopout(state, id) {
Vue.set(state, 'userInformationPopoutID', id)
},
setPopoutVisibility(state, data) {
Vue.set(state, data.name, data.visibility)
},

View file

@ -25,15 +25,18 @@ const actions = {
if(friendsArray !== undefined && friendsArray.length >=1) {
for (let index = 0; index < friendsArray.length; index++) {
const element = friendsArray[index];
friendObject[element.recipient.uniqueID] = element;
for (let currentFriendStatus of currentFriendStatus){
if(currentFriendStatus[0] == element.recipient.uniqueID){
friendObject[element.recipient.uniqueID].recipient.status = currentFriendStatus[1]
if (element.recipient) {
friendObject[element.recipient.uniqueID] = element;
for (let currentFriendStatus of currentFriendStatus){
if(currentFriendStatus[0] == element.recipient.uniqueID){
friendObject[element.recipient.uniqueID].recipient.status = currentFriendStatus[1]
}
}
}
}
data.user.friends = friendObject;
}
context.commit('user', data.user)
// convert dms array to object

View file

@ -8,6 +8,7 @@ const config = [
new: [
'You can now make your own guild.',
"Tabs have been added at the top of the screen.",
"Added users information page which allows you to block, End friendship or message someone.",
],
fix: ["Some formatting issues with custom emojis have been fixed."],
next: ['link previews.']