[Refactor] Manage comfyui-body elements with Vue (#2522)
Co-authored-by: github-actions <github-actions@github.com>
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
@@ -45,8 +45,6 @@ body {
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
background: var(--bg-color) var(--bg-img);
|
||||
color: var(--fg-color);
|
||||
min-height: -webkit-fill-available;
|
||||
@@ -56,87 +54,6 @@ body {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
/**
|
||||
+------------------+------------------+------------------+
|
||||
| |
|
||||
| .comfyui-body- |
|
||||
| top |
|
||||
| (spans all cols) |
|
||||
| |
|
||||
+------------------+------------------+------------------+
|
||||
| | | |
|
||||
| .comfyui-body- | #graph-canvas | .comfyui-body- |
|
||||
| left | | right |
|
||||
| | | |
|
||||
| | | |
|
||||
+------------------+------------------+------------------+
|
||||
| |
|
||||
| .comfyui-body- |
|
||||
| bottom |
|
||||
| (spans all cols) |
|
||||
| |
|
||||
+------------------+------------------+------------------+
|
||||
*/
|
||||
|
||||
.comfyui-body-top {
|
||||
order: -5;
|
||||
/* Span across all columns */
|
||||
grid-column: 1/-1;
|
||||
/* Position at the first row */
|
||||
grid-row: 1;
|
||||
/* Top menu bar dropdown needs to be above of graph canvas splitter overlay which is z-index: 999 */
|
||||
/* Top menu bar z-index needs to be higher than bottom menu bar z-index as by default
|
||||
pysssss's image feed is located at body-bottom, and it can overlap with the queue button, which
|
||||
is located in body-top. */
|
||||
z-index: 1001;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.comfyui-body-left {
|
||||
order: -4;
|
||||
/* Position in the first column */
|
||||
grid-column: 1;
|
||||
/* Position below the top element */
|
||||
grid-row: 2;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.graph-canvas-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
order: -3;
|
||||
grid-column: 2;
|
||||
grid-row: 2;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#graph-canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.comfyui-body-right {
|
||||
order: -2;
|
||||
z-index: 10;
|
||||
grid-column: 3;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
.comfyui-body-bottom {
|
||||
order: 4;
|
||||
/* Span across all columns */
|
||||
grid-column: 1/-1;
|
||||
grid-row: 3;
|
||||
/* Bottom menu bar dropdown needs to be above of graph canvas splitter overlay which is z-index: 999 */
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.comfy-multiline-input {
|
||||
background-color: var(--comfy-input-bg);
|
||||
color: var(--input-text);
|
||||
@@ -753,7 +670,6 @@ audio.comfy-audio.empty-audio-widget {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Set auto complete panel's width as it is not accessible within vue-root */
|
||||
|
||||
@@ -1,28 +1,31 @@
|
||||
<template>
|
||||
<teleport to=".graph-canvas-container">
|
||||
<!-- Load splitter overlay only after comfyApp is ready. -->
|
||||
<!-- If load immediately, the top-level splitter stateKey won't be correctly
|
||||
synced with the stateStorage (localStorage). -->
|
||||
<LiteGraphCanvasSplitterOverlay
|
||||
v-if="comfyAppReady && betaMenuEnabled && !workspaceStore.focusMode"
|
||||
>
|
||||
<template #side-bar-panel>
|
||||
<SideToolbar />
|
||||
</template>
|
||||
<template #bottom-panel>
|
||||
<BottomPanel />
|
||||
</template>
|
||||
<template #graph-canvas-panel>
|
||||
<SecondRowWorkflowTabs
|
||||
v-if="workflowTabsPosition === 'Topbar (2nd-row)'"
|
||||
/>
|
||||
<GraphCanvasMenu v-if="canvasMenuEnabled" />
|
||||
</template>
|
||||
</LiteGraphCanvasSplitterOverlay>
|
||||
<TitleEditor />
|
||||
<GraphCanvasMenu v-if="!betaMenuEnabled && canvasMenuEnabled" />
|
||||
<canvas ref="canvasRef" id="graph-canvas" tabindex="1" />
|
||||
</teleport>
|
||||
<!-- Load splitter overlay only after comfyApp is ready. -->
|
||||
<!-- If load immediately, the top-level splitter stateKey won't be correctly
|
||||
synced with the stateStorage (localStorage). -->
|
||||
<LiteGraphCanvasSplitterOverlay
|
||||
v-if="comfyAppReady && betaMenuEnabled && !workspaceStore.focusMode"
|
||||
>
|
||||
<template #side-bar-panel>
|
||||
<SideToolbar />
|
||||
</template>
|
||||
<template #bottom-panel>
|
||||
<BottomPanel />
|
||||
</template>
|
||||
<template #graph-canvas-panel>
|
||||
<SecondRowWorkflowTabs
|
||||
v-if="workflowTabsPosition === 'Topbar (2nd-row)'"
|
||||
/>
|
||||
<GraphCanvasMenu v-if="canvasMenuEnabled" />
|
||||
</template>
|
||||
</LiteGraphCanvasSplitterOverlay>
|
||||
<TitleEditor />
|
||||
<GraphCanvasMenu v-if="!betaMenuEnabled && canvasMenuEnabled" />
|
||||
<canvas
|
||||
ref="canvasRef"
|
||||
id="graph-canvas"
|
||||
tabindex="1"
|
||||
class="w-full h-full touch-none"
|
||||
/>
|
||||
<NodeSearchboxPopover />
|
||||
<NodeTooltip v-if="tooltipEnabled" />
|
||||
<NodeBadge />
|
||||
|
||||
@@ -1,35 +1,33 @@
|
||||
<template>
|
||||
<teleport :to="teleportTarget">
|
||||
<div
|
||||
ref="topMenuRef"
|
||||
class="comfyui-menu flex items-center"
|
||||
v-show="showTopMenu"
|
||||
:class="{ dropzone: isDropZone, 'dropzone-active': isDroppable }"
|
||||
>
|
||||
<h1 class="comfyui-logo mx-2 app-drag">ComfyUI</h1>
|
||||
<CommandMenubar />
|
||||
<div class="flex-grow min-w-0 app-drag h-full">
|
||||
<WorkflowTabs v-if="workflowTabsPosition === 'Topbar'" />
|
||||
</div>
|
||||
<div class="comfyui-menu-right flex-shrink-0" ref="menuRight"></div>
|
||||
<Actionbar />
|
||||
<BottomPanelToggleButton class="flex-shrink-0" />
|
||||
<Button
|
||||
class="flex-shrink-0"
|
||||
icon="pi pi-bars"
|
||||
severity="secondary"
|
||||
text
|
||||
v-tooltip="{ value: $t('menu.hideMenu'), showDelay: 300 }"
|
||||
:aria-label="$t('menu.hideMenu')"
|
||||
@click="workspaceState.focusMode = true"
|
||||
@contextmenu="showNativeMenu"
|
||||
/>
|
||||
<div
|
||||
v-show="menuSetting !== 'Bottom'"
|
||||
class="window-actions-spacer flex-shrink-0"
|
||||
/>
|
||||
<div
|
||||
ref="topMenuRef"
|
||||
class="comfyui-menu flex items-center"
|
||||
v-show="showTopMenu"
|
||||
:class="{ dropzone: isDropZone, 'dropzone-active': isDroppable }"
|
||||
>
|
||||
<h1 class="comfyui-logo mx-2 app-drag">ComfyUI</h1>
|
||||
<CommandMenubar />
|
||||
<div class="flex-grow min-w-0 app-drag h-full">
|
||||
<WorkflowTabs v-if="workflowTabsPosition === 'Topbar'" />
|
||||
</div>
|
||||
</teleport>
|
||||
<div class="comfyui-menu-right flex-shrink-0" ref="menuRight"></div>
|
||||
<Actionbar />
|
||||
<BottomPanelToggleButton class="flex-shrink-0" />
|
||||
<Button
|
||||
class="flex-shrink-0"
|
||||
icon="pi pi-bars"
|
||||
severity="secondary"
|
||||
text
|
||||
v-tooltip="{ value: $t('menu.hideMenu'), showDelay: 300 }"
|
||||
:aria-label="$t('menu.hideMenu')"
|
||||
@click="workspaceState.focusMode = true"
|
||||
@contextmenu="showNativeMenu"
|
||||
/>
|
||||
<div
|
||||
v-show="menuSetting !== 'Bottom'"
|
||||
class="window-actions-spacer flex-shrink-0"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Virtual top menu for native window (drag handle) -->
|
||||
<div
|
||||
@@ -64,11 +62,6 @@ const workflowTabsPosition = computed(() =>
|
||||
)
|
||||
const menuSetting = computed(() => settingStore.get('Comfy.UseNewMenu'))
|
||||
const betaMenuEnabled = computed(() => menuSetting.value !== 'Disabled')
|
||||
const teleportTarget = computed(() =>
|
||||
settingStore.get('Comfy.UseNewMenu') === 'Top'
|
||||
? '.comfyui-body-top'
|
||||
: '.comfyui-body-bottom'
|
||||
)
|
||||
const showTopMenu = computed(
|
||||
() => betaMenuEnabled.value && !workspaceState.focusMode
|
||||
)
|
||||
|
||||
@@ -203,13 +203,13 @@ export class ComfyApp {
|
||||
this.vueAppReady = false
|
||||
this.ui = new ComfyUI(this)
|
||||
this.api = api
|
||||
this.bodyTop = $el('div.comfyui-body-top', { parent: document.body })
|
||||
this.bodyLeft = $el('div.comfyui-body-left', { parent: document.body })
|
||||
this.bodyRight = $el('div.comfyui-body-right', { parent: document.body })
|
||||
this.bodyBottom = $el('div.comfyui-body-bottom', { parent: document.body })
|
||||
this.canvasContainer = $el('div.graph-canvas-container', {
|
||||
parent: document.body
|
||||
})
|
||||
// Dummy placeholder elements before GraphCanvas is mounted.
|
||||
this.bodyTop = $el('div.comfyui-body-top')
|
||||
this.bodyLeft = $el('div.comfyui-body-left')
|
||||
this.bodyRight = $el('div.comfyui-body-right')
|
||||
this.bodyBottom = $el('div.comfyui-body-bottom')
|
||||
this.canvasContainer = $el('div.graph-canvas-container')
|
||||
|
||||
this.menu = new ComfyAppMenu(this)
|
||||
this.bypassBgColor = '#FF00FF'
|
||||
|
||||
@@ -774,6 +774,12 @@ export class ComfyApp {
|
||||
* Set up the app on the page
|
||||
*/
|
||||
async setup(canvasEl: HTMLCanvasElement) {
|
||||
this.bodyTop = document.getElementById('comfyui-body-top')
|
||||
this.bodyLeft = document.getElementById('comfyui-body-left')
|
||||
this.bodyRight = document.getElementById('comfyui-body-right')
|
||||
this.bodyBottom = document.getElementById('comfyui-body-bottom')
|
||||
this.canvasContainer = document.getElementById('graph-canvas-container')
|
||||
|
||||
this.canvasEl = canvasEl
|
||||
this.resizeCanvas()
|
||||
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
<template>
|
||||
<!-- Top menu bar needs to load before the GraphCanvas as it needs to host
|
||||
the menu buttons added by legacy extension scripts.-->
|
||||
<TopMenubar />
|
||||
<GraphCanvas @ready="onGraphReady" />
|
||||
<div class="comfyui-body grid h-screen w-screen overflow-hidden">
|
||||
<div class="comfyui-body-top" id="comfyui-body-top">
|
||||
<TopMenubar v-if="useNewMenu === 'Top'" />
|
||||
</div>
|
||||
<div class="comfyui-body-bottom" id="comfyui-body-bottom">
|
||||
<TopMenubar v-if="useNewMenu === 'Bottom'" />
|
||||
</div>
|
||||
<div class="comfyui-body-left" id="comfyui-body-left" />
|
||||
<div class="comfyui-body-right" id="comfyui-body-right" />
|
||||
<div class="graph-canvas-container" id="graph-canvas-container">
|
||||
<GraphCanvas @ready="onGraphReady" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<GlobalToast />
|
||||
<UnloadWindowConfirmDialog v-if="!isElectron()" />
|
||||
<BrowserTabTitle />
|
||||
@@ -13,7 +23,7 @@
|
||||
import { useEventListener } from '@vueuse/core'
|
||||
import type { ToastMessageOptions } from 'primevue/toast'
|
||||
import { useToast } from 'primevue/usetoast'
|
||||
import { onBeforeUnmount, onMounted, watch, watchEffect } from 'vue'
|
||||
import { computed, onBeforeUnmount, onMounted, watch, watchEffect } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import BrowserTabTitle from '@/components/BrowserTabTitle.vue'
|
||||
@@ -126,9 +136,11 @@ watchEffect(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const useNewMenu = computed(() => {
|
||||
return settingStore.get('Comfy.UseNewMenu')
|
||||
})
|
||||
watchEffect(() => {
|
||||
const useNewMenu = settingStore.get('Comfy.UseNewMenu')
|
||||
if (useNewMenu === 'Disabled') {
|
||||
if (useNewMenu.value === 'Disabled') {
|
||||
app.ui.menuContainer.style.setProperty('display', 'block')
|
||||
app.ui.restoreMenuPosition()
|
||||
} else {
|
||||
@@ -226,3 +238,85 @@ const onGraphReady = () => {
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.comfyui-body {
|
||||
grid-template-columns: auto 1fr auto;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
}
|
||||
|
||||
/**
|
||||
+------------------+------------------+------------------+
|
||||
| |
|
||||
| .comfyui-body- |
|
||||
| top |
|
||||
| (spans all cols) |
|
||||
| |
|
||||
+------------------+------------------+------------------+
|
||||
| | | |
|
||||
| .comfyui-body- | #graph-canvas | .comfyui-body- |
|
||||
| left | | right |
|
||||
| | | |
|
||||
| | | |
|
||||
+------------------+------------------+------------------+
|
||||
| |
|
||||
| .comfyui-body- |
|
||||
| bottom |
|
||||
| (spans all cols) |
|
||||
| |
|
||||
+------------------+------------------+------------------+
|
||||
*/
|
||||
|
||||
.comfyui-body-top {
|
||||
order: -5;
|
||||
/* Span across all columns */
|
||||
grid-column: 1/-1;
|
||||
/* Position at the first row */
|
||||
grid-row: 1;
|
||||
/* Top menu bar dropdown needs to be above of graph canvas splitter overlay which is z-index: 999 */
|
||||
/* Top menu bar z-index needs to be higher than bottom menu bar z-index as by default
|
||||
pysssss's image feed is located at body-bottom, and it can overlap with the queue button, which
|
||||
is located in body-top. */
|
||||
z-index: 1001;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.comfyui-body-left {
|
||||
order: -4;
|
||||
/* Position in the first column */
|
||||
grid-column: 1;
|
||||
/* Position below the top element */
|
||||
grid-row: 2;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.graph-canvas-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
order: -3;
|
||||
grid-column: 2;
|
||||
grid-row: 2;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.comfyui-body-right {
|
||||
order: -2;
|
||||
z-index: 10;
|
||||
grid-column: 3;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
.comfyui-body-bottom {
|
||||
order: 4;
|
||||
/* Span across all columns */
|
||||
grid-column: 1/-1;
|
||||
grid-row: 3;
|
||||
/* Bottom menu bar dropdown needs to be above of graph canvas splitter overlay which is z-index: 999 */
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
|
||||