62 lines
2.6 KiB
Vue
62 lines
2.6 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from "vue";
|
|
import LayoutIcon from "@/components/layout/LayoutIcon.vue";
|
|
import { getMenuIconName, visibleNavigableMenus } from "@/lib/menu-display";
|
|
import type { NavigationType } from "@/lib/layout-settings";
|
|
import type { AdminMenu } from "@/types";
|
|
|
|
type SidebarMenu = AdminMenu & { isVisible?: boolean };
|
|
|
|
const props = withDefaults(defineProps<{
|
|
menu: SidebarMenu;
|
|
basePath?: string;
|
|
collapsed?: boolean;
|
|
navigationType?: NavigationType;
|
|
}>(), {
|
|
basePath: "",
|
|
collapsed: false,
|
|
navigationType: "left",
|
|
});
|
|
|
|
function resolveMenuPath(basePath: string, menuPath: string | null | undefined): string | undefined {
|
|
if (!menuPath) return undefined;
|
|
if (menuPath.startsWith("/")) return menuPath;
|
|
|
|
const normalizedBasePath = basePath.replace(/^\/+|\/+$/g, "");
|
|
const normalizedMenuPath = menuPath.trim().replace(/^\/+/, "");
|
|
if (!normalizedMenuPath) return normalizedBasePath ? `/${normalizedBasePath}` : undefined;
|
|
|
|
return `/${[normalizedBasePath, normalizedMenuPath].filter(Boolean).join("/")}`.replace(/\/{2,}/g, "/");
|
|
}
|
|
|
|
const resolvedPath = computed(() => resolveMenuPath(props.basePath, props.menu.path));
|
|
const visibleChildren = computed(() => visibleNavigableMenus(props.menu.children ?? []));
|
|
const childBasePath = computed(() => resolvedPath.value || props.basePath || "/");
|
|
</script>
|
|
|
|
<template>
|
|
<el-sub-menu v-if="menu.type === 'directory' && visibleChildren.length > 0" :index="resolvedPath || menu.id"
|
|
:aria-label="menu.name" :class="['sidebar-item', `sidebar-item--${navigationType}`]">
|
|
<template #title>
|
|
<el-tooltip :content="menu.name" :disabled="!collapsed" placement="right">
|
|
<div class="sidebar-item__content">
|
|
<LayoutIcon :name="getMenuIconName(menu)" :title="collapsed ? menu.name : undefined" size="18" />
|
|
<span v-if="!collapsed" class="sidebar-item__label">{{ menu.name }}</span>
|
|
</div>
|
|
</el-tooltip>
|
|
</template>
|
|
<SidebarItem v-for="child in visibleChildren" :key="child.id" :menu="child" :base-path="childBasePath"
|
|
:collapsed="false" :navigation-type="navigationType" />
|
|
</el-sub-menu>
|
|
|
|
<el-menu-item v-else-if="menu.type === 'page' && resolvedPath" :index="resolvedPath" :aria-label="menu.name"
|
|
:class="['sidebar-item', `sidebar-item--${navigationType}`]">
|
|
<el-tooltip :content="menu.name" :disabled="!collapsed" placement="right">
|
|
<div class="sidebar-item__content">
|
|
<LayoutIcon :name="getMenuIconName(menu)" :title="collapsed ? menu.name : undefined" size="18" />
|
|
<span v-if="!collapsed" class="sidebar-item__label">{{ menu.name }}</span>
|
|
</div>
|
|
</el-tooltip>
|
|
</el-menu-item>
|
|
</template>
|