This commit is contained in:
Troplo 2021-01-18 00:05:28 +11:00
parent cbd5ce5199
commit 247baaa399
21 changed files with 431 additions and 151 deletions

1
.env
View file

@ -4,3 +4,4 @@ VUE_APP_GATEWAYENDPOINT=https://gateway.kaverti.com
VUE_APP_STAGING=false VUE_APP_STAGING=false
VUE_APP_I18N_LOCALE=en VUE_APP_I18N_LOCALE=en
VUE_APP_I18N_FALLBACK_LOCALE=en VUE_APP_I18N_FALLBACK_LOCALE=en
VUE_APP_RELEASE="Canary"

View file

@ -2,3 +2,4 @@ VUE_APP_APIENDPOINT="/api/"
VUE_APP_APIVERSION="v1" VUE_APP_APIVERSION="v1"
VUE_APP_GATEWAYENDPOINT="http://localhost:23981" VUE_APP_GATEWAYENDPOINT="http://localhost:23981"
VUE_APP_STAGING=true VUE_APP_STAGING=true
VUE_APP_RELEASE="Canary"

242
assets/css/sidebar.css Normal file
View file

@ -0,0 +1,242 @@
body {
padding-bottom: 30px!important;
position: relative!important;
min-height: 100%!important;
}
a {
transition: background 0.2s, color 0.2s!important;
}
a:hover,
a:focus {
text-decoration: none!important;
}
#wrapper {
padding-left: 0!important;
transition: all 0.5s ease!important;
position: relative!important;
}
#sidebar-wrapper {
z-index: 1000!important;
position: fixed!important;
left: 250px!important;
width: 0!important;
height: 100%!important;
margin-left: -250px!important;
overflow-y: auto!important;
overflow-x: hidden!important;
background: #222!important;
transition: all 0.5s ease!important;
}
#wrapper.toggled #sidebar-wrapper {
width: 250px!important;
}
.sidebar-brand {
position: absolute!important;
top: 0!important;
width: 250px!important;
text-align: center!important;
padding: 20px 0!important;
}
.sidebar-brand h2 {
margin: 0!important;
font-weight: 600!important;
font-size: 24px!important;
color: #fff!important;
}
.sidebar-nav {
position: absolute!important;
top: 75px!important;
width: 250px!important;
margin: 0!important;
padding: 0!important;
list-style: none!important;
}
.sidebar-nav > li {
text-indent: 10px!important;
line-height: 42px!important;
}
.sidebar-nav > li a {
display: block!important;
text-decoration: none!important;
color: #757575!important;
font-weight: 600!important;
font-size: 18px!important;
}
.sidebar-nav > li > a:hover,
.sidebar-nav > li.active > a {
text-decoration: none!important;
color: #fff!important;
background: #F8BE12!important;
}
.sidebar-nav > li > a i.fa {
font-size: 24px!important;
width: 60px!important;
}
#navbar-wrapper {
width: 100%!important;
position: absolute!important;
z-index: 2!important;
}
#wrapper.toggled #navbar-wrapper {
position: absolute!important;
margin-right: -250px!important;
}
#navbar-wrapper .navbar {
border-width: 0 0 0 0!important;
background-color: #eee!important;
font-size: 24px!important;
margin-bottom: 0!important;
border-radius: 0!important;
}
#navbar-wrapper .navbar a {
color: #757575!important;
}
#navbar-wrapper .navbar a:hover {
color: #F8BE12!important;
}
#content-wrapper {
width: 100%!important;
position: absolute!important;
padding: 15px!important;
top: 100px!important;
}
#wrapper.toggled #content-wrapper {
position: absolute!important;
margin-right: -250px!important;
}
@media (min-width: 992px) {
#wrapper {
padding-left: 250px!important;
}
#wrapper.toggled {
padding-left: 60px!important;
}
#sidebar-wrapper {
width: 250px!important;
}
#wrapper.toggled #sidebar-wrapper {
width: 60px!important;
}
#wrapper.toggled #navbar-wrapper {
position: absolute!important;
margin-right: -190px!important;
}
#wrapper.toggled #content-wrapper {
position: absolute!important;
margin-right: -190px!important;
}
#navbar-wrapper {
position: relative!important;
}
#wrapper.toggled {
padding-left: 60px!important;
}
#content-wrapper {
position: relative!important;
top: 0!important;
}
#wrapper.toggled #navbar-wrapper,
#wrapper.toggled #content-wrapper {
position: relative!important;
margin-right: 60px!important;
}
}
@media (min-width: 768px) and (max-width: 991px) {
#wrapper {
padding-left: 60px!important;
}
#sidebar-wrapper {
width: 60px!important;
}
#wrapper.toggled #navbar-wrapper {
position: absolute!important;
margin-right: -250px!important;
}
#wrapper.toggled #content-wrapper {
position: absolute!important;
margin-right: -250px!important;
}
#navbar-wrapper {
position: relative!important;
}
#wrapper.toggled {
padding-left: 250px!important;
}
#content-wrapper {
position: relative!important;
top: 0!important;
}
#wrapper.toggled #navbar-wrapper,
#wrapper.toggled #content-wrapper {
position: relative!important;
margin-right: 250px!important;
}
}
@media (max-width: 767px) {
#wrapper {
padding-left: 0!important;
}
#sidebar-wrapper {
width: 0!important;
}
#wrapper.toggled #sidebar-wrapper {
width: 250px!important;
}
#wrapper.toggled #navbar-wrapper {
position: absolute!important;
margin-right: -250px!important;
}
#wrapper.toggled #content-wrapper {
position: absolute!important;
margin-right: -250px!important;
}
#navbar-wrapper {
position: relative!important;
}
#wrapper.toggled {
padding-left: 250px!important;
}
#content-wrapper {
position: relative!important;
top: 0!important;
}
#wrapper.toggled #navbar-wrapper,
#wrapper.toggled #content-wrapper {
position: relative!important;
margin-right: 250px!important;
}
}

