mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-26 17:54:14 +00:00
[System Pop Up] Improve help center menu behavior and Electron compatibility (#4330)
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
<nav class="help-menu-section" role="menubar">
|
||||
<button
|
||||
v-for="menuItem in menuItems"
|
||||
v-show="menuItem.visible !== false"
|
||||
:key="menuItem.key"
|
||||
type="button"
|
||||
class="help-menu-item"
|
||||
@@ -29,14 +30,20 @@
|
||||
@mouseenter="onSubmenuHover"
|
||||
@mouseleave="onSubmenuLeave"
|
||||
>
|
||||
<template v-for="submenuItem in submenuItems" :key="submenuItem.key">
|
||||
<div v-if="submenuItem.type === 'divider'" class="submenu-divider" />
|
||||
<template
|
||||
v-for="submenuItem in moreMenuItem?.items"
|
||||
:key="submenuItem.key"
|
||||
>
|
||||
<div
|
||||
v-if="submenuItem.type === 'divider'"
|
||||
v-show="submenuItem.visible !== false"
|
||||
class="submenu-divider"
|
||||
/>
|
||||
<button
|
||||
v-else
|
||||
v-show="submenuItem.visible !== false"
|
||||
type="button"
|
||||
class="help-menu-item submenu-item"
|
||||
:class="{ disabled: submenuItem.disabled }"
|
||||
:disabled="submenuItem.disabled"
|
||||
role="menuitem"
|
||||
@click="submenuItem.action"
|
||||
>
|
||||
@@ -117,6 +124,7 @@ import { type CSSProperties, computed, nextTick, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { type ReleaseNote } from '@/services/releaseService'
|
||||
import { useCommandStore } from '@/stores/commandStore'
|
||||
import { useReleaseStore } from '@/stores/releaseStore'
|
||||
import { electronAPI, isElectron } from '@/utils/envUtil'
|
||||
import { formatVersionAnchor } from '@/utils/formatUtil'
|
||||
@@ -124,17 +132,12 @@ import { formatVersionAnchor } from '@/utils/formatUtil'
|
||||
// Types
|
||||
interface MenuItem {
|
||||
key: string
|
||||
icon: string
|
||||
label: string
|
||||
action: () => void
|
||||
}
|
||||
|
||||
interface SubmenuItem {
|
||||
key: string
|
||||
type?: 'item' | 'divider'
|
||||
icon?: string
|
||||
label?: string
|
||||
action?: () => void
|
||||
disabled?: boolean
|
||||
visible?: boolean
|
||||
type?: 'item' | 'divider'
|
||||
items?: MenuItem[]
|
||||
}
|
||||
|
||||
// Constants
|
||||
@@ -142,7 +145,7 @@ const EXTERNAL_LINKS = {
|
||||
DOCS: 'https://docs.comfy.org/',
|
||||
DISCORD: 'https://www.comfy.org/discord',
|
||||
GITHUB: 'https://github.com/comfyanonymous/ComfyUI',
|
||||
DESKTOP_GUIDE: 'https://docs.comfy.org/installation/desktop',
|
||||
DESKTOP_GUIDE: 'https://comfyorg.notion.site/',
|
||||
UPDATE_GUIDE: 'https://docs.comfy.org/installation/update_comfyui'
|
||||
} as const
|
||||
|
||||
@@ -164,6 +167,12 @@ const SUBMENU_CONFIG = {
|
||||
// Composables
|
||||
const { t, locale } = useI18n()
|
||||
const releaseStore = useReleaseStore()
|
||||
const commandStore = useCommandStore()
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits<{
|
||||
close: []
|
||||
}>()
|
||||
|
||||
// State
|
||||
const isSubmenuVisible = ref(false)
|
||||
@@ -174,66 +183,99 @@ let hoverTimeout: number | null = null
|
||||
// Computed
|
||||
const hasReleases = computed(() => releaseStore.releases.length > 0)
|
||||
|
||||
const menuItems = computed<MenuItem[]>(() => [
|
||||
{
|
||||
key: 'docs',
|
||||
icon: 'pi pi-book',
|
||||
label: t('helpCenter.docs'),
|
||||
action: () => openExternalLink(EXTERNAL_LINKS.DOCS)
|
||||
},
|
||||
{
|
||||
key: 'discord',
|
||||
icon: 'pi pi-discord',
|
||||
label: 'Discord',
|
||||
action: () => openExternalLink(EXTERNAL_LINKS.DISCORD)
|
||||
},
|
||||
{
|
||||
key: 'github',
|
||||
icon: 'pi pi-github',
|
||||
label: t('helpCenter.github'),
|
||||
action: () => openExternalLink(EXTERNAL_LINKS.GITHUB)
|
||||
},
|
||||
{
|
||||
key: 'help',
|
||||
icon: 'pi pi-question-circle',
|
||||
label: t('helpCenter.helpFeedback'),
|
||||
action: () => openExternalLink(EXTERNAL_LINKS.DISCORD)
|
||||
},
|
||||
{
|
||||
key: 'more',
|
||||
icon: '',
|
||||
label: t('helpCenter.more'),
|
||||
action: () => {} // No action for more item
|
||||
}
|
||||
])
|
||||
const moreMenuItem = computed(() =>
|
||||
menuItems.value.find((item) => item.key === 'more')
|
||||
)
|
||||
|
||||
const submenuItems = computed<SubmenuItem[]>(() => [
|
||||
{
|
||||
key: 'desktop-guide',
|
||||
type: 'item',
|
||||
label: t('helpCenter.desktopUserGuide'),
|
||||
action: () => openExternalLink(EXTERNAL_LINKS.DESKTOP_GUIDE),
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
key: 'dev-tools',
|
||||
type: 'item',
|
||||
label: t('helpCenter.openDevTools'),
|
||||
action: openDevTools,
|
||||
disabled: !isElectron()
|
||||
},
|
||||
{
|
||||
key: 'divider-1',
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
key: 'reinstall',
|
||||
type: 'item',
|
||||
label: t('helpCenter.reinstall'),
|
||||
action: onReinstall,
|
||||
disabled: !isElectron()
|
||||
}
|
||||
])
|
||||
const menuItems = computed<MenuItem[]>(() => {
|
||||
const moreItems: MenuItem[] = [
|
||||
{
|
||||
key: 'desktop-guide',
|
||||
type: 'item',
|
||||
label: t('helpCenter.desktopUserGuide'),
|
||||
action: () => {
|
||||
openExternalLink(EXTERNAL_LINKS.DESKTOP_GUIDE)
|
||||
emit('close')
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'dev-tools',
|
||||
type: 'item',
|
||||
label: t('helpCenter.openDevTools'),
|
||||
visible: isElectron(),
|
||||
action: () => {
|
||||
openDevTools()
|
||||
emit('close')
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'divider-1',
|
||||
type: 'divider',
|
||||
visible: isElectron()
|
||||
},
|
||||
{
|
||||
key: 'reinstall',
|
||||
type: 'item',
|
||||
label: t('helpCenter.reinstall'),
|
||||
visible: isElectron(),
|
||||
action: () => {
|
||||
onReinstall()
|
||||
emit('close')
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
return [
|
||||
{
|
||||
key: 'docs',
|
||||
type: 'item',
|
||||
icon: 'pi pi-book',
|
||||
label: t('helpCenter.docs'),
|
||||
action: () => {
|
||||
openExternalLink(EXTERNAL_LINKS.DOCS)
|
||||
emit('close')
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'discord',
|
||||
type: 'item',
|
||||
icon: 'pi pi-discord',
|
||||
label: 'Discord',
|
||||
action: () => {
|
||||
openExternalLink(EXTERNAL_LINKS.DISCORD)
|
||||
emit('close')
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'github',
|
||||
type: 'item',
|
||||
icon: 'pi pi-github',
|
||||
label: t('helpCenter.github'),
|
||||
action: () => {
|
||||
openExternalLink(EXTERNAL_LINKS.GITHUB)
|
||||
emit('close')
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'help',
|
||||
type: 'item',
|
||||
icon: 'pi pi-question-circle',
|
||||
label: t('helpCenter.helpFeedback'),
|
||||
action: () => {
|
||||
void commandStore.execute('Comfy.Feedback')
|
||||
emit('close')
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'more',
|
||||
type: 'item',
|
||||
icon: '',
|
||||
label: t('helpCenter.more'),
|
||||
action: () => {}, // No action for more item
|
||||
items: moreItems
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// Utility Functions
|
||||
const openExternalLink = (url: string): void => {
|
||||
@@ -251,8 +293,12 @@ const calculateSubmenuPosition = (button: HTMLElement): CSSProperties => {
|
||||
const rect = button.getBoundingClientRect()
|
||||
const submenuWidth = 210 // Width defined in CSS
|
||||
|
||||
// Get actual submenu height if available, otherwise use estimated height
|
||||
const submenuHeight = submenuRef.value?.offsetHeight || 120 // More realistic estimate for 2 items
|
||||
// Get actual submenu height if available, otherwise estimate based on visible item count
|
||||
const visibleItemCount =
|
||||
moreMenuItem.value?.items?.filter((item) => item.visible !== false)
|
||||
.length || 0
|
||||
const estimatedHeight = visibleItemCount * 48 + 16 // ~48px per item + padding
|
||||
const submenuHeight = submenuRef.value?.offsetHeight || estimatedHeight
|
||||
|
||||
// Get viewport dimensions
|
||||
const viewportWidth = window.innerWidth
|
||||
@@ -282,6 +328,8 @@ const calculateSubmenuPosition = (button: HTMLElement): CSSProperties => {
|
||||
top = SUBMENU_CONFIG.OFFSET_PX
|
||||
}
|
||||
|
||||
top -= 8
|
||||
|
||||
return {
|
||||
position: 'fixed',
|
||||
top: `${top}px`,
|
||||
@@ -328,7 +376,13 @@ const onMenuItemHover = async (
|
||||
key: string,
|
||||
event: MouseEvent
|
||||
): Promise<void> => {
|
||||
if (key !== 'more') return
|
||||
if (key !== 'more' || !moreMenuItem.value?.items) return
|
||||
|
||||
// Don't show submenu if all items are hidden
|
||||
const hasVisibleItems = moreMenuItem.value.items.some(
|
||||
(item) => item.visible !== false
|
||||
)
|
||||
if (!hasVisibleItems) return
|
||||
|
||||
clearHoverTimeout()
|
||||
|
||||
@@ -380,10 +434,12 @@ const onReleaseClick = (release: ReleaseNote): void => {
|
||||
const versionAnchor = formatVersionAnchor(release.version)
|
||||
const changelogUrl = `${getChangelogUrl()}#${versionAnchor}`
|
||||
openExternalLink(changelogUrl)
|
||||
emit('close')
|
||||
}
|
||||
|
||||
const onUpdate = (_: ReleaseNote): void => {
|
||||
openExternalLink(EXTERNAL_LINKS.UPDATE_GUIDE)
|
||||
emit('close')
|
||||
}
|
||||
|
||||
// Generate language-aware changelog URL
|
||||
@@ -551,13 +607,6 @@ onMounted(async () => {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.submenu-item.disabled,
|
||||
.submenu-item:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.submenu-divider {
|
||||
height: 1px;
|
||||
background: #3e3e3e;
|
||||
|
||||
Reference in New Issue
Block a user