From 2a9dba536430b026a79e0ad890b9a9912d149ebb Mon Sep 17 00:00:00 2001 From: Michel EDIGHOFFER Date: Mon, 24 Nov 2025 01:19:48 +0100 Subject: [PATCH 1/3] feat(NavigationMenu): add nested children support for vertical collapsed menu --- .../app/pages/components/navigation-menu.vue | 51 ++++++++++++- src/runtime/components/NavigationMenu.vue | 71 +++++++++++-------- 2 files changed, 89 insertions(+), 33 deletions(-) diff --git a/playgrounds/nuxt/app/pages/components/navigation-menu.vue b/playgrounds/nuxt/app/pages/components/navigation-menu.vue index 463f66c86d..b50e0d47ed 100644 --- a/playgrounds/nuxt/app/pages/components/navigation-menu.vue +++ b/playgrounds/nuxt/app/pages/components/navigation-menu.vue @@ -14,9 +14,9 @@ const attrs = reactive({ const highlight = ref(true) const highlightColor = ref() -const orientation = ref('horizontal' as keyof typeof theme.variants.orientation) +const orientation = ref('vertical' as keyof typeof theme.variants.orientation) const contentOrientation = ref('horizontal' as keyof typeof theme.variants.contentOrientation) -const collapsed = ref(false) +const collapsed = ref(true) const arrow = ref(false) const items = [ @@ -50,12 +50,57 @@ const items = [ to: '/components/navigation-menu', type: 'trigger', active: true, + popover: { + mode: 'click' + }, defaultOpen: true, children: [{ label: 'Link', icon: 'i-lucide-link', description: 'Use NuxtLink with superpowers.', - to: '/components/link' + to: '/components/link', + children: [{ + label: 'Button', + icon: 'i-lucide-square', + description: 'Display a modal dialog overlay for important content.', + to: '/components/modal' + }, { + label: 'Pagination', + icon: 'i-lucide-parking-meter', + description: 'Display a list of pages.', + to: '/components/pagination' + }, { + label: 'Popover', + icon: 'i-lucide-message-circle', + description: 'Display a non-modal dialog that floats around a trigger element.', + to: '/components/popover', + children: [{ + label: 'Button', + icon: 'i-lucide-square', + description: 'Display a modal dialog overlay for important content.', + to: '/components/modal' + }, { + label: 'Pagination', + icon: 'i-lucide-parking-meter', + description: 'Display a list of pages.', + to: '/components/pagination' + }, { + label: 'Popover', + icon: 'i-lucide-message-circle', + description: 'Display a non-modal dialog that floats around a trigger element.', + to: '/components/popover' + }, { + label: 'Progress', + icon: 'i-lucide-loader', + description: 'Show a horizontal bar to indicate task progression.', + to: '/components/progress' + }] + }, { + label: 'Progress', + icon: 'i-lucide-loader', + description: 'Show a horizontal bar to indicate task progression.', + to: '/components/progress' + }] }, { label: 'Modal', icon: 'i-lucide-square', diff --git a/src/runtime/components/NavigationMenu.vue b/src/runtime/components/NavigationMenu.vue index f74aa55cd1..7f83f5d1ae 100644 --- a/src/runtime/components/NavigationMenu.vue +++ b/src/runtime/components/NavigationMenu.vue @@ -260,12 +260,13 @@ const contentProps = toRef(() => props.content) const tooltipProps = toRef(() => defu(typeof props.tooltip === 'boolean' ? {} : props.tooltip, { delayDuration: 0, content: { side: 'right' } }) as TooltipProps) const popoverProps = toRef(() => defu(typeof props.popover === 'boolean' ? {} : props.popover, { mode: 'hover', content: { side: 'right', align: 'start', alignOffset: 2 } }) as PopoverProps) -const [DefineLinkTemplate, ReuseLinkTemplate] = createReusableTemplate<{ item: NavigationMenuItem, index: number, active?: boolean }>() -const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate<{ item: NavigationMenuItem, index: number, level?: number }>({ +const [DefineLinkTemplate, ReuseLinkTemplate] = createReusableTemplate<{ item: NavigationMenuItem, index: number, active?: boolean, withLabel?: boolean }>() +const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate<{ item: NavigationMenuItem, index: number, level?: number, withLabel?: boolean }>({ props: { item: Object, index: Number, - level: Number + level: Number, + withLabel: Boolean } }) @@ -300,7 +301,7 @@ function getAccordionDefaultValue(list: NavigationMenuItem[], level = 0) {