cubash-archive/frontend/src/App.vue

1012 lines
33 KiB
Vue

<style>
trpl-title {
font-size: 32px ;
background: -webkit-linear-gradient(#00b3ff, #007aff) ;
-webkit-background-clip: text ;
-webkit-text-fill-color: transparent ;
}
trpl-para {
background: #007aff ;
-webkit-background-clip: text ;
-webkit-text-fill-color: transparent ;
font-weight: bold ;
}
h1 {
font-size: 32px ;
}
h2 {
font-size: 24px ;
}
mini-br {
border-width: 0.1em;
}
unselectable {
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+/Edge */
user-select: none; /* Standard */
}
.vertical {
margin: 0;
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
</style>
<template>
<div id='app'>
<main>
<modal-window v-model='showAjaxErrorsModal' style='z-index: 100' width='25rem' :no-padding='true' :is-error="true">
<div slot="header">
Oh uh!
</div>
<div slot='main'>
<p :key='error' v-for='error in this.$store.state.ajaxErrors' style='margin: 1rem;'>{{error}}</p>
</div>
<button
slot='footer'
class='button is-info'
style='z-index: 100; width: 100%;'
@click='showAjaxErrorsModal = false'
ref='ajaxErrorsModalButton'
>
Okay
</button>
</modal-window>
<b-modal :can-cancel="false" :active="connModal" @update:active="value => connModal = value" v-model="connModal" full-screen>
<div class="modal-card" style="width: auto">
<section class="vertical">
<center>
<sync-loader color="#445159" :size="20" :sizeUnit="px"></sync-loader>
<h1>Connecting to Kaverti...</h1>
<p>Taking a while? Check the <a href="https://status.troplo.com">service status</a>, or alert us on <a href="https://twitter.com/Kaverti">Twitter</a>!</p>
</center>
</section>
</div>
</b-modal>
<modal-window
v-model='showAccountModal'
@input='closeAccountModal'
style="z-index: 99"
:no-padding='true'
:hide-footer='true'
:hide-header="true"
>
<tab-view
:tabs='["Register", "Login", "Recovery"]'
v-model="showAccountTab"
padding='true'
slot='main'
>
<template slot='Register'>
<p style='margin-top: 0;' v-if='$store.state.token'>
<strong>Providing the state token is still valid, this will create an admin account</strong>
</p>
<p style='margin-top: 0;' v-if='$store.state.passkey'>
<strong>Providing a PassKey, this will create a normal user account</strong>
</p>
<p style='margin-top: 0;' v-else>
Sign up to {{name}} today!
<br/>It's fast and easy.
</p>
<br/>
<form @submit.prevent='createAccount'>
<fancy-input
v-model='signup.username'
:label-position="kavelabelPosition"
:error='signup.errors.username'
placeholder='Username'
width='100%'
>
</fancy-input>
<fancy-input
v-model='signup.email'
:label-position="kavelabelPosition"
:error='signup.errors.email'
placeholder='Email'
width='100%'
type="email"
>
</fancy-input>
<fancy-input
v-model='signup.password'
:label-position="kavelabelPosition"
:error='signup.errors.hash'
placeholder='Password'
type='password'
width='100%'
>
</fancy-input>
<fancy-input
v-model='signup.confirmPassword'
:label-position="kavelabelPosition"
:error='signup.errors.confirmPassword'
placeholder='Confirm Password'
type='password'
width='100%'
>
</fancy-input>
By pressing the "Register" button, you agree to the Kaverti <router-link to="/legal/tos" v-on:click.native="closeAccountModal">Terms of Service</router-link>, and have read the <router-link to="/legal/privacy" v-on:click.native="closeAccountModal">Privacy Policy</router-link>.
<div style='margin-top: 0.5rem;'>
<b-button
class='is-info'
style="width: 55%"
:loading='signup.loading'
@click='createAccount'
v-if='!$store.state.meta.RegistrationsDisabled'
>
Register
</b-button>
<b-button
class='is-info disabled'
disabled="disabled"
style="width: 55%"
:loading='signup.loading'
@click='closeAccountModal'
v-if='$store.state.meta.RegistrationsDisabled'
>
Disabled
</b-button>
&nbsp;
<b-button style="float: right" class="is-danger-passive" @click='closeAccountModal'>
Cancel
</b-button>
</div>
</form>
</template>
<template slot='Login'>
<p style='margin-top: 0;'>
Login to {{name}} for the full experience.
</p>
<form @submit.prevent='doLogin'>
<fancy-input
v-model='login.username'
:error='login.errors.username'
placeholder='Username'
width='100%'
>
</fancy-input>
<fancy-input
v-model='login.password'
:error='login.errors.hash'
placeholder='Password'
type='password'
width='100%'
>
</fancy-input>
<div style='margin-top: 0.5rem;'>
<b-button
class='is-info'
style="width: 55%"
:loading='login.loading'
@click='doLogin'
>
Login
</b-button>
&nbsp;
<b-button style="float: right" class="is-danger-passive" @click='closeAccountModal'>
Cancel
</b-button>
</div>
</form>
</template>
<template slot='Recovery'>
<p style='margin-top: 0;'>
{{name}} Account Recovery
</p>
<form @submit.prevent='doRecovery'>
<fancy-input
v-model='recovery.email'
:error='recovery.errors.email'
placeholder='Email'
width='100%'
>
</fancy-input>
<div style='margin-top: 0.5rem;'>
<b-button
class='is-info'
style="width: 55%"
:loading='recovery.loading'
@click='doRecovery'
>
Send email
</b-button>
&nbsp;
<b-button style="float: right" class="is-danger-passive" @click='closeAccountModal'>
Cancel
</b-button>
</div>
</form>
</template>
</tab-view>
</modal-window>
<template>
<b-navbar v-bind:fixed-top="true">
<template slot="brand">
<b-navbar-item tag="router-link" :to="{ path: '/' }">
<VueSkipTo to="#main" label="Skip to main content" />
<img
:src = $store.state.meta.logo
>
</b-navbar-item>
</template>
<template slot="start">
<b-navbar-item tag="router-link" :to="{ path: '/forums' }"><b>
Forums
</b></b-navbar-item>
<b-navbar-item tag="router-link" href="https://support.kaverti.com"><b>
Support
</b></b-navbar-item>
<b-navbar-item tag="router-link" :to="{ path: '/users' }"><b>
Users
</b></b-navbar-item>
<b-navbar-item tag="router-link" :to="{ path: '/marketplace' }"><b>
Marketplace
</b></b-navbar-item>
<b-navbar-item tag="router-link" :to="{ path: '/games' }"><b>
Games
</b></b-navbar-item>
<b-navbar-item tag="router-link" :to="{ path: '/teams' }"><b>
Teams
</b></b-navbar-item>
<div class="navbar-item has-dropdown is-hoverable is-info" type="is-info">
<a class="navbar-link">
<b>More</b>
</a>
<div class="navbar-dropdown is-boxed">
<router-link class="navbar-item" to='/blog'>Blog</router-link>
<a class="navbar-item" href="https://twitter.com/Kaverti">
Twitter
</a>
<a class="navbar-item" href="https://discord.gg/3jN5RAX">
Discord
</a>
<router-link class="navbar-item" to='/developers'>Developers</router-link>
<router-link class="navbar-item is-active" to='/premium'>Upgrade</router-link>
<router-link class="navbar-item" to='/licenses'>Credits and Licenses</router-link>
<router-link class="navbar-item" to='/contributors'>Contributors</router-link>
<router-link class="navbar-item is-active" to='/jobs'>We're Hiring!</router-link>
</div>
</div>
</template>
<template slot="end" v-if='$store.state.username'>
<b-navbar-item @click="dailyReward()" v-if="$store.state.koins"><b>
{{$store.state.koins}} Koins
</b></b-navbar-item>
<b-navbar-item v-if="!$store.state.koins"><b>
<i class="fas fa-circle-notch fa-spin"></i> Loading...
</b></b-navbar-item>
<b-navbar-item tag="div">
<NotificationButton class="is-hidden-mobile"></NotificationButton>
<div>
<div class="navbar-item has-dropdown is-hoverable is-info">
<a class="navbar-link">
<b>{{this.$store.state.username}}</b>
</a>
<div class="navbar-dropdown is-boxed">
<router-link class="navbar-item" :to='"/u/" + this.$store.state.username'>My Profile</router-link>
<router-link class="navbar-item" to='/settings'>Settings</router-link>
<router-link class="navbar-item is-hidden-desktop" to='/notifications'>Notifications</router-link>
<router-link to='/admin' class="navbar-item" v-if='$store.state.admin'>Admin Panel</router-link>
<router-link class="navbar-item is-active" to='/premium'>Upgrade</router-link>
<a class="navbar-item" @click='logout'>
Log out
</a>
</div>
</div>
</div>
<search-box header-bar='true'></search-box>
</b-navbar-item>
</template>
<template slot="end" v-else>
<b-navbar-item tag="div">
<div class="buttons">
<a class="button is-info" @click="showAccountModalTab(0)">
<strong>Sign up</strong>
</a>
<a class="button is-light" @click="showAccountModalTab(1)">
Log in
</a>
</div>
</b-navbar-item>
</template>
</b-navbar>
</template>
<div v-if='$store.state.clientVersion !== $store.state.latestClientVersion' class="container is-fullhd" style="padding-left: 5px; padding-right: 5px; padding-top: 20px; padding-bottom: 5px;">
<div class="notification is-info">
You are using an outdated client, refresh to update.
</div>
</div>
<div v-if='$store.state.meta.bannerText && !$store.state.username' class="container is-fullhd" style="padding-left: 5px; padding-right: 5px; padding-top: 20px; padding-bottom: 5px;">
<div class="notification is-info">
{{$store.state.meta.bannerText}}
</div>
</div>
<div v-if="!$store.state.emailVerified && $store.state.username" class="container is-fullhd" style="padding-left: 5px; padding-right: 5px; padding-top: 20px; padding-bottom: 5px;">
<div class="notification is-danger">
<b>Your email is not verified.</b> You will have limited access to Kaverti until you verify your email in <router-link to="/settings/account">User Settings</router-link>
</div>
</div>
<not-found v-show='$store.state.show404Page'></not-found>
<transition name='fade'>
<router-view id="main" v-show='!$store.state.show404Page'></router-view>
</transition>
<footer class="footer">
<div class="content has-text-centered">
<p>
<strong>Kaverti</strong> by <a href="https://troplo.com">Troplo</a> and <router-link to="/contributors">Contributors</router-link>
<br/>
Be sure to read the <router-link to="/legal/tos">Terms of Service</router-link> and <router-link to="/legal/privacy">Privacy Policy</router-link>
</p>
</div>
</footer>
</main>
</div>
</template>
<style>
@import 'https://kit-pro.fontawesome.com/releases/v5.14.0/css/pro.min.css';
</style>
<style lang="scss">
$primary: #007aff ;
$navbar-dropdown-arrow: #007aff ;
</style>
<script>
import ModalWindow from './components/ModalWindow'
import TabView from './components/TabView'
import FancyInput from './components/FancyInput'
import NotificationButton from './components/NotificationButton'
import SearchBox from './components/SearchBox'
import { SyncLoader } from '@saeris/vue-spinners'
import NotFound from './components/routes/NotFound'
import AjaxErrorHandler from './assets/js/errorHandler'
export default {
name: 'app',
components: {
ModalWindow,
TabView,
FancyInput,
NotificationButton,
SearchBox,
NotFound,
SyncLoader
},
data () {
return {
kavelabelPosition: 'on-border',
signup: {
username: '',
password: '',
email: '',
confirmPassword: '',
passkey: '',
loading: false,
errors: {
username: '',
email: '',
hash: '',
confirmPassword: ''
}
},
login: {
username: '',
password: '',
loading: false,
errors: {
username: '',
hash: ''
}
},
recovery: {
email: '',
loading: false,
errors: {
email: ''
}
},
loadingLogout: false,
showMenu: false,
connModal: true,
ajaxErrorHandler: AjaxErrorHandler(this.$store)
}
},
computed: {
name () {
return this.$store.state.meta.name
},
logo () {
if(this.$store.state.meta.logo) {
this.$store.state.meta.logo
}
return "https://cdn.kaverti.com/logo.png";
},
theme () {
return this.$store.state.theme
},
showAccountModal: {
get () { return this.$store.state.accountModal },
set (val) {
this.$store.commit('setAccountModalState', val);
}
},
showAjaxErrorsModal: {
get () { return this.$store.state.ajaxErrorsModal },
set (val) { this.$store.commit('setAjaxErrorsModalState', val) }
},
showConnModal: {
get () { return this.$store.state.connModal },
set (val) {
this.$store.commit('setConnModal', val);
}
},
showOutLinkModal: {
get () { return this.$store.state.showOutLinkModal },
set (val) { this.$store.commit('setOutLinkModalState', val) }
},
showAccountTab : {
get () { return this.$store.state.accountTabs },
set (index) { this.$store.commit('setAccountTabs', index) }
},
categories() {
return this.$store.state.meta.categories
}
},
methods: {
darkTheme() {
let darkThemeLinkEl = document.createElement("link");
darkThemeLinkEl.setAttribute("rel", "stylesheet");
darkThemeLinkEl.setAttribute("href", "https://cdn.kaverti.com/css/dark.css");
darkThemeLinkEl.setAttribute("id", "dark-theme");
let docHead = document.querySelector("head");
docHead.append(darkThemeLinkEl);
},
disableDarkTheme() {
let darkThemeLinkEl = document.removeElement("dark-theme");
let docHead = document.querySelector("head");
docHead.append(darkThemeLinkEl);
},
recaptcha() {
this.$recaptcha('login').then((token) => {
console.log(token) // Will print the token
})},
showAccountModalTab (index) {
this.toggleMenu()
this.showAccountModal = true
this.showAccountTab = index
},
toggleMenu () {
this.showMenu = !this.showMenu
},
dailyReward () {
this.loadingLogout = true
this.axios.get(
'/api/v1/users/reward'
).then(res => {
this.$store.commit('setKoins', res.data.koins)
}).catch(err => {
this.loadingLogout = false
this.ajaxErrorHandler(err)
})
},
logout () {
this.toggleMenu()
this.loadingLogout = true
this.axios.post(
'/api/v1/user/' +
this.$store.state.username +
'/logout'
).then(res => {
this.loadingLogout = false
this.$store.commit('setUsername', '')
this.$store.commit('setAdmin', res.data.admin)
this.$socket.emit('accountEvent')
}).catch(err => {
this.loadingLogout = false
this.ajaxErrorHandler(err)
})
},
botLogout (res) {
this.loadingLogout = false
this.$store.commit('setUsername', '')
this.$store.commit('setAdmin', res.data.admin)
this.$socket.emit('accountEvent')
this.$router.push('/')
},
clearSignup () {
this.signup.username = ''
this.signup.password = ''
this.signup.confirmPassword = ''
this.signup.email = ''
this.signup.passkey = ''
this.$store.commit('setToken', null)
this.$store.commit('setPassKey', null)
},
clearSignupErrors () {
this.signup.errors.username = ''
this.signup.errors.hash = ''
this.signup.errors.confirmPassword = ''
this.signup.errors.email = ''
this.signup.errors.passkey = ''
},
clearRecovery () {
this.recovery.email = ''
this.$store.commit('setToken', null)
this.$store.commit('setPassKey', null)
},
clearRecoveryErrors () {
this.recovery.errors.email = ''
},
pollConn() {
this.polling = setInterval(() => {
this.retryConnection()
}, 5000)
},
pollConnAlt() {
this.polling = setInterval(() => {
this.retryConnection()
}, 25000)
},
clearLogin () {
this.login.username = ''
this.login.password = ''
},
clearLoginErrors () {
this.login.errors.username = ''
this.login.errors.hash = ''
},
retryConnection () {
this.axios.get('/api/v1/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('setDevMode', res.data.developerMode)
this.$store.commit('setTheme', res.data.theme)
this.axios.get('/api/v1/kaverti/state')
.then(res => {
this.$store.commit('setSettings', res.data)
this.$store.dispatch('setTitle', this.$store.state.meta.title)
this.$store.commit('setAPIVersion', res.data.latestAPIVersion)
this.$store.commit('setLatestVersion', res.data.latestStableVersion)
this.closeConn()
}).catch(err => {
if(err.response.data.errors[0].name === 'noSettings') {
this.showConn()
} else {
this.showConn()
}
})
})
this.axios.get('/api/v1/kaverti/state')
.then(res => {
this.$store.commit('setSettings', res.data)
this.$store.dispatch('setTitle', this.$store.state.meta.title)
this.$store.commit('setAPIVersion', res.data.latestAPIVersion)
this.$store.commit('setLatestVersion', res.data.latestStableVersion)
this.axios.get('/api/v1/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('setDevMode', res.data.developerMode)
this.$store.commit('setTheme', res.data.theme)
this.closeConn()
}).catch(err => {
this.showConn()
if(err.response.data.errors[0].name === 'noSettings') {
this.showConn()
} else {
this.showConn()
}
})
})
},
closeAccountModal () {
this.showAccountModal = false
this.clearLogin()
this.clearSignup()
this.clearLoginErrors()
this.clearSignupErrors()
},
showConn () {
this.connModal = true
},
closeConn () {
this.connModal = false
},
createAccount () {
this.clearSignupErrors()
let postParams = {
username: this.signup.username,
password: this.signup.password,
email: this.signup.email,
passkey: this.signup.passkey
}
if(this.$store.state.token) {
postParams.admin = true
postParams.token = this.$store.state.token
}
if(this.$store.state.passkey) {
postParams.passkey = this.$store.state.passkey
}
if(this.signup.password !== this.signup.confirmPassword) {
this.signup.errors.confirmPassword = 'Passwords must match'
} else {
this.signup.loading = true
this.axios.post(`/api/v1/passkey/${this.$store.state.passkey}`, postParams).then(res => {
this.signup.loading = false
this.$store.commit('setUsername', res.data.username)
this.$store.commit('setAdmin', res.data.admin)
this.closeAccountModal()
this.$socket.emit('accountEvent')
this.axios
.post('/api/v1/users/email-send')
.then(() => {
this.email.loading = false
})
.catch(e => {
this.email.loading = false
AjaxErrorHandler(this.$store)(e)
})
}).catch(e => {
this.signup.loading = false
this.ajaxErrorHandler(e, (error) => {
let path = error.path
if(this.signup.errors[path] !== undefined && this.signup.errors[path] !== undefined) {
this.signup.errors[path] = error.message
}
})
})
}
},
doLogin () {
this.clearSignupErrors()
if(!this.login.username.trim().length) {
this.login.errors.username = 'Username must not be blank'
return
}
this.login.loading = true
this.axios.post(`/api/v1/users/login`, {
username: this.login.username,
password: this.login.password
}).then(res => {
this.login.loading = false
this.$store.commit('setUsername', res.data.username)
this.$store.commit('setAdmin', res.data.admin)
this.closeAccountModal()
this.$socket.emit('accountEvent')
this.axios.get('/api/v1/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('setDevMode', res.data.developerMode)
this.$store.commit('setTheme', res.data.theme)
this.closeConn()
}).catch(err => {
this.showConn()
this.pollConn()
if(err.response.data.errors[0].name === 'noSettings') {
this.showConn()
this.pollConn()
} else {
this.showConn()
this.pollConn()
}
})
}).catch(e => {
this.login.loading = false
this.ajaxErrorHandler(e, (error) => {
let path = error.path
if(this.signup.errors[path] !== undefined && this.signup.errors[path] !== undefined) {
this.signup.errors[path] = error.message
}
})
})
},
doRecovery () {
this.clearRecoveryErrors()
if(!this.recovery.email.trim().length) {
this.recovery.errors.email = 'Email must not be blank'
return
}
this.recovery.loading = true
this.axios.post(`/api/v1/users/recovery/send`, {
email: this.recovery.email
}).then(res => {
this.recovery.loading = false
this.$store.commit('setUsername', res.data.username)
this.$store.commit('setAdmin', res.data.admin)
this.closeAccountModal()
this.axios.get('/api/v1/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('setDevMode', res.data.developerMode)
this.$store.commit('setTheme', res.data.theme)
this.closeConn()
}).catch(err => {
this.showConn()
this.pollConn()
if(err.response.data.errors[0].name === 'noSettings') {
this.showConn()
this.pollConn()
} else {
this.showConn()
this.pollConn()
}
})
}).catch(e => {
this.recovery.loading = false
this.ajaxErrorHandler(e, (error) => {
let path = error.path
if(this.recovery.errors[path] !== undefined && this.recovery.errors[path] !== undefined) {
this.recovery.errors[path] = error.message
}
})
})
}
},
mounted () {
this.axios.get('/api/v1/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('setDevMode', res.data.developerMode)
this.$store.commit('setTheme', res.data.theme)
this.$store.commit('setTheme', res.data.theme)
this.closeConn()
}).catch(err => {
this.showConn()
this.pollConn()
if(err.response.data.errors[0].name === 'noSettings') {
this.showConn()
this.pollConn()
} else {
this.showConn()
this.pollConn()
}
})
this.axios.get('/api/v1/kaverti/state')
.then(res => {
this.$store.commit('setSettings', res.data)
this.$store.dispatch('setTitle', this.$store.state.meta.title)
this.$store.commit('setAPIVersion', res.data.latestAPIVersion)
this.$store.commit('setLatestVersion', res.data.latestStableVersion)
this.closeConn()
this.axios.get('/api/v1/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('setTheme', res.data.theme)
if(res.data.theme === "dark") {
this.darkTheme()
}
this.closeConn()
}).catch(err => {
this.showConn()
this.pollConn()
if(err.response.data.errors[0].name === 'noSettings') {
this.showConn()
this.pollConn()
} else {
this.showConn()
this.pollConn()
}
})
this.axios.get(
'/api/v1/users/reward'
).then(res => {
this.$store.commit('setKoins', res.data.koins)
})
}).catch(err => {
this.showConn()
this.pollConn()
if(err.response.data.errors[0].name === 'noSettings') {
this.showConn()
this.pollConn()
} else {
this.showConn()
this.pollConn()
}
})
this.axios.get('/api/v1/forums/category')
.then(res => {
this.$store.commit('addCategories', res.data)
if(!this.$store.state.meta.title.length && this.$route.params.category) {
let selectedCategory = this.$route.params.category.toUpperCase()
let category = this.categories.find(c => c.value === selectedCategory)
this.$store.dispatch('setTitle', category.name)
}
})
this.pollConnAlt()
},
watch: {
$route () {
this.showMenu = false
},
'$store.state.ajaxErrorsModal': function(val) {
if(val) {
this.$refs.ajaxErrorsModalButton.focus()
}
},
}
}
</script>
<style lang='scss'>
@import url('https://fonts.googleapis.com/css?family=Lato:400,400i,500,500i,700');
@import './assets/scss/variables.scss';
@import './assets/sass/primary';
$primary: #0ba8e6 ;
$colors: (
"primary": #0ba8e6
);
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
color: $color__text--primary;
@include text;
}
* {
box-sizing: border-box;
}
.route_container {
width: 90%;
max-width: 1250px;
margin: 0 auto;
margin-top: 2rem;
padding-bottom: 2rem;
}
.logo {
@include text($font--role-emphasis, 2rem, 600);
@include user-select(none);
cursor: pointer;
background: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 20rem;
&:hover, &:visited, &:active {
outline: none;
color: $color__text--primary;
}
}
@media (max-width: 870px) {
.route_container {
width: calc(100% - 2rem);
margin: 0 1rem;
margin-top: 0rem;
}
.logo {
position: relative;
z-index: 2;
max-width: calc(100vw - 7rem);
}
.header__menu_button {
display: inline-block;
cursor: pointer;
}
.header__overlay--show {
pointer-events: all;
opacity: 1;
}
.header__group:first-child {
margin-left: 1rem;
}
.header__group:nth-child(2) {
position: fixed;
padding-top: 1.5rem;
width: 17rem;
display: flex;
flex-direction: column;
z-index: 2;
background: #fff;
top: 0;
left: calc(-100% - 2rem);
height: 100%;
box-shadow: none;
transition: left 0.4s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.4s ease-in;
> .button {
width: 100%;
border-radius: 0;
margin: 0;
margin-bottom: 1rem;
}
&::before {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 0.3rem;
content: '';
background: linear-gradient(to right, hsl(200, 98%, 43%), hsla(193, 98%, 48%, 1));
}
}
.header__group:nth-child(2).header__group--show {
left: 0;
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.4);
}
.search_box {
margin: 0;
display: inline-block;
}
}
</style>