mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 10:59:53 +00:00
* feat: add dynamic icon support for NavItem components - Created NavIcon component with switch-case based icon rendering - Added iconName prop to NavItem and NavItemData interface - Updated LeftSidePanel to pass icon names to nav items - Added sample icons to SampleModelSelector navigation (download, tag, layers, grid) - Uses i-lucide syntax without imports for better tree-shaking 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * test: add Storybook stories for navigation components - Add NavIcon.stories.ts with interactive icon selector and all icons gallery - Add NavItem.stories.ts with text customization and interactive list examples - Add LeftSidePanel.stories.ts with various navigation configurations - Remove old Navigation.stories.ts (replaced with component-specific stories) - Configure slot visibility and hide update:modelValue event in controls * refactor: simplify NavIcon component and improve type definitions * fix: add icon size specification for Lucide icons in Storybook * feature: NavItem story modified * fix: disable knip unresolved imports rule for virtual icon modules Add unresolved: 'off' to knip configuration to ignore virtual module imports from unplugin-icons (~icons/*). These are generated at build time and cannot be resolved statically. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: v-if condition added * chore: knip ignoreUnresolved added based on knip issue PR * refactor: navItem types added & deleting any type on storybook files --------- Co-authored-by: Claude <noreply@anthropic.com>
78 lines
2.0 KiB
Vue
78 lines
2.0 KiB
Vue
<template>
|
|
<div class="flex flex-col h-full w-full bg-white dark-theme:bg-zinc-800">
|
|
<PanelHeader>
|
|
<template #icon>
|
|
<slot name="header-icon"></slot>
|
|
</template>
|
|
<slot name="header-title"></slot>
|
|
</PanelHeader>
|
|
|
|
<nav class="flex-1 px-3 py-4 flex flex-col gap-1">
|
|
<template v-for="(item, index) in navItems" :key="index">
|
|
<div v-if="'items' in item" class="flex flex-col gap-2">
|
|
<NavTitle :title="item.title" />
|
|
<NavItem
|
|
v-for="subItem in item.items"
|
|
:key="subItem.id"
|
|
:icon="subItem.icon"
|
|
:active="activeItem === subItem.id"
|
|
@click="activeItem = subItem.id"
|
|
>
|
|
{{ subItem.label }}
|
|
</NavItem>
|
|
</div>
|
|
<div v-else class="flex flex-col gap-2">
|
|
<NavItem
|
|
:icon="item.icon"
|
|
:active="activeItem === item.id"
|
|
@click="activeItem = item.id"
|
|
>
|
|
{{ item.label }}
|
|
</NavItem>
|
|
</div>
|
|
</template>
|
|
</nav>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
|
|
import NavItem from '@/components/widget/nav/NavItem.vue'
|
|
import NavTitle from '@/components/widget/nav/NavTitle.vue'
|
|
import { 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]
|
|
}>()
|
|
|
|
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>
|