mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
Initial commit.
This commit is contained in:
11
client/src/App.vue
Normal file
11
client/src/App.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App',
|
||||
};
|
||||
</script>
|
||||
BIN
client/src/assets/logo.png
Normal file
BIN
client/src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
113
client/src/components/HelloWorld.vue
Normal file
113
client/src/components/HelloWorld.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div class="hello">
|
||||
<h1>\{{ msg }}</h1>
|
||||
<h2>Essential Links</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="https://vuejs.org"
|
||||
target="_blank"
|
||||
>
|
||||
Core Docs
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://forum.vuejs.org"
|
||||
target="_blank"
|
||||
>
|
||||
Forum
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://chat.vuejs.org"
|
||||
target="_blank"
|
||||
>
|
||||
Community Chat
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://twitter.com/vuejs"
|
||||
target="_blank"
|
||||
>
|
||||
Twitter
|
||||
</a>
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
<a
|
||||
href="http://vuejs-templates.github.io/webpack/"
|
||||
target="_blank"
|
||||
>
|
||||
Docs for This Template
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Ecosystem</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="http://router.vuejs.org/"
|
||||
target="_blank"
|
||||
>
|
||||
vue-router
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="http://vuex.vuejs.org/"
|
||||
target="_blank"
|
||||
>
|
||||
vuex
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="http://vue-loader.vuejs.org/"
|
||||
target="_blank"
|
||||
>
|
||||
vue-loader
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/awesome-vue"
|
||||
target="_blank"
|
||||
>
|
||||
awesome-vue
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'HelloWorld',
|
||||
data() {
|
||||
return {
|
||||
msg: 'Welcome to Your Vue.js App',
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
h1, h2 {
|
||||
font-weight: normal;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
a {
|
||||
color: #42b983;
|
||||
}
|
||||
</style>
|
||||
5
client/src/lang/en/app.js
Normal file
5
client/src/lang/en/app.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
login: 'Login',
|
||||
password: 'Password',
|
||||
username_password: 'Username or Email',
|
||||
};
|
||||
21
client/src/main.js
Normal file
21
client/src/main.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import Vue from 'vue';
|
||||
import ElementUI from 'element-ui';
|
||||
import App from '@/App';
|
||||
import router from '@/router';
|
||||
import store from '@/store';
|
||||
|
||||
// Plugins
|
||||
import '@/plugins/i18n';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
Vue.use(ElementUI);
|
||||
|
||||
const app = new Vue({
|
||||
el: '#app',
|
||||
render: h => h(App),
|
||||
router,
|
||||
store,
|
||||
});
|
||||
|
||||
export default app;
|
||||
44
client/src/pages/Auth/Auth.vue
Normal file
44
client/src/pages/Auth/Auth.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="auth-page">
|
||||
<div class="auth-page__logo">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="auth-page__card">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'auth-warpper',
|
||||
beforeRouteEnter(to, from, next) {
|
||||
document.body.classList.add('page-auth');
|
||||
next();
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
document.body.classList.remove('page-auth');
|
||||
next();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body.page-auth{
|
||||
background: red;
|
||||
}
|
||||
|
||||
.auth-page{
|
||||
width: 600px;
|
||||
|
||||
&__logo{
|
||||
|
||||
}
|
||||
|
||||
&__card{
|
||||
background: #fff;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
32
client/src/pages/Auth/Login.vue
Normal file
32
client/src/pages/Auth/Login.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="login">
|
||||
<el-form ref="form" class="form-container">
|
||||
<el-form-item :label="$t('username_password')" prop="title">
|
||||
<el-input v-model="form.crediential" :maxlength="100" name="name" required />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('password')">
|
||||
<el-input v-model="form.password" name="password" />
|
||||
</el-form-item>
|
||||
|
||||
<el-button type="primary">{{ $t('login') }}</el-button>
|
||||
<el-link>{{ $t('forget_your_password') }}</el-link>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'login',
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
username: '',
|
||||
password: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
4
client/src/pages/Auth/ResetPassword.vue
Normal file
4
client/src/pages/Auth/ResetPassword.vue
Normal file
@@ -0,0 +1,4 @@
|
||||
<template>
|
||||
|
||||
|
||||
</template>
|
||||
33
client/src/pages/Dashboard/Dashboard.vue
Normal file
33
client/src/pages/Dashboard/Dashboard.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div id="dashboard" class="dashboard">
|
||||
<DashboardSidebar />
|
||||
|
||||
<div class="dashboard__content">
|
||||
<DashboardTopbar></DashboardTopbar>
|
||||
|
||||
<div class="dashboard__content-inner">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DashboardSidebar from '@/views/Sidebar';
|
||||
import DashboardTopbar from '@/views/Topbar';
|
||||
|
||||
export default {
|
||||
name: 'dashboard',
|
||||
components: {
|
||||
DashboardTopbar,
|
||||
DashboardSidebar,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#dashboard{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
</style>
|
||||
9
client/src/pages/Dashboard/Home.vue
Normal file
9
client/src/pages/Dashboard/Home.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div>Home</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'home',
|
||||
};
|
||||
</script>
|
||||
28
client/src/plugins/api-service.js
Normal file
28
client/src/plugins/api-service.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
export default {
|
||||
|
||||
get(resource, params) {
|
||||
return Vue.axios.get(`api/${resource}`, params).catch((error) => {
|
||||
throw new Error(`[Moosher] ApiService ${error}`);
|
||||
});
|
||||
},
|
||||
|
||||
post(resource, params) {
|
||||
return Vue.axios.post(`api/${resource}`, params);
|
||||
},
|
||||
|
||||
update(resource, slug, params) {
|
||||
return Vue.axios.put(`api/${resource}/${slug}`, params);
|
||||
},
|
||||
|
||||
put(resource, params) {
|
||||
return Vue.axios.put(`api/${resource}`, params);
|
||||
},
|
||||
|
||||
delete(resource) {
|
||||
return Vue.axios.delete(`api/${resource}`).catch((error) => {
|
||||
throw new Error(`[Moosher] ApiService ${error}`);
|
||||
});
|
||||
}
|
||||
};
|
||||
59
client/src/plugins/axios.js
Normal file
59
client/src/plugins/axios.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import axios from 'axios';
|
||||
import store from '~/store';
|
||||
import swal from 'sweetalert2'
|
||||
import Vue from 'vue';
|
||||
import VueAxios from 'vue-axios';
|
||||
import router from '~/routes';
|
||||
|
||||
// Set config defaults when creating the instance
|
||||
const http = axios.create();
|
||||
|
||||
// request interceptor.
|
||||
http.interceptors.request.use((request) => {
|
||||
const token = store.getters.authToken;
|
||||
const locale = Vue.i18n.locale();
|
||||
|
||||
if (token) {
|
||||
request.headers.common['x-access-token'] = token;
|
||||
}
|
||||
if (locale) {
|
||||
request.headers.common['Accept-Language'] = locale;
|
||||
}
|
||||
return request;
|
||||
});
|
||||
|
||||
// response interceptor
|
||||
http.interceptors.response.use(response => response, (error) => {
|
||||
const { status } = error.response;
|
||||
|
||||
if (status >= 500) {
|
||||
swal({
|
||||
type: 'error',
|
||||
title: Vue.i18n.translate('error_alert_title'),
|
||||
text: Vue.i18n.translate('error_alert_text'),
|
||||
reverseButtons: true,
|
||||
confirmButtonText: Vue.i18n.translate('ok'),
|
||||
cancelButtonText: Vue.i18n.translate('cancel')
|
||||
});
|
||||
}
|
||||
|
||||
if (status === 401) {
|
||||
swal({
|
||||
type: 'warning',
|
||||
title: Vue.i18n.translate('token_expired_alert_title'),
|
||||
text: Vue.i18n.translate('token_expired_alert_text'),
|
||||
reverseButtons: true,
|
||||
confirmButtonText: Vue.i18n.translate('ok'),
|
||||
cancelButtonText: Vue.i18n.translate('cancel')
|
||||
}).then(() => {
|
||||
store.commit('removeToken');
|
||||
router.push({ name: 'login' });
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(error)
|
||||
});
|
||||
|
||||
Vue.use(VueAxios, http);
|
||||
|
||||
export default http;
|
||||
29
client/src/plugins/i18n.js
Normal file
29
client/src/plugins/i18n.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
const defaultLocale = 'en';
|
||||
const loadedLangauges = [];
|
||||
const currentLocale = Vue.i18n.locale();
|
||||
|
||||
function setLanguage(locale, messages) {
|
||||
const localeMessages = messages.default;
|
||||
|
||||
Vue.i18n.add(locale, { ...localeMessages });
|
||||
|
||||
loadedLangauges.push(locale);
|
||||
Vue.i18n.set(locale);
|
||||
}
|
||||
|
||||
async function loadAsyncLanguage(locale) {
|
||||
if (locale !== currentLocale) {
|
||||
if (!loadedLangauges.includes(locale)) {
|
||||
const messages = await import(/* webpackChunkName: "lang-[request]" */ `@/lang/${locale}/app`);
|
||||
setLanguage(locale, messages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
await loadAsyncLanguage(defaultLocale);
|
||||
})();
|
||||
|
||||
export default loadAsyncLanguage;
|
||||
43
client/src/router/index.js
Normal file
43
client/src/router/index.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import Vue from 'vue';
|
||||
import Router from 'vue-router';
|
||||
import store from '@/store';
|
||||
import routes from './routes';
|
||||
|
||||
Vue.use(Router);
|
||||
|
||||
const router = new Router({
|
||||
mode: 'hash',
|
||||
routes: [
|
||||
...routes,
|
||||
],
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
const isAuthenticated = store.getters.authCheck;
|
||||
|
||||
if (to.matched.some(record => record.meta.requiresAuth)) {
|
||||
if (!isAuthenticated) {
|
||||
next({
|
||||
name: 'login',
|
||||
params: { nextUrl: to.fullPath },
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
} else if (to.matched.some(record => record.meta.guest)) {
|
||||
if (isAuthenticated) {
|
||||
next({
|
||||
name: 'dashboard.name',
|
||||
params: {
|
||||
nextUrl: to.fullPath,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
33
client/src/router/routes.js
Normal file
33
client/src/router/routes.js
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
const routes = [
|
||||
{
|
||||
name: 'auth',
|
||||
path: '/',
|
||||
component: () => import(/* webpackChunkName: "auth" */
|
||||
'@/pages/Auth/Auth.vue'),
|
||||
children: [
|
||||
{
|
||||
name: 'authLogin',
|
||||
path: '/login',
|
||||
component: () => import(/* webpackChunkName: "login" */
|
||||
'@/pages/Auth/Login.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'dashboard',
|
||||
path: '/dashboard',
|
||||
component: () => import(/* webpackChunkName: "dashboard" */
|
||||
'@/pages/Dashboard/Dashboard.vue'),
|
||||
children: [
|
||||
{
|
||||
name: 'dashboard.home',
|
||||
path: '/home',
|
||||
component: () => import(/* webpackChunkName: "dashboard_home" */
|
||||
'@/pages/Dashboard/Home.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
21
client/src/store/index.js
Normal file
21
client/src/store/index.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import vuexI18n from 'vuex-i18n';
|
||||
import sidebar from '@/store/modules/sidebar';
|
||||
import app from '@/store/modules/app';
|
||||
|
||||
const debug = process.env.NODE_ENV !== 'production';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
app,
|
||||
sidebar,
|
||||
},
|
||||
strict: debug,
|
||||
});
|
||||
|
||||
Vue.use(vuexI18n.plugin, store);
|
||||
|
||||
export default store;
|
||||
26
client/src/store/modules/app.js
Normal file
26
client/src/store/modules/app.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
const state = {
|
||||
appName: 'Ratteb',
|
||||
appVersion: '1.0.0',
|
||||
appBuild: '1000',
|
||||
|
||||
pageTitle: 'Welcome',
|
||||
actions: [],
|
||||
};
|
||||
|
||||
const getters = {
|
||||
getAppName: s => s.appName,
|
||||
getAppVersion: s => s.appVersion,
|
||||
getAppBuild: s => s.appBuild,
|
||||
getPageTitle: s => s.pageTitle,
|
||||
};
|
||||
|
||||
const actions = {
|
||||
|
||||
setPageTitle(s, title) {
|
||||
s.title = title;
|
||||
},
|
||||
};
|
||||
|
||||
export default { state, actions, getters };
|
||||
58
client/src/store/modules/auth.js
Normal file
58
client/src/store/modules/auth.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import ApiService from '~/plugins/api-service';
|
||||
|
||||
let state = {
|
||||
token: localStorage.getItem('token') || '',
|
||||
errors: {},
|
||||
role: {}
|
||||
};
|
||||
|
||||
const getters = {
|
||||
authCheck: s => s.token,
|
||||
authToken: s => s.token,
|
||||
authorizedUserRole: s => s.role,
|
||||
};
|
||||
|
||||
const actions = {
|
||||
/**
|
||||
* User login authentication request.
|
||||
*/
|
||||
async authRequest({ commit }, { form }) {
|
||||
const response = await ApiService.post('auth/login', form);
|
||||
const { data } = response;
|
||||
|
||||
if (data.token) {
|
||||
commit('setToken', data.token);
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Send reset password email or SMS.
|
||||
*/
|
||||
sendResetPassword({}, { email }) {
|
||||
return ApiService.post('auth/send_reset_password', { email });
|
||||
},
|
||||
|
||||
/**
|
||||
* Verify reset password verification code.
|
||||
*/
|
||||
verifyResetPasswordToken({ commit, dispatch }, { token }) {
|
||||
return ApiService.post(`reset/${token}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const mutations = {
|
||||
|
||||
setToken(state, token) {
|
||||
localStorage.setItem('token', token);
|
||||
state.token = token;
|
||||
},
|
||||
|
||||
removeToken(state) {
|
||||
localStorage.removeItem('token');
|
||||
state.token = '';
|
||||
},
|
||||
};
|
||||
|
||||
export default {state, actions, mutations, getters};
|
||||
48
client/src/store/modules/sidebar.js
Normal file
48
client/src/store/modules/sidebar.js
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
const state = {
|
||||
items: [
|
||||
{
|
||||
name: 'Home',
|
||||
to: 'dashboard.home',
|
||||
icon: 'home',
|
||||
count: null,
|
||||
},
|
||||
{
|
||||
name: 'Products',
|
||||
to: 'dashboard.home',
|
||||
},
|
||||
{
|
||||
name: 'Customers',
|
||||
to: 'dashboard.home',
|
||||
},
|
||||
{
|
||||
name: 'Suppliers',
|
||||
to: 'dashboard.home',
|
||||
},
|
||||
{
|
||||
name: 'Reports',
|
||||
to: 'dashboard.home',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const getters = {
|
||||
getSidebarItems: s => s.items,
|
||||
getSidebarItem: s => name => s.items.find(item => item.name === name),
|
||||
};
|
||||
|
||||
const actions = {
|
||||
|
||||
/**
|
||||
* Set count to the given sidebar item.
|
||||
*/
|
||||
setSidebarItemCount(s, { name, count }) {
|
||||
s.items.forEach((item) => {
|
||||
if (item.name === name) {
|
||||
item.count = count;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default { state, getters, actions };
|
||||
2
client/src/utils/vuex.js
Normal file
2
client/src/utils/vuex.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export const set = property => (store, payload) => (store[property] = payload)
|
||||
export const toggle = property => store => (store[property] = !store[property])
|
||||
35
client/src/views/Sidebar/SidebarItem.vue
Normal file
35
client/src/views/Sidebar/SidebarItem.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div class="sidebar__item" :class="computedClasses">
|
||||
<router-link :to="to">
|
||||
<span class="title">{{ name }}</span>
|
||||
<span v-if="count" class="count">{{ count }}</span>
|
||||
</router-link>
|
||||
|
||||
<div v-if="hasChildren" class="sidebar__item-children">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'sidebar-item',
|
||||
props: {
|
||||
name: String,
|
||||
to: String,
|
||||
icon: String,
|
||||
children: Array,
|
||||
},
|
||||
computed: {
|
||||
computedClasses() {
|
||||
return {
|
||||
[`sidebar__item--${this.name}`]: this.name,
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
hasChildren() {
|
||||
return this.children.length > 0;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
54
client/src/views/Sidebar/index.vue
Normal file
54
client/src/views/Sidebar/index.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="dashboard__sidebar sidebar">
|
||||
|
||||
<div class="sidebar__app">
|
||||
<div class="sidebar__app-logo">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="sidebar__app-info">
|
||||
<h6 class="title">{{ appName }}</h6>
|
||||
<span class="version">{{ appVersion }} (build {{ appBuild }})</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar__menu">
|
||||
<SidebarItem
|
||||
v-for="(item, index) in sidebarItems" :key="index"
|
||||
:to="item.to"
|
||||
:name="item.name"
|
||||
:count="item.count"
|
||||
:children="item.children"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SidebarItem from '@/views/Sidebar/SidebarItem';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'sidebar',
|
||||
components: {
|
||||
SidebarItem,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
appName: 'getAppName',
|
||||
appVersion: 'getAppVersion',
|
||||
appBuild: 'getAppBuild',
|
||||
sidebarItems: 'getSidebarItems',
|
||||
}),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.dashboard__sidebar{
|
||||
width: 210px;
|
||||
background: red;
|
||||
transition: width 0.3s;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
41
client/src/views/Topbar.vue
Normal file
41
client/src/views/Topbar.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div class="topbar">
|
||||
<div class="topbar__title">
|
||||
<h3>{{ pageTitle }}</h3>
|
||||
</div>
|
||||
|
||||
<div class="topbar__actions">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'dashboard-topbar',
|
||||
computed: {
|
||||
...mapGetters({
|
||||
pageTitle: 'getPageTitle',
|
||||
}),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.topbar{
|
||||
padding-bottom: 12px;
|
||||
|
||||
&__title{
|
||||
|
||||
h3{
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
&__actions{
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user