mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-03 14:54:37 +00:00
feat: Enhance navigation with collapsible groups and improved NavTitle component
This commit is contained in:
@@ -1,13 +1,55 @@
|
||||
<template>
|
||||
<h3
|
||||
class="m-0 px-3 py-0 pt-5 text-xs font-bold uppercase text-neutral-400 dark-theme:text-neutral-400"
|
||||
<div
|
||||
:class="
|
||||
cn(
|
||||
'flex items-center justify-between m-0 px-3 py-0 pt-5',
|
||||
collapsible && 'cursor-pointer select-none'
|
||||
)
|
||||
"
|
||||
@click="collapsible && toggleCollapse()"
|
||||
>
|
||||
{{ title }}
|
||||
</h3>
|
||||
<h3
|
||||
class="text-xs font-bold uppercase text-neutral-400 dark-theme:text-neutral-400"
|
||||
>
|
||||
{{ title }}
|
||||
</h3>
|
||||
<i
|
||||
v-if="collapsible"
|
||||
:class="
|
||||
cn(
|
||||
'pi transition-transform duration-200 text-xs text-neutral-400 dark-theme:text-neutral-400',
|
||||
isCollapsed ? 'pi-chevron-right' : 'pi-chevron-down'
|
||||
)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { title } = defineProps<{
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
|
||||
const {
|
||||
title,
|
||||
modelValue = false,
|
||||
collapsible = false
|
||||
} = defineProps<{
|
||||
title: string
|
||||
modelValue?: boolean
|
||||
collapsible?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: boolean]
|
||||
}>()
|
||||
|
||||
const isCollapsed = computed({
|
||||
get: () => modelValue,
|
||||
set: (value: boolean) => emit('update:modelValue', value)
|
||||
})
|
||||
|
||||
const toggleCollapse = () => {
|
||||
isCollapsed.value = !isCollapsed.value
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -10,16 +10,22 @@
|
||||
<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>
|
||||
<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"
|
||||
:active="activeItem === subItem.id"
|
||||
@click="activeItem = subItem.id"
|
||||
>
|
||||
{{ subItem.label }}
|
||||
</NavItem>
|
||||
</template>
|
||||
</div>
|
||||
<div v-else class="flex flex-col gap-2">
|
||||
<NavItem
|
||||
@@ -36,7 +42,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import NavItem from '@/components/widget/nav/NavItem.vue'
|
||||
import NavTitle from '@/components/widget/nav/NavTitle.vue'
|
||||
@@ -53,6 +59,9 @@ 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
|
||||
|
||||
@@ -8,4 +8,5 @@ export interface NavGroupData {
|
||||
title: string
|
||||
items: NavItemData[]
|
||||
icon?: string
|
||||
collapsible?: boolean
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user