146 lines
3.7 KiB
Vue

<script setup>
import { useLayoutStore } from "~/stores/layout";
import { useWindowSize } from "vue-window-size";
import RSChildItem from "~/components/layouts/sidemenu/ItemChild.vue";
import { useUserStore } from "~/stores/user";
const layoutStore = useLayoutStore();
const mobileWidth = layoutStore.mobileWidth;
const { width } = useWindowSize();
const user = useUserStore();
const route = useRoute();
const props = defineProps({
items: {
type: Array,
required: true,
},
indent: {
type: Number,
default: 0.5,
},
});
const emit = defineEmits(["openMenu"]);
const indent = ref(props.indent);
const menuItem = props.items ? props.items : [];
const username = user.username;
const roles = user.roles;
// validate userExist on meta.auth.user
function userExist(item) {
if (item.meta?.auth?.user) {
if (item.meta?.auth?.user.includes(username)) {
return true;
} else {
return false;
}
}
return true;
}
// validate roleExist on meta.auth.role
function roleExist(item) {
if (item.meta?.auth?.role) {
if (item.meta?.auth?.role.some((r) => roles.includes(r))) {
return true;
} else {
return false;
}
}
return true;
}
// Toggle Open/Close menu
function openMenu(event) {
emit("openMenu", event);
}
// Active menu
function activeMenu(routePath) {
return route.path == routePath
? `bg-[rgb(var(--color-primary))] font-normal text-white active-menu`
: `font-light text-white/90 md:transition-all md:duration-200 hover:md:ml-2`;
}
function toggleMenu() {
document.querySelector(".v-layout").classList.toggle("menu-hide");
document.getElementsByClassName("menu-overlay")[0].classList.toggle("hide");
}
function navigationPage(path, external) {
if (width.value <= mobileWidth) toggleMenu();
navigateTo(path, {
external: external,
});
}
const indentStyle = computed(() => {
return { "background-color": `rgba(var(--sidebar-menu), ${indent.value})` };
});
</script>
<template>
<ul
class="menu-content hide transition-all duration-300"
:style="indentStyle"
>
<li
v-for="(item, index) in menuItem"
:key="index"
@click.stop="
item.child !== undefined || (item.child && item.child.length !== 0)
? openMenu($event)
: ''
"
>
<div
v-if="
!item.meta || !item.meta?.auth || (userExist(item) && roleExist(item))
"
class="navigation-item-wrapper"
>
<NuxtLink
v-if="
item.child === undefined || (item.child && item.child.length === 0)
"
class="flex items-center px-6 py-3 cursor-pointer"
@click="navigationPage(item.path, item.external)"
:class="activeMenu(item.path)"
>
<Icon v-if="item.icon" :name="item.icon" size="18"></Icon>
<span class="mx-4 font-normal">{{ item.title }}</span>
<Icon
v-if="item.child && item.child.length > 0"
class="ml-auto side-menu-arrow"
name="material-symbols:chevron-right-rounded"
size="18"
></Icon>
</NuxtLink>
<a
v-else
class="flex items-center px-6 py-3 rounded-lg cursor-pointer"
:class="activeMenu(item.path)"
>
<span class="mx-3 font-normal">{{ item.title }}</span>
<Icon
v-if="item.child && item.child.length > 0"
class="ml-auto side-menu-arrow"
name="material-symbols:chevron-right-rounded"
size="18"
></Icon>
</a>
<RSChildItem
v-if="item.child"
:items="item.child"
:indent="indent + 0.1"
@openMenu="openMenu"
@activeMenu="activeMenu"
></RSChildItem>
</div>
</li>
</ul>
</template>