feat: Integrated tab UI updates (#8516)

## Summary
Next iteration of the integrated tab/top menu

## Changes
- **What**:  
- make integrated default, rename old to legacy
- move feedback to integrated
- fix user icon shapes
- remove comfy cloud text in top bar, move to canvas stats
- add chevron to C logo menu
- move help back to sidebar
   - remove now unused help top positioning code

## Screenshots (if applicable)
<img width="428" height="148" alt="image"
src="https://github.com/user-attachments/assets/725025b7-4982-4f61-be11-8aabb0a1faff"
/>
<img width="264" height="187" alt="image"
src="https://github.com/user-attachments/assets/91fa5e92-df08-4467-9bc5-50a614d9b8aa"
/>
<img width="1169" height="220" alt="image"
src="https://github.com/user-attachments/assets/68c81bea-0cff-48df-8303-a6231a1d2fc4"
/>
<img width="242" height="207" alt="image"
src="https://github.com/user-attachments/assets/5a10f40e-83ae-44c3-9434-3dbe87ba30e2"
/>
<img width="302" height="222" alt="image"
src="https://github.com/user-attachments/assets/27fcc638-5fff-4302-9a1f-066227aafd86"
/>

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
pythongosssss
2026-03-07 19:20:01 +00:00
committed by GitHub
parent 5bb742ac3a
commit 1687ca93b3
57 changed files with 114 additions and 138 deletions

View File

@@ -166,13 +166,22 @@ describe('TopMenuSection', () => {
})
describe('authentication state', () => {
function createLegacyTabBarWrapper() {
const pinia = createTestingPinia({ createSpy: vi.fn })
const settingStore = useSettingStore(pinia)
vi.mocked(settingStore.get).mockImplementation((key) =>
key === 'Comfy.UI.TabBarLayout' ? 'Legacy' : undefined
)
return createWrapper({ pinia })
}
describe('when user is logged in', () => {
beforeEach(() => {
mockData.isLoggedIn = true
})
it('should display CurrentUserButton and not display LoginButton', () => {
const wrapper = createWrapper()
const wrapper = createLegacyTabBarWrapper()
expect(wrapper.findComponent(CurrentUserButton).exists()).toBe(true)
expect(wrapper.findComponent(LoginButton).exists()).toBe(false)
})
@@ -186,7 +195,7 @@ describe('TopMenuSection', () => {
describe('on desktop platform', () => {
it('should display LoginButton and not display CurrentUserButton', () => {
mockData.isDesktop = true
const wrapper = createWrapper()
const wrapper = createLegacyTabBarWrapper()
expect(wrapper.findComponent(LoginButton).exists()).toBe(true)
expect(wrapper.findComponent(CurrentUserButton).exists()).toBe(false)
})
@@ -194,7 +203,7 @@ describe('TopMenuSection', () => {
describe('on web platform', () => {
it('should not display CurrentUserButton and not display LoginButton', () => {
const wrapper = createWrapper()
const wrapper = createLegacyTabBarWrapper()
expect(wrapper.findComponent(CurrentUserButton).exists()).toBe(false)
expect(wrapper.findComponent(LoginButton).exists()).toBe(false)
})

View File

@@ -183,7 +183,7 @@ const isActionbarFloating = computed(
() => isActionbarEnabled.value && !isActionbarDocked.value
)
const isIntegratedTabBar = computed(
() => settingStore.get('Comfy.UI.TabBarLayout') === 'Integrated'
() => settingStore.get('Comfy.UI.TabBarLayout') !== 'Legacy'
)
const { isQueuePanelV2Enabled, isRunProgressBarEnabled } =
useQueueFeatureFlags()

View File

@@ -1,6 +1,6 @@
<template>
<Avatar
class="bg-interface-panel-selected-surface"
class="aspect-square bg-interface-panel-selected-surface"
:image="photoUrl ?? undefined"
:icon="hasAvatar ? undefined : 'icon-[lucide--user]'"
:pt:icon:class="{ 'size-4': !hasAvatar }"

View File

@@ -5,11 +5,8 @@
v-if="isHelpCenterVisible"
class="help-center-popup"
:class="{
'sidebar-left':
triggerLocation === 'sidebar' && sidebarLocation === 'left',
'sidebar-right':
triggerLocation === 'sidebar' && sidebarLocation === 'right',
'topbar-right': triggerLocation === 'topbar',
'sidebar-left': sidebarLocation === 'left',
'sidebar-right': sidebarLocation === 'right',
'small-sidebar': isSmall
}"
>
@@ -63,7 +60,6 @@ const { isSmall = false } = defineProps<{
const {
isHelpCenterVisible,
triggerLocation,
sidebarLocation,
closeHelpCenter,
handleWhatsNewDismissed
@@ -101,25 +97,6 @@ const {
right: 1rem;
}
.help-center-popup.topbar-right {
top: 2rem;
right: 1rem;
bottom: auto;
animation: slideInDown 0.2s ease-out;
}
@keyframes slideInDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInUp {
from {
opacity: 0;

View File

@@ -11,12 +11,13 @@
}"
@click="onLogoMenuClick($event)"
>
<div class="flex size-8 items-center justify-center rounded-lg bg-black">
<div class="flex items-center gap-0.5">
<ComfyLogo
alt="ComfyUI Logo"
class="comfyui-logo h-[18px] w-[18px] text-white"
class="comfyui-logo h-[18px] w-[18px]"
mode="fill"
/>
<i class="icon-[lucide--chevron-down] size-3 text-muted-foreground" />
</div>
</div>

View File

@@ -41,7 +41,7 @@
v-if="userStore.isMultiUserServer"
:is-small="isSmall"
/>
<SidebarHelpCenterIcon v-if="!isIntegratedTabBar" :is-small="isSmall" />
<SidebarHelpCenterIcon :is-small="isSmall" />
<SidebarBottomPanelToggleButton v-if="!isCloud" :is-small="isSmall" />
<SidebarShortcutsToggleButton :is-small="isSmall" />
<SidebarSettingsButton :is-small="isSmall" />
@@ -95,9 +95,6 @@ const sidebarLocation = computed<'left' | 'right'>(() =>
settingStore.get('Comfy.Sidebar.Location')
)
const sidebarStyle = computed(() => settingStore.get('Comfy.Sidebar.Style'))
const isIntegratedTabBar = computed(
() => settingStore.get('Comfy.UI.TabBarLayout') === 'Integrated'
)
const isConnected = computed(
() =>
selectedTab.value ||

View File

@@ -7,7 +7,7 @@
:icon-badge="shouldShowRedDot ? '' : ''"
badge-class="-top-1 -right-1 min-w-2 w-2 h-2 p-0 rounded-full text-[0px] bg-[#ff3b30]"
:is-small="isSmall"
@click="toggleHelpCenter"
@click="toggleHelpCenter()"
/>
</template>

View File

@@ -30,7 +30,7 @@
<UserAvatar
v-else
:photo-url="photoURL"
:class="compact && 'size-full'"
:class="compact && 'h-full w-auto'"
/>
<i v-if="showArrow" class="icon-[lucide--chevron-down] size-4 px-1" />

View File

@@ -1,21 +0,0 @@
<template>
<Button
class="comfy-help-center-btn relative text-base-foreground"
variant="textonly"
@click="toggleHelpCenter"
>
<div class="not-md:hidden">{{ $t('menu.helpAndFeedback') }}</div>
<i class="ml-0.5 icon-[lucide--circle-help]" />
<span
v-if="shouldShowRedDot"
class="absolute top-[7px] right-[7px] size-1.5 rounded-full bg-[#ff3b30]"
/>
</Button>
</template>
<script setup lang="ts">
import Button from '@/components/ui/button/Button.vue'
import { useHelpCenter } from '@/composables/useHelpCenter'
const { shouldShowRedDot, toggleHelpCenter } = useHelpCenter('topbar')
</script>

View File

@@ -83,13 +83,18 @@
v-if="isIntegratedTabBar"
class="ml-auto flex shrink-0 items-center gap-2 px-2"
>
<TopMenuHelpButton />
<CurrentUserButton
v-if="isLoggedIn"
:show-arrow="false"
compact
class="grid w-10 shrink-0 p-1"
/>
<Button
v-if="isCloud || isNightly"
v-tooltip="{ value: $t('actionbar.feedbackTooltip'), showDelay: 300 }"
variant="muted-textonly"
size="icon"
class="shrink-0 text-base-foreground"
:aria-label="$t('actionbar.feedback')"
@click="openFeedback"
>
<i class="icon-[lucide--message-square-text]" />
</Button>
<CurrentUserButton v-if="showCurrentUser" compact class="shrink-0 p-1" />
<LoginButton v-else-if="isDesktop" class="p-1" />
</div>
<div v-if="isDesktop" class="window-actions-spacer app-drag shrink-0" />
@@ -102,21 +107,20 @@ import ScrollPanel from 'primevue/scrollpanel'
import SelectButton from 'primevue/selectbutton'
import { computed, nextTick, onUpdated, ref, watch } from 'vue'
import type { WatchStopHandle } from 'vue'
import CurrentUserButton from '@/components/topbar/CurrentUserButton.vue'
import LoginButton from '@/components/topbar/LoginButton.vue'
import TopMenuHelpButton from '@/components/topbar/TopMenuHelpButton.vue'
import WorkflowTab from '@/components/topbar/WorkflowTab.vue'
import Button from '@/components/ui/button/Button.vue'
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
import { useOverflowObserver } from '@/composables/element/useOverflowObserver'
import { useSettingStore } from '@/platform/settings/settingStore'
import { buildFeedbackUrl } from '@/platform/support/config'
import { useWorkflowService } from '@/platform/workflow/core/services/workflowService'
import type { ComfyWorkflow } from '@/platform/workflow/management/stores/workflowStore'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import { useCommandStore } from '@/stores/commandStore'
import { useWorkspaceStore } from '@/stores/workspaceStore'
import { isDesktop } from '@/platform/distribution/types'
import { isCloud, isDesktop, isNightly } from '@/platform/distribution/types'
import { whileMouseDown } from '@/utils/mouseDownUtil'
import WorkflowOverflowMenu from './WorkflowOverflowMenu.vue'
@@ -138,8 +142,14 @@ const commandStore = useCommandStore()
const { isLoggedIn } = useCurrentUser()
const isIntegratedTabBar = computed(
() => settingStore.get('Comfy.UI.TabBarLayout') === 'Integrated'
() => settingStore.get('Comfy.UI.TabBarLayout') !== 'Legacy'
)
const showCurrentUser = computed(() => isCloud || isLoggedIn.value)
const feedbackUrl = buildFeedbackUrl()
function openFeedback() {
window.open(feedbackUrl, '_blank', 'noopener,noreferrer')
}
const containerRef = ref<HTMLElement | null>(null)
const showOverflowArrows = ref(false)

View File

@@ -5,19 +5,15 @@ import { useSettingStore } from '@/platform/settings/settingStore'
import { useTelemetry } from '@/platform/telemetry'
import { useReleaseStore } from '@/platform/updates/common/releaseStore'
import { useHelpCenterStore } from '@/stores/helpCenterStore'
import type { HelpCenterTriggerLocation } from '@/stores/helpCenterStore'
import { useConflictAcknowledgment } from '@/workbench/extensions/manager/composables/useConflictAcknowledgment'
import { useConflictDetection } from '@/workbench/extensions/manager/composables/useConflictDetection'
import { useNodeConflictDialog } from '@/workbench/extensions/manager/composables/useNodeConflictDialog'
export function useHelpCenter(
triggerFrom: HelpCenterTriggerLocation = 'sidebar'
) {
export function useHelpCenter() {
const settingStore = useSettingStore()
const releaseStore = useReleaseStore()
const helpCenterStore = useHelpCenterStore()
const { isVisible: isHelpCenterVisible, triggerLocation } =
storeToRefs(helpCenterStore)
const { isVisible: isHelpCenterVisible } = storeToRefs(helpCenterStore)
const { shouldShowRedDot: showReleaseRedDot } = storeToRefs(releaseStore)
const conflictDetection = useConflictDetection()
@@ -42,9 +38,9 @@ export function useHelpCenter(
*/
const toggleHelpCenter = () => {
useTelemetry()?.trackUiButtonClicked({
button_id: `${triggerFrom}_help_center_toggled`
button_id: 'sidebar_help_center_toggled'
})
helpCenterStore.toggle(triggerFrom)
helpCenterStore.toggle()
}
const closeHelpCenter = () => {
@@ -90,7 +86,6 @@ export function useHelpCenter(
return {
isHelpCenterVisible,
triggerLocation,
shouldShowRedDot,
sidebarLocation,
toggleHelpCenter,

View File

@@ -1,6 +1,7 @@
import { computed } from 'vue'
import { computed, watch } from 'vue'
import { remoteConfig } from '@/platform/remoteConfig/remoteConfig'
import { t } from '@/i18n'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useExtensionService } from '@/services/extensionService'
import type { TopbarBadge } from '@/types/comfy'
@@ -17,16 +18,20 @@ const badges = computed<TopbarBadge[]>(() => {
tooltip: alert.tooltip
})
}
// Always add cloud badge last (furthest right)
result.push({
icon: 'icon-[lucide--cloud]',
text: 'Comfy Cloud'
})
return result
})
const canvasStore = useCanvasStore()
watch(
() => canvasStore.canvas,
(canvas) => {
if (canvas) {
canvas.info_text = t('g.comfyCloud')
}
},
{ immediate: true }
)
useExtensionService().registerExtension({
name: 'Comfy.Cloud.Badges',
get topbarBadges() {

View File

@@ -1,21 +1,14 @@
import { t } from '@/i18n'
import { getDistribution, ZENDESK_FIELDS } from '@/platform/support/config'
import { useSettingStore } from '@/platform/settings/settingStore'
import { buildFeedbackUrl } from '@/platform/support/config'
import { useExtensionService } from '@/services/extensionService'
import type { ActionBarButton } from '@/types/comfy'
const ZENDESK_BASE_URL = 'https://support.comfy.org/hc/en-us/requests/new'
const ZENDESK_FEEDBACK_FORM_ID = '43066738713236'
const distribution = getDistribution()
const params = new URLSearchParams({
ticket_form_id: ZENDESK_FEEDBACK_FORM_ID,
[ZENDESK_FIELDS.DISTRIBUTION]: distribution
})
const feedbackUrl = `${ZENDESK_BASE_URL}?${params.toString()}`
const feedbackUrl = buildFeedbackUrl()
const buttons: ActionBarButton[] = [
{
icon: 'icon-[lucide--message-circle-question-mark]',
icon: 'icon-[lucide--message-square-text]',
label: t('actionbar.feedback'),
tooltip: t('actionbar.feedbackTooltip'),
onClick: () => {
@@ -25,6 +18,10 @@ const buttons: ActionBarButton[] = [
]
useExtensionService().registerExtension({
name: 'Comfy.Cloud.FeedbackButton',
actionBarButtons: buttons
name: 'Comfy.FeedbackButton',
get actionBarButtons() {
return useSettingStore().get('Comfy.UI.TabBarLayout') === 'Legacy'
? buttons
: []
}
})

View File

@@ -559,6 +559,8 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
clear_background_color: string
render_only_selected: boolean
show_info: boolean
/** Additional text appended to the canvas info overlay (rendered by {@link renderInfo}). */
info_text: string | undefined
allow_dragcanvas: boolean
allow_dragnodes: boolean
allow_interaction: boolean
@@ -5180,8 +5182,10 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
* draws some useful stats in the corner of the canvas
*/
renderInfo(ctx: CanvasRenderingContext2D, x: number, y: number): void {
const lineHeight = 13
const lineCount = (this.graph ? 5 : 1) + (this.info_text ? 1 : 0)
x = x || 10
y = y || this.canvas.offsetHeight - 80
y = y || this.canvas.offsetHeight - (lineCount + 1) * lineHeight
ctx.save()
ctx.translate(x, y)
@@ -5189,18 +5193,26 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
ctx.font = `10px ${LiteGraph.DEFAULT_FONT}`
ctx.fillStyle = '#888'
ctx.textAlign = 'left'
let line = 1
if (this.graph) {
ctx.fillText(`T: ${this.graph.globaltime.toFixed(2)}s`, 5, 13 * 1)
ctx.fillText(`I: ${this.graph.iteration}`, 5, 13 * 2)
ctx.fillText(
`T: ${this.graph.globaltime.toFixed(2)}s`,
5,
lineHeight * line++
)
ctx.fillText(`I: ${this.graph.iteration}`, 5, lineHeight * line++)
ctx.fillText(
`N: ${this.graph._nodes.length} [${this.visible_nodes.length}]`,
5,
13 * 3
lineHeight * line++
)
ctx.fillText(`V: ${this.graph._version}`, 5, 13 * 4)
ctx.fillText(`FPS:${this.fps.toFixed(2)}`, 5, 13 * 5)
ctx.fillText(`V: ${this.graph._version}`, 5, lineHeight * line++)
ctx.fillText(`FPS:${this.fps.toFixed(2)}`, 5, lineHeight * line++)
} else {
ctx.fillText('No graph selected', 5, 13 * 1)
ctx.fillText('No graph selected', 5, lineHeight * line++)
}
if (this.info_text) {
ctx.fillText(this.info_text, 5, lineHeight * line++)
}
ctx.restore()
}

View File

@@ -1855,7 +1855,6 @@
"execute": "تنفيذ",
"fullscreen": "ملء الشاشة",
"help": "مساعدة",
"helpAndFeedback": "المساعدة والتعليقات",
"hideMenu": "إخفاء القائمة",
"instant": "فوري",
"instantTooltip": "سيتم وضع سير العمل في قائمة الانتظار فور انتهاء التوليد",

View File

@@ -301,6 +301,7 @@
"1x": "1x",
"2x": "2x",
"beta": "BETA",
"comfyCloud": "Comfy Cloud",
"nightly": "NIGHTLY",
"profile": "Profile",
"noItems": "No items",
@@ -968,7 +969,6 @@
"customNodesManager": "Custom Nodes Manager",
"settings": "Settings",
"help": "Help",
"helpAndFeedback": "Help & Feedback",
"queue": "Queue Panel",
"fullscreen": "Fullscreen"
},

View File

@@ -1855,7 +1855,6 @@
"execute": "Ejecutar",
"fullscreen": "Pantalla completa",
"help": "Ayuda",
"helpAndFeedback": "Ayuda y comentarios",
"hideMenu": "Ocultar menú",
"instant": "Instantáneo",
"instantTooltip": "El flujo de trabajo se encolará instantáneamente después de que finalice una generación",

View File

@@ -1855,7 +1855,6 @@
"execute": "اجرا",
"fullscreen": "تمام‌صفحه",
"help": "راهنما",
"helpAndFeedback": "راهنما و بازخورد",
"hideMenu": "مخفی کردن منو",
"instant": "فوری",
"instantTooltip": "workflow بلافاصله پس از پایان تولید در صف قرار می‌گیرد",

View File

@@ -1855,7 +1855,6 @@
"execute": "Exécuter",
"fullscreen": "Plein écran",
"help": "Aide",
"helpAndFeedback": "Aide et commentaires",
"hideMenu": "Masquer le menu",
"instant": "Instantané",
"instantTooltip": "Le flux de travail sera mis en file d'attente immédiatement après la fin d'une génération",

View File

@@ -1855,7 +1855,6 @@
"execute": "実行",
"fullscreen": "全画面表示",
"help": "ヘルプ",
"helpAndFeedback": "ヘルプとフィードバック",
"hideMenu": "メニューを隠す",
"instant": "即時",
"instantTooltip": "生成完了後すぐにキューに追加",

View File

@@ -1855,7 +1855,6 @@
"execute": "실행",
"fullscreen": "전체 화면",
"help": "도움말",
"helpAndFeedback": "도움말 및 피드백",
"hideMenu": "메뉴 숨기기",
"instant": "즉시",
"instantTooltip": "워크플로 실행이 완료되면 즉시 실행 대기열에 추가합니다.",

View File

@@ -1855,7 +1855,6 @@
"execute": "Executar",
"fullscreen": "Tela cheia",
"help": "Ajuda",
"helpAndFeedback": "Ajuda e feedback",
"hideMenu": "Ocultar menu",
"instant": "Instantâneo",
"instantTooltip": "O fluxo de trabalho será enfileirado instantaneamente após uma geração terminar",

View File

@@ -1855,7 +1855,6 @@
"execute": "Выполнить",
"fullscreen": "Полноэкранный режим",
"help": "Справка",
"helpAndFeedback": "Помощь и обратная связь",
"hideMenu": "Скрыть меню",
"instant": "Мгновенно",
"instantTooltip": "Рабочий процесс будет помещён в очередь сразу же после завершения генерации",

View File

@@ -1855,7 +1855,6 @@
"execute": "Yürüt",
"fullscreen": "Tam ekran",
"help": "Yardım",
"helpAndFeedback": "Yardım ve Geri Bildirim",
"hideMenu": "Menüyü Gizle",
"instant": "Anında",
"instantTooltip": "İş akışı, bir oluşturma işlemi bittikten sonra anında kuyruğa alınacak",

View File

@@ -1855,7 +1855,6 @@
"execute": "執行",
"fullscreen": "全螢幕",
"help": "說明",
"helpAndFeedback": "說明與回饋",
"hideMenu": "隱藏選單",
"instant": "立即",
"instantTooltip": "每次產生完成後,工作流程會立即排入佇列",

View File

@@ -1855,7 +1855,6 @@
"execute": "执行",
"fullscreen": "全屏",
"help": "说明",
"helpAndFeedback": "帮助与反馈",
"hideMenu": "隐藏菜单",
"instant": "实时",
"instantTooltip": "工作流将会在生成完成后立即执行",

View File

@@ -570,10 +570,11 @@ export const CORE_SETTINGS: SettingParams[] = [
category: ['Appearance', 'General'],
name: 'Tab Bar Layout',
type: 'combo',
options: ['Default', 'Integrated'],
tooltip:
'Controls the layout of the tab bar. "Integrated" moves Help and User controls into the tab bar area.',
defaultValue: 'Default'
options: ['Default', 'Legacy'],
tooltip: 'Controls the elements contained in the integrated tab bar.',
defaultValue: 'Default',
migrateDeprecatedValue: (value: unknown) =>
value === 'Integrated' ? 'Default' : value
},
{
id: 'Comfy.UseNewMenu',

View File

@@ -3,7 +3,7 @@ import { isCloud, isNightly } from '@/platform/distribution/types'
/**
* Zendesk ticket form field IDs.
*/
export const ZENDESK_FIELDS = {
const ZENDESK_FIELDS = {
/** Distribution tag (cloud vs OSS) */
DISTRIBUTION: 'tf_42243568391700',
/** User email (anonymous requester) */
@@ -18,13 +18,25 @@ export const ZENDESK_FIELDS = {
* Gets the distribution identifier for Zendesk tracking.
* Helps distinguish feedback from different build types.
*/
export function getDistribution(): 'ccloud' | 'oss-nightly' | 'oss' {
function getDistribution(): 'ccloud' | 'oss-nightly' | 'oss' {
if (isCloud) return 'ccloud'
if (isNightly) return 'oss-nightly'
return 'oss'
}
const SUPPORT_BASE_URL = 'https://support.comfy.org/hc/en-us/requests/new'
const ZENDESK_FEEDBACK_FORM_ID = '43066738713236'
/**
* Builds the feedback form URL with the appropriate distribution tag.
*/
export function buildFeedbackUrl(): string {
const params = new URLSearchParams({
ticket_form_id: ZENDESK_FEEDBACK_FORM_ID,
[ZENDESK_FIELDS.DISTRIBUTION]: getDistribution()
})
return `${SUPPORT_BASE_URL}?${params.toString()}`
}
/**
* Builds the support URL with optional user information for pre-filling.

View File

@@ -1,6 +1,6 @@
<template>
<div
class="flex size-8 items-center justify-center rounded-md text-base font-semibold text-white"
class="flex aspect-square size-8 items-center justify-center rounded-md text-base font-semibold text-white"
:style="{
background: gradient,
textShadow: '0 1px 2px rgba(0, 0, 0, 0.2)'

View File

@@ -296,7 +296,7 @@ const zSettings = z.object({
'Comfy.Canvas.BackgroundImage': z.string().optional(),
'Comfy.ConfirmClear': z.boolean(),
'Comfy.DevMode': z.boolean(),
'Comfy.UI.TabBarLayout': z.enum(['Default', 'Integrated']),
'Comfy.UI.TabBarLayout': z.enum(['Default', 'Legacy']),
'Comfy.Workflow.ShowMissingNodesWarning': z.boolean(),
'Comfy.Workflow.ShowMissingModelsWarning': z.boolean(),
'Comfy.Workflow.WarnBlueprintOverwrite': z.boolean(),

View File

@@ -1,21 +1,14 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
export type HelpCenterTriggerLocation = 'sidebar' | 'topbar'
export const useHelpCenterStore = defineStore('helpCenter', () => {
const isVisible = ref(false)
const triggerLocation = ref<HelpCenterTriggerLocation>('sidebar')
const toggle = (location: HelpCenterTriggerLocation = 'sidebar') => {
if (!isVisible.value) {
triggerLocation.value = location
}
const toggle = () => {
isVisible.value = !isVisible.value
}
const show = (location: HelpCenterTriggerLocation = 'sidebar') => {
triggerLocation.value = location
const show = () => {
isVisible.value = true
}
@@ -25,7 +18,6 @@ export const useHelpCenterStore = defineStore('helpCenter', () => {
return {
isVisible,
triggerLocation,
toggle,
show,
hide