View file

@ -1,4 +1,5 @@
module.exports = function(vuex) { import { SnackbarProgrammatic as Snackbar } from 'buefy'
export default function (vuex) {
return function (res, ignorePathErrorCb) { return function (res, ignorePathErrorCb) {
let errors = [] let errors = []
@ -17,7 +18,7 @@ module.exports = function(vuex) {
} }
if(errors.length) { if(errors.length) {
vuex.commit('setAjaxErrors', errors) vuex.commit('setAjaxErrors', errors)
vuex.commit('setAjaxErrorsModalState', true) Snackbar.open({message: '&nbsp' + vuex.state.errors.errors, type: 'is-danger'})
} }
} }

View file

@ -9,9 +9,10 @@
<div id="navigation"> <div id="navigation">
<Navbar/> <Navbar/>
</div> </div>
<div id="router"> <div id="router content-wrapper">
<router-view/> <router-view/>
</div> </div>
<br>
<div id="footer"> <div id="footer">
<Footer/> <Footer/>
</div> </div>
@ -51,7 +52,7 @@ export default {
this.$store.commit('setID', res.data.id) this.$store.commit('setID', res.data.id)
this.$store.commit('setBot', res.data.bot) this.$store.commit('setBot', res.data.bot)
}).catch(() => { }).catch(() => {
this.$buefy.snackbar.open({message:this.$t('errors.authFail'), type: 'is-warning'}) this.$buefy.snackbar.open({message:this.$t('errors.down'), type: 'is-warning'})
}) })
} }
} }

View file

View file

