alpha built ready

This commit is contained in:
supertiger1234 2019-05-23 20:45:27 +01:00
parent 62f725522a
commit 5af8c39acc
11 changed files with 441 additions and 57 deletions

View file

@ -3,6 +3,7 @@
<div class="header"> <div class="header">
<div class="title">Members</div> <div class="title">Members</div>
</div> </div>
<div style="text-align: center">Soon!</div>
</div> </div>
</template> </template>

View file

@ -2,7 +2,7 @@
<div class="right-panel"> <div class="right-panel">
<heading <heading
:uniqueID="recipients && recipients.length ? recipients[0].uniqueID : undefined" :uniqueID="recipients && recipients.length ? recipients[0].uniqueID : undefined"
:type="selectedChannelID && channel && !channel.server_id ? 1 : 0" :type="selectedChannelID && channel && !channel.server_id ? 1 : channel && channel.server_id ? 2 : 0"
:status-color="userStatusColor" :status-color="userStatusColor"
:name="selectedChannelID ? channelName : `Welcome back, ${user.username}!` " :name="selectedChannelID ? channelName : `Welcome back, ${user.username}!` "
/> />
@ -22,6 +22,7 @@
:message="msg.message" :message="msg.message"
:files="msg.files" :files="msg.files"
:status="msg.status" :status="msg.status"
:type="msg.type"
/> />
<uploadsQueue v-if="uploadQueue !== undefined" :queue="uploadQueue"/> <uploadsQueue v-if="uploadQueue !== undefined" :queue="uploadQueue"/>
</div> </div>

View file

