Vuetify is the default customizable section with hierarchical menu with VNavigationDrawer component. Sidebar menu is located within the
packages/admin/src/components/layout/AppBar.vue
src/layout/Admin.vue
<template>
<v-app>
<va-layout v-if="authenticatedUser">
<template>
<va-app-bar :key="getCurrentLocale" color="primary" density="compact" :header-menu="getHeaderMenu" sidebar-color="white">
<template v-slot:logo>
<div class="mb-1" style="letter-spacing: 1px;">logo</div>
</template>
<template v-slot:avatar>
<v-avatar v-if="avatarExists" size="24px">
<v-img :src="getAvatar" alt="Avatar"></v-img>
</v-avatar>
<v-icon v-else>mdi-account-circle</v-icon>
</template>
<template v-slot:profile>
<v-card min-width="300">
<v-list nav>
<v-list-item v-if="getFullname" :prepend-avatar="getAvatar">
<div class="list-item-content">
<v-list-item-title class="title">{{ getFullname }}</v-list-item-title>
<v-list-item-subtitle v-if="getEmail">{{ getEmail }}</v-list-item-subtitle>
</div>
</v-list-item>
<v-divider></v-divider>
<v-card flat>
<v-card-text style="padding:9px">
<v-list-item v-for="(item, index) in getProfileMenu" :key="index" link :to="item.link" logout : null class=" mt-2">
<template v-slot:prepend>
<v-icon>{{ item.icon }}</v-icon>
</template>
<v-list-item-title>{{ item.text }}</v-list-item-title>
</v-list-item>
</v-card-text>
</v-card>
</v-list>
</v-card>
</template>
</va-app-bar>
</template>
<template>
<va-breadcrumbs></va-breadcrumbs>
</template>
<template>
<va-aside></va-aside>
</template>
<template>
<va-footer :key="getCurrentLocale" :menu="getFooterMenu">
<span style="font-size:13px">© 2023</span>
</va-footer>
</template>
</va-layout>
</v-app>
</template>
<script>
import isEmpty from "lodash/isEmpty"
import { useDisplay } from "vuetify";
import { mapActions } from "vuex";
import Trans from "@/i18n/translation";
export default {
name: "App",
inject: ["admin"],
data() {
return {
authenticatedUser: null,
};
},
async created() {
/**
* Set default locale
*/
const lang = Trans.guessDefaultLocale();
if (lang && Trans.supportedLocales.includes(lang)) { // assign browser language
await Trans.switchLanguage(lang);
}
/**
* Check user is authenticated
*/
this.authenticatedUser = await this.checkAuth();
if (! this.authenticatedUser) {
this.$router.push({name: "login"});
} else {
//
// Please do not remove it, it periodically updates the session lifetime.
// Thus, as long as the user's browser is open, the user logged in to the application,
// otherwise the session will be closed when the ttl period expires.
//
this.admin.http.post('/auth/session', { update: 1 });
}
},
computed: {
avatarExists() {
let base64Image = this.$store.getters["auth/getAvatar"];
if (base64Image == "undefined" || base64Image == "null" || isEmpty(base64Image)) {
return false;
}
return true;
},
getAvatar() {
let base64Image = this.$store.getters["auth/getAvatar"];
if (base64Image == "undefined" || base64Image == "null" || isEmpty(base64Image)) {
return this.admin.getConfig().avatar.base64; // default avatar image
}
return base64Image;
},
getEmail() {
return this.$store.getters["auth/getEmail"];
},
getFullname() {
return this.$store.getters["auth/getFullname"];
},
getCurrentLocale() {
return this.$store.getters[`getLocale`];
},
getHeaderMenu() {
return [];
},
getProfileMenu() {
return [
{
icon: "mdi-account",
text: this.$t("va.account"),
link: "/account",
},
{
icon: "mdi-key-variant",
text: this.$t("va.changePassword"),
link: "/password",
},
{
icon: "mdi-logout",
text: this.$t("va.logout"),
logout: true,
},
];
},
getFooterMenu() {
return [
{
href: "https://oloma.dev/end-user-license-agreement",
text: this.$t("menu.terms"),
},
]
}
},
methods: {
...mapActions({
checkAuth: "auth/checkAuth",
}),
logout() {
this.$store.dispatch("auth/logout");
},
},
};
</script>
Any navigation menu that can be placed in components that support navigation is a simple array of objects that represent a link. Components that support navigation; It consists of a total of 4 different components: header, profile, sidebar and footer menu.
Menus are created by sending a simple menu array as follows to these components.
[
{
icon: "mdi-account",
text: this.$t("menu.profile"),
link: "/profile",
},
{
icon: "mdi-settings",
text: this.$t("menu.settings"),
link: "/settings",
},
]
Sidebar menu example:
src/_nav.js
export default {
build: async function(t, admin) {
return [
{
icon: "mdi-view-dashboard-outline",
text: t("menu.dashboard"),
link: "/dashboard",
},
{
icon: "mdi-cart-variant",
text: t("menu.plans"),
children: [
{
icon: "circle",
text: t("menu.subscriptions"),
link: "/subscriptions",
},
{
icon: "circle",
text: t("menu.services"),
link: "/services",
},
]
},
];
} // end func
} // end class
To create the menu dynamically based on authorizations, see related document.
Property | Type | Description |
---|---|---|
icon | string |
The menu icon shown on the left. Must be a valid mdi and is only supported in sidebar and profile menu. |
text | string |
Link tag. |
link | string | object |
Current Vue router menu. It cannot be used with child connections. |
href | string |
Use for external links only. The target value is sent as empty. It cannot be used with child connections. |
children | array |
Used only for sublinks to the hierarchical menu for the sidebar. Cannot be used with link or href. |
expanded | boolean |
Shows Children links as expanded by default. It only affects links that are children. |
heading | string |
It just turns the link into a section label title for the sidebar menu. All other features within it are disabled. |
divider | boolean |
It turns the link into a separator for the sidebar menu only. All other features within it are disabled. |