4
4
<nav class =" help-menu-section" role =" menubar" >
5
5
<button
6
6
v-for =" menuItem in menuItems"
7
+ v-show =" menuItem.visible !== false"
7
8
:key =" menuItem.key"
8
9
type =" button"
9
10
class =" help-menu-item"
29
30
@mouseenter =" onSubmenuHover"
30
31
@mouseleave =" onSubmenuLeave"
31
32
>
32
- <template v-for =" submenuItem in submenuItems " :key =" submenuItem .key " >
33
- <div v-if =" submenuItem.type === 'divider'" class =" submenu-divider" />
33
+ <template
34
+ v-for =" submenuItem in moreMenuItem ?.items "
35
+ :key =" submenuItem .key "
36
+ >
37
+ <div
38
+ v-if =" submenuItem.type === 'divider'"
39
+ v-show =" submenuItem.visible !== false"
40
+ class =" submenu-divider"
41
+ />
34
42
<button
35
43
v-else
44
+ v-show =" submenuItem.visible !== false"
36
45
type =" button"
37
46
class =" help-menu-item submenu-item"
38
- :class =" { disabled: submenuItem.disabled }"
39
- :disabled =" submenuItem.disabled"
40
47
role =" menuitem"
41
48
@click =" submenuItem.action"
42
49
>
@@ -117,32 +124,28 @@ import { type CSSProperties, computed, nextTick, onMounted, ref } from 'vue'
117
124
import { useI18n } from ' vue-i18n'
118
125
119
126
import { type ReleaseNote } from ' @/services/releaseService'
127
+ import { useCommandStore } from ' @/stores/commandStore'
120
128
import { useReleaseStore } from ' @/stores/releaseStore'
121
129
import { electronAPI , isElectron } from ' @/utils/envUtil'
122
130
import { formatVersionAnchor } from ' @/utils/formatUtil'
123
131
124
132
// Types
125
133
interface MenuItem {
126
134
key: string
127
- icon: string
128
- label: string
129
- action: () => void
130
- }
131
-
132
- interface SubmenuItem {
133
- key: string
134
- type? : ' item' | ' divider'
135
+ icon? : string
135
136
label? : string
136
137
action? : () => void
137
- disabled? : boolean
138
+ visible? : boolean
139
+ type? : ' item' | ' divider'
140
+ items? : MenuItem []
138
141
}
139
142
140
143
// Constants
141
144
const EXTERNAL_LINKS = {
142
145
DOCS: ' https://docs.comfy.org/' ,
143
146
DISCORD: ' https://www.comfy.org/discord' ,
144
147
GITHUB: ' https://github.com/comfyanonymous/ComfyUI' ,
145
- DESKTOP_GUIDE: ' https://docs.comfy.org/installation/desktop ' ,
148
+ DESKTOP_GUIDE: ' https://comfyorg.notion.site/ ' ,
146
149
UPDATE_GUIDE: ' https://docs.comfy.org/installation/update_comfyui'
147
150
} as const
148
151
@@ -164,6 +167,12 @@ const SUBMENU_CONFIG = {
164
167
// Composables
165
168
const { t, locale } = useI18n ()
166
169
const releaseStore = useReleaseStore ()
170
+ const commandStore = useCommandStore ()
171
+
172
+ // Emits
173
+ const emit = defineEmits <{
174
+ close: []
175
+ }>()
167
176
168
177
// State
169
178
const isSubmenuVisible = ref (false )
@@ -174,66 +183,99 @@ let hoverTimeout: number | null = null
174
183
// Computed
175
184
const hasReleases = computed (() => releaseStore .releases .length > 0 )
176
185
177
- const menuItems = computed <MenuItem []>(() => [
178
- {
179
- key: ' docs' ,
180
- icon: ' pi pi-book' ,
181
- label: t (' helpCenter.docs' ),
182
- action : () => openExternalLink (EXTERNAL_LINKS .DOCS )
183
- },
184
- {
185
- key: ' discord' ,
186
- icon: ' pi pi-discord' ,
187
- label: ' Discord' ,
188
- action : () => openExternalLink (EXTERNAL_LINKS .DISCORD )
189
- },
190
- {
191
- key: ' github' ,
192
- icon: ' pi pi-github' ,
193
- label: t (' helpCenter.github' ),
194
- action : () => openExternalLink (EXTERNAL_LINKS .GITHUB )
195
- },
196
- {
197
- key: ' help' ,
198
- icon: ' pi pi-question-circle' ,
199
- label: t (' helpCenter.helpFeedback' ),
200
- action : () => openExternalLink (EXTERNAL_LINKS .DISCORD )
201
- },
202
- {
203
- key: ' more' ,
204
- icon: ' ' ,
205
- label: t (' helpCenter.more' ),
206
- action : () => {} // No action for more item
207
- }
208
- ])
209
-
210
- const submenuItems = computed <SubmenuItem []>(() => [
211
- {
212
- key: ' desktop-guide' ,
213
- type: ' item' ,
214
- label: t (' helpCenter.desktopUserGuide' ),
215
- action : () => openExternalLink (EXTERNAL_LINKS .DESKTOP_GUIDE ),
216
- disabled: false
217
- },
218
- {
219
- key: ' dev-tools' ,
220
- type: ' item' ,
221
- label: t (' helpCenter.openDevTools' ),
222
- action: openDevTools ,
223
- disabled: ! isElectron ()
224
- },
225
- {
226
- key: ' divider-1' ,
227
- type: ' divider'
228
- },
229
- {
230
- key: ' reinstall' ,
231
- type: ' item' ,
232
- label: t (' helpCenter.reinstall' ),
233
- action: onReinstall ,
234
- disabled: ! isElectron ()
235
- }
236
- ])
186
+ const moreMenuItem = computed (() =>
187
+ menuItems .value .find ((item ) => item .key === ' more' )
188
+ )
189
+
190
+ const menuItems = computed <MenuItem []>(() => {
191
+ const moreItems: MenuItem [] = [
192
+ {
193
+ key: ' desktop-guide' ,
194
+ type: ' item' ,
195
+ label: t (' helpCenter.desktopUserGuide' ),
196
+ action : () => {
197
+ openExternalLink (EXTERNAL_LINKS .DESKTOP_GUIDE )
198
+ emit (' close' )
199
+ }
200
+ },
201
+ {
202
+ key: ' dev-tools' ,
203
+ type: ' item' ,
204
+ label: t (' helpCenter.openDevTools' ),
205
+ visible: isElectron (),
206
+ action : () => {
207
+ openDevTools ()
208
+ emit (' close' )
209
+ }
210
+ },
211
+ {
212
+ key: ' divider-1' ,
213
+ type: ' divider' ,
214
+ visible: isElectron ()
215
+ },
216
+ {
217
+ key: ' reinstall' ,
218
+ type: ' item' ,
219
+ label: t (' helpCenter.reinstall' ),
220
+ visible: isElectron (),
221
+ action : () => {
222
+ onReinstall ()
223
+ emit (' close' )
224
+ }
225
+ }
226
+ ]
227
+
228
+ return [
229
+ {
230
+ key: ' docs' ,
231
+ type: ' item' ,
232
+ icon: ' pi pi-book' ,
233
+ label: t (' helpCenter.docs' ),
234
+ action : () => {
235
+ openExternalLink (EXTERNAL_LINKS .DOCS )
236
+ emit (' close' )
237
+ }
238
+ },
239
+ {
240
+ key: ' discord' ,
241
+ type: ' item' ,
242
+ icon: ' pi pi-discord' ,
243
+ label: ' Discord' ,
244
+ action : () => {
245
+ openExternalLink (EXTERNAL_LINKS .DISCORD )
246
+ emit (' close' )
247
+ }
248
+ },
249
+ {
250
+ key: ' github' ,
251
+ type: ' item' ,
252
+ icon: ' pi pi-github' ,
253
+ label: t (' helpCenter.github' ),
254
+ action : () => {
255
+ openExternalLink (EXTERNAL_LINKS .GITHUB )
256
+ emit (' close' )
257
+ }
258
+ },
259
+ {
260
+ key: ' help' ,
261
+ type: ' item' ,
262
+ icon: ' pi pi-question-circle' ,
263
+ label: t (' helpCenter.helpFeedback' ),
264
+ action : () => {
265
+ void commandStore .execute (' Comfy.Feedback' )
266
+ emit (' close' )
267
+ }
268
+ },
269
+ {
270
+ key: ' more' ,
271
+ type: ' item' ,
272
+ icon: ' ' ,
273
+ label: t (' helpCenter.more' ),
274
+ action : () => {}, // No action for more item
275
+ items: moreItems
276
+ }
277
+ ]
278
+ })
237
279
238
280
// Utility Functions
239
281
const openExternalLink = (url : string ): void => {
@@ -251,8 +293,12 @@ const calculateSubmenuPosition = (button: HTMLElement): CSSProperties => {
251
293
const rect = button .getBoundingClientRect ()
252
294
const submenuWidth = 210 // Width defined in CSS
253
295
254
- // Get actual submenu height if available, otherwise use estimated height
255
- const submenuHeight = submenuRef .value ?.offsetHeight || 120 // More realistic estimate for 2 items
296
+ // Get actual submenu height if available, otherwise estimate based on visible item count
297
+ const visibleItemCount =
298
+ moreMenuItem .value ?.items ?.filter ((item ) => item .visible !== false )
299
+ .length || 0
300
+ const estimatedHeight = visibleItemCount * 48 + 16 // ~48px per item + padding
301
+ const submenuHeight = submenuRef .value ?.offsetHeight || estimatedHeight
256
302
257
303
// Get viewport dimensions
258
304
const viewportWidth = window .innerWidth
@@ -282,6 +328,8 @@ const calculateSubmenuPosition = (button: HTMLElement): CSSProperties => {
282
328
top = SUBMENU_CONFIG .OFFSET_PX
283
329
}
284
330
331
+ top -= 8
332
+
285
333
return {
286
334
position: ' fixed' ,
287
335
top: ` ${top }px ` ,
@@ -328,7 +376,13 @@ const onMenuItemHover = async (
328
376
key : string ,
329
377
event : MouseEvent
330
378
): Promise <void > => {
331
- if (key !== ' more' ) return
379
+ if (key !== ' more' || ! moreMenuItem .value ?.items ) return
380
+
381
+ // Don't show submenu if all items are hidden
382
+ const hasVisibleItems = moreMenuItem .value .items .some (
383
+ (item ) => item .visible !== false
384
+ )
385
+ if (! hasVisibleItems ) return
332
386
333
387
clearHoverTimeout ()
334
388
@@ -380,10 +434,12 @@ const onReleaseClick = (release: ReleaseNote): void => {
380
434
const versionAnchor = formatVersionAnchor (release .version )
381
435
const changelogUrl = ` ${getChangelogUrl ()}#${versionAnchor } `
382
436
openExternalLink (changelogUrl )
437
+ emit (' close' )
383
438
}
384
439
385
440
const onUpdate = (_ : ReleaseNote ): void => {
386
441
openExternalLink (EXTERNAL_LINKS .UPDATE_GUIDE )
442
+ emit (' close' )
387
443
}
388
444
389
445
// Generate language-aware changelog URL
@@ -551,13 +607,6 @@ onMounted(async () => {
551
607
box-shadow : none ;
552
608
}
553
609
554
- .submenu-item.disabled ,
555
- .submenu-item :disabled {
556
- opacity : 0.5 ;
557
- cursor : not-allowed ;
558
- pointer-events : none ;
559
- }
560
-
561
610
.submenu-divider {
562
611
height : 1px ;
563
612
background : #3e3e3e ;
0 commit comments