@ -10,6 +10,9 @@
<div class="information"> <div class="information">
<div :class="{name: true, clickable: !!uniqueID }" @click="openUserInfoPanel">{{name}}</div> <div :class="{name: true, clickable: !!uniqueID }" @click="openUserInfoPanel">{{name}}</div>
</div> </div>
<div class="show-members-button" @click="toggleMembersPanel">
<i class="material-icons">view_list</i>
</div>
</div> </div>
</template> </template>
@ -17,7 +20,7 @@
import { bus } from "@/main"; import { bus } from "@/main";
export default { export default {
props: [ props: [
"type", // 0: without online status; 1: with online status "type", // 0: without online status; 1: with online status; 2: server.
"statusColor", // only if type is set to 1; "statusColor", // only if type is set to 1;
"name", "name",
"uniqueID" "uniqueID"
@ -29,6 +32,9 @@ export default {
}, },
toggleLeftMenu() { toggleLeftMenu() {
bus.$emit("toggleLeftMenu"); bus.$emit("toggleLeftMenu");
},
toggleMembersPanel() {
bus.$emit("toggleMembersPanel");
} }
} }
}; };
@ -51,6 +57,14 @@ export default {
user-select: none; user-select: none;
display: none; display: none;
} }
.show-members-button{
display: inline-block;
margin-right: 5px;
margin-top: 3px;
user-select: none;
display: none;
color: white;
}
.show-menu-button .material-icons { .show-menu-button .material-icons {
color: rgb(207, 207, 207); color: rgb(207, 207, 207);
transition: 0.3s; transition: 0.3s;
@ -94,6 +108,14 @@ export default {
color: rgb(219, 219, 219); color: rgb(219, 219, 219);
text-decoration: underline; text-decoration: underline;
} }
@media (max-width: 949px) {
.show-members-button {
display: block;
}
}
@media (max-width: 600px) { @media (max-width: 600px) {
.show-menu-button { .show-menu-button {
display: block; display: block;

View file

@ -1,33 +1,50 @@
<template> <template>
<div :class="{message: true, ownMessage: user.uniqueID === $props.uniqueID, ownMessageLeft: user.uniqueID === $props.uniqueID && (apperance && apperance.own_message_right === true)} "> <div class="container">
<profile-picture class="avatar" :admin="$props.admin" :url="userAvatar" size="50px" :hover="true" @click.native="openUserInformation"/> <div v-if="!type || type === 0" :class="{message: true, ownMessage: user.uniqueID === $props.uniqueID, ownMessageLeft: user.uniqueID === $props.uniqueID && (apperance && apperance.own_message_right === true)} " >
<div class="triangle"> <profile-picture
<div class="triangle-inner"></div> class="avatar"
</div> :admin="$props.admin"
<div class="content"> :url="userAvatar"
<div class="user-info"> size="50px"
<div class="username" @click="openUserInformation">{{this.$props.username}}</div> :hover="true"
<div class="date">{{getDate}}</div> @click.native="openUserInformation"
/>
<div class="triangle">
<div class="triangle-inner"></div>
</div> </div>
<div class="content-message" v-html="formatMessage"></div> <div class="content">
<div class="user-info">
<div class="file-content" v-if="getFile"> <div class="username" @click="openUserInformation">{{this.$props.username}}</div>
<div class="icon"> <div class="date">{{getDate}}</div>
<i class="material-icons">insert_drive_file</i>
</div> </div>
<div class="information"> <div class="content-message" v-html="formatMessage"></div>
<div class="info">{{getFile.fileName}}</div>
<a :href="getFile.url" target="_blank"> <div class="file-content" v-if="getFile">
<div class="download-button">Download</div> <div class="icon">
</a> <i class="material-icons">insert_drive_file</i>
</div>
<div class="information">
<div class="info">{{getFile.fileName}}</div>
<a :href="getFile.url" target="_blank">
<div class="download-button">Download</div>
</a>
</div>
</div>
<div class="image-content" v-if="getImage">
<img :src="getImage" @click="imageClicked">
</div> </div>
</div> </div>
<div class="sending-status" v-html="statusMessage"></div>
<div class="image-content" v-if="getImage"> </div>
<img :src="getImage" @click="imageClicked"> <div v-if="type && (type === 1 || type === 2)" :class="{'presence-message': true, green: type === 1, red: type === 2}" >
</div> <span>
<span class="username" @click="openUserInformation">{{this.$props.username}}</span>
<span class="text" v-if="type === 1">has joined the server!</span>
<span class="text" v-if="type === 2">has left the server.</span>
<span class="date">{{getDate}}</span>
</span>
</div> </div>
<div class="sending-status" v-html="statusMessage"></div>
</div> </div>
</template> </template>
@ -53,18 +70,19 @@ export default {
"date", "date",
"uniqueID", "uniqueID",
"files", "files",
"admin" "admin",
"type"
], ],
methods: { methods: {
openUserInformation() { openUserInformation() {
this.$store.dispatch('setUserInformationPopout', this.uniqueID) this.$store.dispatch("setUserInformationPopout", this.uniqueID);
}, },
imageClicked(event) { imageClicked(event) {
this.$store.dispatch("setImagePreviewURL", event.target.src); this.$store.dispatch("setImagePreviewURL", event.target.src);
} }
}, },
computed: { computed: {
...mapState('settingsModule', ['apperance']), ...mapState("settingsModule", ["apperance"]),
getImage() { getImage() {
if (!this.$props.files || this.$props.files.length === 0) if (!this.$props.files || this.$props.files.length === 0)
return undefined; return undefined;
@ -118,7 +136,27 @@ export default {
<style scoped> <style scoped>
.ownMessageLeft { .presence-message {
margin: 10px;
padding: 10px;
display: table;
color: white;
overflow: hidden;
border-radius: 5px;
animation: showMessage 0.3s ease-in-out;
}
.presence-message .text {
margin-left: 5px;
}
.presence-message.green {
background: rgba(0, 128, 0, 0.534);
}
.presence-message.red {
background: rgba(128, 0, 0, 0.534);
}
.ownMessageLeft {
flex-direction: row-reverse; flex-direction: row-reverse;
} }
@ -127,17 +165,15 @@ export default {
border-left: 7px solid rgba(184, 184, 184, 0.219); border-left: 7px solid rgba(184, 184, 184, 0.219);
border-right: none !important; border-right: none !important;
} }
.ownMessageLeft .avatar { .ownMessageLeft .avatar {
margin-right: 0px; margin-right: 0px;
margin-left: 5px; margin-left: 5px;
} }
.ownMessageLeft .sending-status{ .ownMessageLeft .sending-status {
margin-left: auto !important; margin-left: auto !important;
margin-right: 4px !important; margin-right: 4px !important;
} }
.message { .message {
margin: 10px; margin: 10px;
display: flex; display: flex;
@ -259,7 +295,7 @@ export default {
transition: 0.1s; transition: 0.1s;
cursor: default; cursor: default;
} }
.username:hover{ .username:hover {
color: rgb(199, 199, 199); color: rgb(199, 199, 199);
text-decoration: underline; text-decoration: underline;
} }

View file

@ -13,24 +13,24 @@
<strong>What's new?</strong> <strong>What's new?</strong>
<br> <br>
<ul> <ul>
<li v-for="(wnew, index) in change.new" :key="index">{{wnew}}</li> <li v-for="(wnew, index) in change.new" :key="index" v-html="wnew"></li>
</ul> </ul>
</div> </div>
<div v-if="change.fix"> <div v-if="change.fix">
<strong>Issues fixed</strong> <strong>Issues fixed</strong>
<br> <br>
<ul> <ul>
<li v-for="(wfix, index) in change.fix" :key="index">{{wfix}}</li> <li v-for="(wfix, index) in change.fix" :key="index" v-html="wfix"></li>
</ul> </ul>
</div> </div>
<div v-if="change.next"> <div v-if="change.next">
<strong>Up next</strong> <strong>Up next</strong>
<br> <br>
<ul> <ul>
<li v-for="(wnext, index) in change.next" :key="index">{{wnext}}</li> <li v-for="(wnext, index) in change.next" :key="index" v-html="wnext"></li>
</ul> </ul>
</div> </div>
<div v-if="change.msg">{{change.msg}}</div> <div v-if="change.msg" v-html="change.msg"></div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,14 +1,20 @@
<template> <template>
<div class="direct-message-tab"> <div class="direct-message-tab">
<transition name="slidein"> <transition name="slide-left">
<server-list <server-list
class="left-panel" class="left-panel"
v-click-outside="hideLeftPanel" v-click-outside="hideLeftPanel"
v-show="$mq === 'mobile' && showLeftPanel || $mq === 'desktop'" v-show="$mq === 'mobile' && showLeftPanel || ($mq !== 'mobile')"
/> />
</transition> </transition>
<message-panel/> <message-panel/>
<members-list/> <transition name="slide-right">
<members-list
class="members-panel"
v-click-outside="hideMembersPanel"
v-show="($mq === 'members_panel' || $mq === 'mobile') && showMembersPanel || ($mq === 'desktop')"
/>
</transition>
</div> </div>
</template> </template>
@ -27,7 +33,8 @@ export default {
}, },
data() { data() {
return { return {
showLeftPanel: false showLeftPanel: false,
showMembersPanel: false
}; };
}, },
methods: { methods: {
@ -37,12 +44,22 @@ export default {
this.showLeftPanel = false; this.showLeftPanel = false;
} }
} }
},
hideMembersPanel(event) {
if (this.showMembersPanel) {
if (event.target.closest(".show-members-button") == null) {
this.showMembersPanel = false;
}
}
} }
}, },
mounted() { mounted() {
bus.$on("toggleLeftMenu", () => { bus.$on("toggleLeftMenu", () => {
this.showLeftPanel = !this.showLeftPanel; this.showLeftPanel = !this.showLeftPanel;
}); });
bus.$on("toggleMembersPanel", () => {
this.showMembersPanel = !this.showMembersPanel;
});
bus.$on("closeLeftMenu", () => { bus.$on("closeLeftMenu", () => {
this.showLeftPanel = false; this.showLeftPanel = false;
}); });
@ -51,13 +68,31 @@ export default {
</script> </script>
<style scoped> <style scoped>
.slidein-enter-active, .slide-left-enter-active,
.slidein-leave-active { .slide-left-leave-active {
transition: 0.5s; transition: 0.5s;
} }
.slidein-enter, .slidein-leave-to /* .fade-leave-active below version 2.1.8 */ { .slide-left-enter, .slide-left-leave-to /* .fade-leave-active below version 2.1.8 */ {
margin-left: -300px; margin-left: -300px;
} }
.slide-right-enter-active,
.slide-right-leave-active {
transition: 0.5s;
}
.slide-right-enter, .slide-right-leave-to /* .fade-leave-active below version 2.1.8 */ {
margin-right: -300px;
}
@media (max-width: 949px) {
.members-panel {
position: absolute;
background-color: rgba(39, 39, 39, 0.97);
right: 0;
}
}
@media (max-width: 600px) { @media (max-width: 600px) {
.left-panel { .left-panel {
position: absolute; position: absolute;

View file

@ -17,6 +17,7 @@ const MainApp = () => import(/* webpackChunkName: "MainApp" */ "../src/views/App
const HomePage = () => import(/* webpackChunkName: "HomePage" */ "../src/views/HomePage.vue"); const HomePage = () => import(/* webpackChunkName: "HomePage" */ "../src/views/HomePage.vue");
const GDriveCallback = () => import(/* webpackChunkName: "GDriveCallback" */ "../src/views/GDriveCallback.vue"); const GDriveCallback = () => import(/* webpackChunkName: "GDriveCallback" */ "../src/views/GDriveCallback.vue");
const LoginPage = () => import(/* webpackChunkName: "LoginPage" */ "../src/views/LoginPage.vue"); const LoginPage = () => import(/* webpackChunkName: "LoginPage" */ "../src/views/LoginPage.vue");
const InvitesPage = () => import(/* webpackChunkName: "Invites" */ "../src/views/Invites.vue");
const RegisterPage = () => import(/* webpackChunkName: "RegisterPage" */ "../src/views/RegisterPage.vue"); const RegisterPage = () => import(/* webpackChunkName: "RegisterPage" */ "../src/views/RegisterPage.vue");
export const router = new VueRouter({ export const router = new VueRouter({
@ -69,10 +70,11 @@ export const router = new VueRouter({
} }
}), }),
{ store } { store }
); );
Vue.use(VueMq, { Vue.use(VueMq, {
breakpoints: { breakpoints: {
mobile: 600, mobile: 600,
members_panel: 950,
desktop: Infinity desktop: Infinity
} }
}); });
@ -83,6 +85,11 @@ export const router = new VueRouter({
path: "/GDrive_callback", path: "/GDrive_callback",
name: "GDrive callback", name: "GDrive callback",
component: GDriveCallback component: GDriveCallback
} },
{
path: "/invites/:invite_id",
name: "invites",
component: InvitesPage,
},
] ]
}); });

View file

@ -1,9 +1,9 @@
const prototype = { const prototype = {
version: 3, version: 4,
title: "Make your own servers!", title: "",
shortTitle: "Servers", shortTitle: "",
date: "24/04/2019", date: "23/05/2019",
headColor: "rgba(155, 244, 66, 0.77)", headColor: "rgba(155, 244, 66, 0.77)",
new: [ new: [
"", "",
@ -13,6 +13,27 @@
} }
const config = [ const config = [
{
version: 4,
title: "Make your own servers! (Alpha)",
shortTitle: "Servers (Alpha)",
date: "23/05/2019",
headColor: "rgb(0, 102, 170, 0.77)",
new: [
"You can now make servers! Note that this is in alpha stage which means that it's not complete and there could be a ton of bugs everywhere :c get reporting!",
"Adjusted padding in some areas.",
],
next: ["Members list for servers"],
msg:
`
<div style='color: red;'>
Please note that this update could be unstable and could involve of resetting the database.
</div>Join the official Nertivia server by clicking
<a style="
color: #27a3ff;
" href='https://nertivia.supertiger.tk/invites/8SSrCF'>here</a>`
},
{ {
version: 3, version: 3,
title: "Page Re-designs", title: "Page Re-designs",

View file

@ -76,7 +76,7 @@ export default {
this.showPopout = false; this.showPopout = false;
}, },
logOut() { logOut() {
localStorage.removeItem("hauthid"); this.$store.dispatch("logout");
this.loggedIn = null; this.loggedIn = null;
}, },
loginPage() { loginPage() {

257
src/views/Invites.vue Normal file
View file

@ -0,0 +1,257 @@
<template>
<div id="app">
<div class="app-content">
<header-login v-on:isDay="isDayEvent"/>
<div class="content">
<transition appear name="fade-up">
<div :class="{box: true, red: server === undefined}" >
<spinner v-if="server === null"/>
<div v-if="server === undefined">
<div class="invalid">{{errorMsg}}</div>
</div>
<div class="server" v-if="server">
<profile-picture class="avatar" size="100px" :url="tempImage"/>
<div class="server-name">{{server.name}}</div>
<div class="buttons">
<div class="button join-button" @click="joinServerButton" v-if="loggedIn">Join {{server.name}}</div>
<div class="button join-button" v-else @click="loginButton">Login to join</div>
</div>
</div>
</div>
</transition>
</div>
</div>
<div class="background">
<div :class="{background: true, 'night-background': true, chosen: !isDay}">
<particlesJS class="particles"/>
</div>
<div class="background day-background"></div>
</div>
</div>
</template>
<script>
import config from "@/config";
import particlesJS from "@/components/ParticlesJS.vue";
import HeaderLogin from "@/components/HeaderLoginTemplate.vue";
import ProfilePicture from "@/components/ProfilePictureTemplate.vue";
import Spinner from "@/components/Spinner.vue";
import ServerService from "@/services/ServerService";
export default {
components: { HeaderLogin, particlesJS, Spinner, ProfilePicture},
data() {
return {
isDay: true,
server: null,
tempImage: config.domain + "/avatars/noob",
loggedIn: localStorage.getItem('hauthid'),
errorMsg: ""
};
},
methods: {
isDayEvent(data) {
this.isDay = data;
},
async joinServerButton(event) {
if (event.target.classList.contains("button-clicked")) return;
event.target.classList.add("button-clicked");
const inviteID = this.$route.params.invite_id;
if (!localStorage.getItem("hauthid")) {
return this.loggedIn = undefined;
}
const { ok, error, result } = await ServerService.joinServer(inviteID)
if (ok) {
this.$router.push(`/app`);
} else {
event.target.classList.remove("button-clicked");
//409 404
if (error.response === undefined) {
this.errorMsg = "Cannot connect to server. Try again later.";
} else {
const status = error.response.status;
if (status === 409){
return this.$router.push(`/app`);
}
if (status === 404){
return this.errorMsg = "Invite does not exist.";
}
this.errorMsg = "Something went wrong. Try again later.";
}
this.server = undefined;
}
},
loginButton() {
const inviteID = this.$route.params.invite_id;
this.$router.push(`/login?to=invites&id=${inviteID}`);
}
},
async mounted() {
const inviteID = this.$route.params.invite_id;
const { ok, error, result } = await ServerService.getInviteDetail(inviteID);
if (ok) {
this.server = result.data;
} else {
if (error.response === undefined) {
this.errorMsg = "Cannot connect to server. Try again later.";
} else {
this.errorMsg = "The invite code is either invalid, expired or blocked.";
}
this.server = undefined;
}
}
};
</script>
<style>
html,
body {
height: 100%;
}
</style>
<style scoped>
.fade-up-enter-active {
opacity: 0;
animation: bounce-in 0.5s;
animation-delay: 0.7s;
}
.fade-up-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: translateX(30px);
opacity: 0;
}
50% {
transform: translateX(-10px);
}
100% {
transform: translateX(0);
opacity: 1;
}
}
#app {
display: flex;
flex-direction: column;
transition: background 10s;
color: white;
height: 100%;
}
.app-content {
display: flex;
position: relative;
flex-direction: column;
height: 100%;
width: 100%;
overflow: auto;
z-index: 9999;
padding-bottom: 100px;
}
.background {
position: fixed;
height: 100%;
width: 100%;
transition: background 10s;
}
.night-background {
opacity: 0;
transition: 10s;
background: linear-gradient(to bottom, #000000 0%, #606060 100%) !important;
}
.day-background {
opacity: 1;
background: linear-gradient(to bottom, #165dc0 0%, #5482bf 100%);
z-index: -1;
}
.night-background.chosen {
opacity: 1 !important;
}
.night-background .particles {
opacity: 1;
}
.content {
display: flex;
height: 100%;
margin: 10px;
flex-shrink: 0;
}
.box {
width: 100%;
max-width: 400px;
background: rgba(44, 44, 44, 0.774);
transition: 0.3s;
margin: auto;
margin-top: 20px;
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
padding-bottom: 20px;
}
.server {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
height: 300px;
}
.invalid{
margin-top: 15px;
}
.red{
background: rgba(117, 10, 10, 0.774)
}
.avatar {
align-self: center;
margin-bottom: 10px;
}
.server-name {
text-align: center;
font-size: 25px;
margin-bottom: 40px;
}
.button {
padding: 10px;
background: rgba(25, 151, 255, 0.699);
border-radius: 5px;
user-select: none;
border: none;
color: white;
font-size: 17px;
outline: none;
transition: 0.2s;
box-shadow: 3px 3px rgba(23, 112, 255, 0.479);
align-self: center;
flex-shrink: 0;
text-align: center;
}
.button:hover {
background: rgb(25, 151, 255);
}
.button:focus {
background: rgb(25, 151, 255);
}
.button:active {
background: rgb(25, 151, 255);
transform: translate(3px, 3px);
box-shadow: 0px 0px rgba(0, 97, 207, 0.479);
}
.button-clicked {
background: rgb(126, 126, 126) !important;
transform: translate(3px, 3px) !important;
box-shadow: 0px 0px rgba(61, 61, 61, 0.479) !important;
}
</style>

View file

@ -117,6 +117,10 @@ export default {
this.visible = false; this.visible = false;
this.$store.dispatch("token", result.data.token); this.$store.dispatch("token", result.data.token);
setTimeout(_ => { setTimeout(_ => {
const {to, id} = this.$route.query;
if (to) {
return window.location.href = `/${to}/${id}`
}
window.location.href = "/app"; window.location.href = "/app";
}, 1000); }, 1000);
} else { } else {