@ -204,6 +204,15 @@
</div> </div>
</form> </form>
</b-modal> </b-modal>
<section v-if='!$store.state.user.emailVerified && $store.state.user.username' class="hero is-danger">
<div class="hero-body" style="padding: 1rem 1rem !important;">
<div class="mobile-container">
<div class="container">
<p style="text-align: center;">{{$t('errors.emailVerify')}}</p>
</div>
</div>
</div>
</section>
<b-navbar> <b-navbar>
<template #brand> <template #brand>
<b-navbar-item tag="router-link" :to="{ path: '/' }"> <b-navbar-item tag="router-link" :to="{ path: '/' }">
@ -295,6 +304,19 @@
</div> </div>
</template> </template>
</b-navbar> </b-navbar>
<section v-if='$store.state.client.bannerText && $store.state.client.bannerEnabled && showBanner' class="hero is-info">
<div class="hero-body" style="padding: 1rem 1rem !important;">
<div class="mobile-container">
<div class="container">
<p style="text-align: center;">{{$store.state.client.bannerText}} <button
type="button"
class="delete"
style="float: right;"
@click="removeBannerId"/></p>
</div>
</div>
</div>
</section>
</nav> </nav>
</template> </template>
<script> <script>
@ -307,6 +329,7 @@ export default {
registerModal: false, registerModal: false,
loading: true, loading: true,
settingsModal: false, settingsModal: false,
showBanner: true,
settings: { settings: {
tab: 0, tab: 0,
general: { general: {
@ -416,9 +439,21 @@ export default {
}, },
}, },
methods: { methods: {
getBannerId() {
if(localStorage.getItem(this.$store.state.client.bannerId)) {
this.showBanner = false
} else {
this.showBanner = true
}
},
removeBannerId() {
localStorage.setItem(this.$store.state.client.bannerId, true)
this.$store.state.client.bannerEnabled = false
console.log(localStorage.getItem(this.$store.state.client.bannerId))
},
doRegister() { doRegister() {
this.register.loading = true this.register.loading = true
this.axios.post('/api/v1/users/register', { this.axios.post('/api/v1/passkey/register', {
username: this.register.username, username: this.register.username,
password: this.register.password, password: this.register.password,
email: this.register.email, email: this.register.email,
@ -433,6 +468,7 @@ export default {
this.$store.commit('setEmail', res.data.email) this.$store.commit('setEmail', res.data.email)
this.$store.commit('setAdmin', res.data.admin) this.$store.commit('setAdmin', res.data.admin)
this.$store.commit('setToken', res.data.token) this.$store.commit('setToken', res.data.token)
this.$buefy.snackbar.open({message:this.$t('errors.registered'), type: 'is-info'})
}).catch(e => { }).catch(e => {
this.register.loading = false this.register.loading = false
@ -469,6 +505,7 @@ export default {
this.$store.commit('setKoins', res.data.koins) this.$store.commit('setKoins', res.data.koins)
this.$store.commit('setID', res.data.id) this.$store.commit('setID', res.data.id)
this.$store.commit('setBot', res.data.bot) this.$store.commit('setBot', res.data.bot)
this.$buefy.snackbar.open({message:this.$t('errors.login'), type: 'is-info'})
}).catch(() => { }).catch(() => {
this.$buefy.snackbar.open({message:this.$t('errors.authFail'), type: 'is-warning'}) this.$buefy.snackbar.open({message:this.$t('errors.authFail'), type: 'is-warning'})
}) })
@ -499,6 +536,24 @@ export default {
}) })
}) })
}, },
logout() {
localStorage.removeItem('token');
this.$store.commit('setToken', '')
Object.assign(axios.defaults, {headers: {Authorization: this.$store.state.user.token}})
this.axios.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'userinfo')
.then(res => {
this.$store.commit('setUsername', res.data.username)
this.$store.commit('setEmail', res.data.email)
this.$store.commit('setEmailVerified', res.data.emailVerified)
this.$store.commit('setAdmin', res.data.admin)
this.$store.commit('setKoins', res.data.koins)
this.$store.commit('setID', res.data.id)
this.$store.commit('setBot', res.data.bot)
this.$buefy.snackbar.open({message:this.$t('errors.logout'), type: 'is-info'})
}).catch(() => {
this.$buefy.snackbar.open({message:this.$t('errors.logout'), type: 'is-info'})
})
},
fakeUser () { fakeUser () {
this.$store.commit('fakeUser') this.$store.commit('fakeUser')
this.$buefy.snackbar.open(`WARNING: You have fake authenticated, you do not have authenticated API access. Use for debug purposes only.`) this.$buefy.snackbar.open(`WARNING: You have fake authenticated, you do not have authenticated API access. Use for debug purposes only.`)
@ -506,6 +561,13 @@ export default {
} }
}, },
mounted() { mounted() {
this.axios.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'kaverti/state')
.then(res => {
this.$store.commit('setSettings', res.data)
this.$store.commit('setVersion', res.data.latestCanaryVersion)
}).catch(() => {
this.$buefy.snackbar.open({message:this.$t('errors.down'), type: 'is-info'})
})
this.axios.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'userinfo') this.axios.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'userinfo')
.then(res => { .then(res => {
this.$store.commit('setUsername', res.data.username) this.$store.commit('setUsername', res.data.username)
@ -526,6 +588,7 @@ export default {
localStorage.setItem('userCache', JSON.stringify(this.$store.state.user)); localStorage.setItem('userCache', JSON.stringify(this.$store.state.user));
this.$buefy.snackbar.open({message:this.$t('errors.authFail'), type: 'is-warning'}) this.$buefy.snackbar.open({message:this.$t('errors.authFail'), type: 'is-warning'})
this.loading = false this.loading = false
console.log(this.getBannerId())
}) })
} }
} }

