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="getNavbarKey" color="primary" density="compact" elevation="1" :header-menu="getHeaderMenu" sidebar-color="white">
<template v-slot:navbar-logo>
<div class="text-center mt-12 mb-5 mr-6 text-primary" style="font-size: 26px;">
Logo
</div>
</template>
<template v-slot:profile>
<v-menu offset-y>
<template v-slot:activator="{ props }">
<v-btn icon small v-bind="props" class="mr-1">
<div v-if="avatarExists" style="float:left;">
<v-avatar size="24px">
<v-img :src="getAvatar" alt="Avatar"></v-img>
</v-avatar>
</div>
<div v-else style="float:left;">
<v-icon>mdi-account-circle</v-icon>
</div>
</v-btn>
</template>
<v-card min-width="300">
<v-list nav>
<v-list-item class="mb-2 mt-2" 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 class="mt-2">
<v-card-text style="padding:0px;">
<v-list-item v-for="(item, index) in getProfileMenu" :key="index" link :to="item.link" logout : null>
<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>
</v-menu>
</template>
</va-app-bar>
</template>
<template>
<va-breadcrumbs></va-breadcrumbs>
</template>
<template>
<va-aside></va-aside>
</template>
<template>
<va-footer :key="getCurrentLocale" :menu="getFooterMenu">
<template v-slot:left>
<languageswitcher></languageswitcher>
</template>
<template v-slot:right>
<span style="font-size:13px">© 2024</span>
</template>
</va-footer>
</template>
</va-layout>
</v-app>
</template>
<script>
import isEmpty from "lodash/isEmpty"
import { useDisplay } from "vuetify";
import Trans from "@/i18n/translation";
import LanguageSwitcher from "@/components/LanguageSwitcher.vue";
import { storeToRefs } from 'pinia'
import useAuth from "olobase-admin/src/store/auth";
export default {
name: "App",
inject: [],
components: { LanguageSwitcher },
setup() {
const { lgAndUp } = useDisplay();
return { lgAndUp };
},
data() {
return {
avatar: null,
avatarExists: false,
email: null,
fullname: null,
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.$store.getModule("auth").checkAuth();
if (! this.authenticatedUser) {
this.$router.push({name: "login"});
} else {
this.email = this.$store.getModule("auth").getEmail;
this.fullname = this.$store.getModule("auth").getFullname;
//
// 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 });
}
/**
* Check avatar
*/
let base64Image = this.$store.getModule("auth").getAvatar;
if (base64Image == "undefined" || base64Image == "null" || isEmpty(base64Image)) {
this.avatar = this.$admin.getConfig().avatar.base64; // default avatar image
this.avatarExists = false;
} else {
this.avatarExists = true;
this.avatar = base64Image;
}
},
computed: {
getNavbarKey() {
return this.$store.navbarKey + '_' + this.$store.getLocale;
},
getCurrentLocale() {
const { locale } = storeToRefs(this.$store);
return locale;
},
getAvatar() {
return this.avatar;
},
getEmail() {
return this.email;
},
getFullname() {
return this.fullname;
},
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 []
}
},
methods: {
logout() {
this.$store.getModule("auth").logout();
this.$router.push({ name: "login" });
},
},
};
</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. |