Files
monisuo/monisuo-admin/src/components/app-sidebar/nav-main.vue
2026-03-22 14:03:51 +08:00

109 lines
3.8 KiB
Vue

<script lang="ts" setup>
import {
ChevronRight,
} from 'lucide-vue-next'
import { useSidebar } from '@/components/ui/sidebar'
import type { NavGroup, NavItem } from './types'
const { navMain } = defineProps<{
navMain: NavGroup[]
}>()
const route = useRoute()
const { state, isMobile } = useSidebar()
function isCollapsed(menu: NavItem): boolean {
const pathname = route.path
navMain.forEach((group) => {
group.items.forEach((item) => {
if (item.url === pathname) {
return true
}
})
})
return !!menu.items?.some(item => item.url === pathname)
}
function isActive(menu: NavItem): boolean {
const pathname = route.path
if (menu.url) {
return pathname === menu.url
}
return !!menu.items?.some(item => item.url === pathname)
}
</script>
<template>
<UiSidebarGroup v-for="group in navMain" :key="group.title">
<UiSidebarGroupLabel>{{ group.title }}</UiSidebarGroupLabel>
<UiSidebarMenu>
<template v-for="menu in group.items" :key="menu.title">
<UiSidebarMenuItem v-if="!menu.items">
<UiSidebarMenuButton as-child :is-active="isActive(menu)" :tooltip="menu.title">
<router-link :to="menu.url">
<component :is="menu.icon" />
<span>{{ menu.title }}</span>
</router-link>
</UiSidebarMenuButton>
</UiSidebarMenuItem>
<UiSidebarMenuItem v-else>
<!-- sidebar expanded -->
<UiCollapsible
v-if="state !== 'collapsed' || isMobile"
as-child :default-open="isCollapsed(menu)"
class="group/collapsible"
>
<UiSidebarMenuItem>
<UiCollapsibleTrigger as-child>
<UiSidebarMenuButton :tooltip="menu.title">
<component :is="menu.icon" v-if="menu.icon" />
<span>{{ menu.title }}</span>
<ChevronRight
class="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90"
/>
</UiSidebarMenuButton>
</UiCollapsibleTrigger>
</UiSidebarMenuItem>
<UiCollapsibleContent>
<UiSidebarMenuSub>
<UiSidebarMenuSubItem v-for="subItem in menu.items" :key="subItem.title">
<UiSidebarMenuSubButton as-child :is-active="isActive(subItem as NavItem)">
<router-link :to="subItem?.url || '/'">
<component :is="subItem.icon" v-if="subItem.icon" />
<span>{{ subItem.title }}</span>
</router-link>
</UiSidebarMenuSubButton>
</UiSidebarMenuSubItem>
</UiSidebarMenuSub>
</UiCollapsibleContent>
</UiCollapsible>
<!-- sidebar collapsed -->
<UiDropdownMenu v-else>
<UiDropdownMenuTrigger as-child>
<UiSidebarMenuButton :tooltip="menu.title">
<component :is="menu.icon" v-if="menu.icon" />
<span>{{ menu.title }}</span>
</UiSidebarMenuButton>
</UiDropdownMenuTrigger>
<UiDropdownMenuContent align="start" side="right">
<UiDropdownMenuLabel>{{ menu.title }}</UiDropdownMenuLabel>
<UiDropdownMenuSeparator />
<UiDropdownMenuItem v-for="subItem in menu.items" :key="subItem.title" as-child>
<router-link :to="subItem?.url || '/'">
<component :is="subItem.icon" v-if="subItem.icon" />
<span>{{ subItem.title }}</span>
</router-link>
</UiDropdownMenuItem>
</UiDropdownMenuContent>
</UiDropdownMenu>
</UiSidebarMenuItem>
</template>
</UiSidebarMenu>
</UiSidebarGroup>
</template>