View file

@ -1,143 +1,22 @@
<template> <template>
<div class="sidebar-page"> <div id="wrapper">
<section class="sidebar-layout">
<b-sidebar <aside id="sidebar-wrapper">
position="static" <div class="sidebar-brand">
:mobile="mobile" <h2>Logo</h2>
:expand-on-hover="expandOnHover"
:reduce="reduce"
type="is-light"
open
>
<div class="p-1">
<div class="block">
<img
src="https://raw.githubusercontent.com/buefy/buefy/dev/static/img/buefy-logo.png"
alt="Lightweight UI components for Vue.js based on Bulma"
/>
</div> </div>
<b-menu class="is-custom-mobile"> <ul class="sidebar-nav">
<b-menu-list label="Menu"> <li class="active">
<b-menu-item icon="information-outline" label="Info"></b-menu-item> <a href="#"><i class="fa fa-home"></i>Home</a>
<b-menu-item active expanded icon="settings" label="Administrator"> </li>
<b-menu-item icon="account" label="Users"></b-menu-item> <li>
<b-menu-item icon="cellphone-link" label="Devices"></b-menu-item> <a href="#"><i class="fa fa-plug"></i>Plugins</a>
<b-menu-item icon="cash-multiple" label="Payments" disabled></b-menu-item> </li>
</b-menu-item> <li>
<b-menu-item icon="account" label="My Account"> <a href="#"><i class="fa fa-user"></i>Users</a>
<b-menu-item icon="account-box" label="Account data"></b-menu-item> </li>
<b-menu-item icon="home-account" label="Addresses"></b-menu-item> </ul>
</b-menu-item> </aside>
</b-menu-list>
<b-menu-list>
<b-menu-item label="Expo" icon="link"></b-menu-item>
</b-menu-list>
<b-menu-list label="Actions">
<b-menu-item icon="logout" label="Logout"></b-menu-item>
</b-menu-list>
</b-menu>
</div>
</b-sidebar>
</section>
</div> </div>
</template> </template>
<script>
export default {
data() {
return {
expandOnHover: false,
mobile: "reduce",
reduce: false
};
}
};
</script>
<style lang="scss">
.p-1 {
padding: 1em;
}
.sidebar-page {
display: flex;
flex-direction: column;
width: 100%;
min-height: 100%;
// min-height: 100vh;
.sidebar-layout {
display: flex;
flex-direction: row;
min-height: 100%;
// min-height: 100vh;
}
}
@media screen and (max-width: 1023px) {
.b-sidebar {
.sidebar-content {
&.is-mini-mobile {
&:not(.is-mini-expand),
&.is-mini-expand:not(:hover) {
.menu-list {
li {
a {
span:nth-child(2) {
display: none;
}
}
ul {
padding-left: 0;
li {
a {
display: inline-block;
}
}
}
}
}
.menu-label:not(:last-child) {
margin-bottom: 0;
}
}
}
}
}
}
@media screen and (min-width: 1024px) {
.b-sidebar {
.sidebar-content {
&.is-mini {
&:not(.is-mini-expand),
&.is-mini-expand:not(:hover) {
.menu-list {
li {
a {
span:nth-child(2) {
display: none;
}
}
ul {
padding-left: 0;
li {
a {
display: inline-block;
}
}
}
}
}
.menu-label:not(:last-child) {
margin-bottom: 0;
}
}
}
}
}
}
.is-mini-expand {
.menu-list a {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
</style>

View file

@ -156,7 +156,12 @@
"authFail": "Request failed, you are not authenticated. (Is API blocked?)", "authFail": "Request failed, you are not authenticated. (Is API blocked?)",
"devBuild": "Warning: You are using a development build of Kaverti, expect instabilities.", "devBuild": "Warning: You are using a development build of Kaverti, expect instabilities.",
"disableDebug": "Debug mode disabled, you will no longer have access to development features until you refresh.", "disableDebug": "Debug mode disabled, you will no longer have access to development features until you refresh.",
"authSuccess": "Request successful, your token is valid, and the Kaverti server instance is running correctly." "authSuccess": "Request successful, your token is valid, and the Kaverti server instance is running correctly.",
"login": "You have been logged into Kaverti.",
"down": "There has appeared to be an issue communicating with Kaverti, please try again later.",
"canaryBuild": "You are using the Canary client, if you are expecting a stable experience, please use the regular one on Kaverti.com.",
"logout": "You have been logged out of Kaverti.",
"register": "You have been registered to Kaverti, Welcome!"
}, },
"user": { "user": {
"title": "Loading", "title": "Loading",

View file

@ -2,14 +2,14 @@ import Vue from 'vue'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
import store from './store' import store from './store'
import Buefy from 'buefy' import Buefy, {Snackbar} from 'buefy'
import axios from 'axios' import axios from 'axios'
import VueAxios from 'vue-axios' import VueAxios from 'vue-axios'
import i18n from './i18n' import i18n from './i18n'
Vue.use(VueAxios, axios) Vue.use(VueAxios, axios)
Vue.use(Buefy) Vue.use(Buefy)
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.prototype.$snackbar = Snackbar
new Vue({ new Vue({
router, router,
store, store,

View file

@ -37,6 +37,30 @@ const routes = [
name: 'Users', name: 'Users',
component: route('Users') component: route('Users')
}, },
{
path: '/teams',
name: 'Teams',
component: route('Teams')
},
{ path: '/t/:username', component: route('Team'), children: [
{ path: 'posts', component: route('UserPosts') },
{ path: 'threads', component: route('UserThreads') },
{ path: 'items', component: route('UserMarketplace') },
{ path: 'wall', component: route('UserWall') },
{ path: 'inventory', component: route('UserInventory') },
{ path: 'friends', component: route('UserFriends') },
{ path: 'awards', component: route('UserAwards') }
] },
{
path: '/awards',
name: 'Awards',
component: route('Awards')
},
{
path: '/forums',
name: 'Forums',
component: route('Forums')
},
{ {
path: '/roadmap', path: '/roadmap',
name: 'Roadmap', name: 'Roadmap',

View file

@ -12,13 +12,20 @@ if(JSON.parse(
} }
export default new Vuex.Store({ export default new Vuex.Store({
state: { state: {
name: "Kaverti",
debug: tb(process.env.VUE_APP_STAGING), debug: tb(process.env.VUE_APP_STAGING),
wind: false, wind: false,
client: { client: {
clientVersion: '1.0.0-prerelease', clientVersion: '1.0.0-prerelease',
latestClientVersion: '', latestClientVersion: '',
latestAPIVersion: '', latestAPIVersion: '',
bannerText: '',
bannerEnabled: false,
bannerId: 0,
registrationsDisabled: false,
name: "Kaverti",
logo: '',
icon: '',
release: process.env.VUE_APP_RELEASE
}, },
errors: { errors: {
errors: null, errors: null,
@ -41,6 +48,17 @@ export default new Vuex.Store({
} }
}, },
mutations: { mutations: {
setSettings(state, value) {
state.client.name = value.siteName
state.client.bannerEnabled = value.bannerEnabled
state.client.bannerText = value.bannerText
state.client.registrationsDisabled = value.RegistrationsDisabled
state.client.logo = value.logo
state.client.icon = value.icon
},
setVersion(state, value) {
state.client.latestClientVersion = value
},
turnOffDebug(state) { turnOffDebug(state) {
state.debug = false state.debug = false
}, },

5
src/views/Awards.vue Normal file
View file

@ -0,0 +1,5 @@
<template>
<main>
</main>
</template>

5
src/views/Forums.vue Normal file
View file

@ -0,0 +1,5 @@
<template>
<main>
</main>
</template>

View file

@ -0,0 +1,5 @@
<template>
<main>
</main>
</template>

5
src/views/Team.vue Normal file
View file

@ -0,0 +1,5 @@
<template>
<main>
</main>
</template>

5
src/views/Teams.vue Normal file
View file

@ -0,0 +1,5 @@
<template>
<main>
</main>
</template>

5
src/views/UserAwards.vue Normal file
View file

@ -0,0 +1,5 @@
<template>
<main>
</main>
</template>

View file

@ -0,0 +1,5 @@
<template>
<main>
</main>
</template>

View file

@ -0,0 +1,5 @@
<template>
<main>
</main>
</template>

5
src/views/UserItems.vue Normal file
View file

@ -0,0 +1,5 @@
<template>
<main>
</main>
</template>