mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
## Summary
Adds optional badge support to the `NavItem` component and `NavItemData`
interface, enabling navigation items in the left sidebar of the Asset
Browser Modal to display counts or status indicators.
## Changes
- **`src/types/navTypes.ts`**: Added optional `badge?: string | number`
property to `NavItemData` interface
- **`src/components/widget/nav/NavItem.vue`**: Added `StatusBadge`
rendering when `badge` prop is provided
- **`src/components/widget/panel/LeftSidePanel.vue`**: Wired `badge`
prop from `NavItemData` to `NavItem` for both grouped and ungrouped
items
## Usage
```ts
const navItem: NavItemData = {
id: 'assets',
label: 'Assets',
icon: 'pi pi-folder',
badge: 5 // Optional - displays count badge
}
```
## Related
- Builds on #8170 which added queue badge functionality
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8207-feat-add-badge-support-to-NavItem-component-2ef6d73d365081669f86fe2fc618e87f)
by [Unito](https://www.unito.io)
91 lines
2.4 KiB
Vue
91 lines
2.4 KiB
Vue
<template>
|
|
<div class="flex h-full w-full flex-col bg-modal-panel-background">
|
|
<PanelHeader>
|
|
<template #icon>
|
|
<slot name="header-icon"></slot>
|
|
</template>
|
|
<slot name="header-title"></slot>
|
|
</PanelHeader>
|
|
|
|
<nav
|
|
class="flex scrollbar-hide flex-1 flex-col gap-1 overflow-y-auto px-3 py-4"
|
|
>
|
|
<template v-for="(item, index) in navItems" :key="index">
|
|
<div v-if="'items' in item" class="flex flex-col gap-2">
|
|
<NavTitle
|
|
v-model="collapsedGroups[item.title]"
|
|
:title="item.title"
|
|
:collapsible="item.collapsible"
|
|
/>
|
|
<template v-if="!item.collapsible || !collapsedGroups[item.title]">
|
|
<NavItem
|
|
v-for="subItem in item.items"
|
|
:key="subItem.id"
|
|
:icon="subItem.icon"
|
|
:badge="subItem.badge"
|
|
:active="activeItem === subItem.id"
|
|
@click="activeItem = subItem.id"
|
|
>
|
|
{{ subItem.label }}
|
|
</NavItem>
|
|
</template>
|
|
</div>
|
|
<div v-else class="flex flex-col gap-2">
|
|
<NavItem
|
|
:icon="item.icon"
|
|
:badge="item.badge"
|
|
:active="activeItem === item.id"
|
|
@click="activeItem = item.id"
|
|
>
|
|
{{ item.label }}
|
|
</NavItem>
|
|
</div>
|
|
</template>
|
|
</nav>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, ref } from 'vue'
|
|
|
|
import NavItem from '@/components/widget/nav/NavItem.vue'
|
|
import NavTitle from '@/components/widget/nav/NavTitle.vue'
|
|
import type { NavGroupData, NavItemData } from '@/types/navTypes'
|
|
|
|
import PanelHeader from './PanelHeader.vue'
|
|
|
|
const { navItems = [], modelValue } = defineProps<{
|
|
navItems?: (NavItemData | NavGroupData)[]
|
|
modelValue?: string | null
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
'update:modelValue': [value: string | null]
|
|
}>()
|
|
|
|
// Track collapsed state for each group
|
|
const collapsedGroups = ref<Record<string, boolean>>({})
|
|
|
|
const getFirstItemId = () => {
|
|
if (!navItems || navItems.length === 0) {
|
|
return null
|
|
}
|
|
|
|
const firstEntry = navItems[0]
|
|
|
|
if ('items' in firstEntry && firstEntry.items.length > 0) {
|
|
return firstEntry.items[0].id
|
|
}
|
|
if ('id' in firstEntry) {
|
|
return firstEntry.id
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
const activeItem = computed({
|
|
get: () => modelValue ?? getFirstItemId(),
|
|
set: (value: string | null) => emit('update:modelValue', value)
|
|
})
|
|
</script>
|