[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;
|
height: 100vh;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
grid-template-columns: auto 1fr auto;
|
|
||||||
grid-template-rows: auto 1fr auto;
|
|
||||||
background: var(--bg-color) var(--bg-img);
|
background: var(--bg-color) var(--bg-img);
|
||||||
color: var(--fg-color);
|
color: var(--fg-color);
|
||||||
min-height: -webkit-fill-available;
|
min-height: -webkit-fill-available;
|
||||||
@@ -56,87 +54,6 @@ body {
|
|||||||
font-family: Arial, sans-serif;
|
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 {
|
.comfy-multiline-input {
|
||||||
background-color: var(--comfy-input-bg);
|
background-color: var(--comfy-input-bg);
|
||||||
color: var(--input-text);
|
color: var(--input-text);
|
||||||
@@ -753,7 +670,6 @@ audio.comfy-audio.empty-audio-widget {
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set auto complete panel's width as it is not accessible within vue-root */
|
/* Set auto complete panel's width as it is not accessible within vue-root */
|
||||||
|
|||||||
@@ -1,28 +1,31 @@
|
|||||||
<template>
|
<template>
|
||||||
<teleport to=".graph-canvas-container">
|
<!-- Load splitter overlay only after comfyApp is ready. -->
|
||||||
<!-- Load splitter overlay only after comfyApp is ready. -->
|
<!-- If load immediately, the top-level splitter stateKey won't be correctly
|
||||||
<!-- If load immediately, the top-level splitter stateKey won't be correctly
|
synced with the stateStorage (localStorage). -->
|
||||||
synced with the stateStorage (localStorage). -->
|
<LiteGraphCanvasSplitterOverlay
|
||||||
<LiteGraphCanvasSplitterOverlay
|
v-if="comfyAppReady && betaMenuEnabled && !workspaceStore.focusMode"
|
||||||
v-if="comfyAppReady && betaMenuEnabled && !workspaceStore.focusMode"
|
>
|
||||||
>
|
<template #side-bar-panel>
|
||||||
<template #side-bar-panel>
|
<SideToolbar />
|
||||||
<SideToolbar />
|
</template>
|
||||||
</template>
|
<template #bottom-panel>
|
||||||
<template #bottom-panel>
|
<BottomPanel />
|
||||||
<BottomPanel />
|
</template>
|
||||||
</template>
|
<template #graph-canvas-panel>
|
||||||
<template #graph-canvas-panel>
|
<SecondRowWorkflowTabs
|
||||||
<SecondRowWorkflowTabs
|
v-if="workflowTabsPosition === 'Topbar (2nd-row)'"
|
||||||
v-if="workflowTabsPosition === 'Topbar (2nd-row)'"
|
/>
|
||||||
/>
|
<GraphCanvasMenu v-if="canvasMenuEnabled" />
|
||||||
<GraphCanvasMenu v-if="canvasMenuEnabled" />
|
</template>
|
||||||
</template>
|
</LiteGraphCanvasSplitterOverlay>
|
||||||
</LiteGraphCanvasSplitterOverlay>
|
<TitleEditor />
|
||||||
<TitleEditor />
|
<GraphCanvasMenu v-if="!betaMenuEnabled && canvasMenuEnabled" />
|
||||||
<GraphCanvasMenu v-if="!betaMenuEnabled && canvasMenuEnabled" />
|
<canvas
|
||||||
<canvas ref="canvasRef" id="graph-canvas" tabindex="1" />
|
ref="canvasRef"
|
||||||
</teleport>
|
id="graph-canvas"
|
||||||
|
tabindex="1"
|
||||||
|
class="w-full h-full touch-none"
|
||||||
|
/>
|
||||||
<NodeSearchboxPopover />
|
<NodeSearchboxPopover />
|
||||||
<NodeTooltip v-if="tooltipEnabled" />
|
<NodeTooltip v-if="tooltipEnabled" />
|
||||||
<NodeBadge />
|
<NodeBadge />
|
||||||
|
|||||||
@@ -1,35 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<teleport :to="teleportTarget">
|
<div
|
||||||
<div
|
ref="topMenuRef"
|
||||||
ref="topMenuRef"
|
class="comfyui-menu flex items-center"
|
||||||
class="comfyui-menu flex items-center"
|
v-show="showTopMenu"
|
||||||
v-show="showTopMenu"
|
:class="{ dropzone: isDropZone, 'dropzone-active': isDroppable }"
|
||||||
:class="{ dropzone: isDropZone, 'dropzone-active': isDroppable }"
|
>
|
||||||
>
|
<h1 class="comfyui-logo mx-2 app-drag">ComfyUI</h1>
|
||||||
<h1 class="comfyui-logo mx-2 app-drag">ComfyUI</h1>
|
<CommandMenubar />
|
||||||
<CommandMenubar />
|
<div class="flex-grow min-w-0 app-drag h-full">
|
||||||
<div class="flex-grow min-w-0 app-drag h-full">
|
<WorkflowTabs v-if="workflowTabsPosition === 'Topbar'" />
|
||||||
<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>
|
</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) -->
|
<!-- Virtual top menu for native window (drag handle) -->
|
||||||
<div
|
<div
|
||||||
@@ -64,11 +62,6 @@ const workflowTabsPosition = computed(() =>
|
|||||||
)
|
)
|
||||||
const menuSetting = computed(() => settingStore.get('Comfy.UseNewMenu'))
|
const menuSetting = computed(() => settingStore.get('Comfy.UseNewMenu'))
|
||||||
const betaMenuEnabled = computed(() => menuSetting.value !== 'Disabled')
|
const betaMenuEnabled = computed(() => menuSetting.value !== 'Disabled')
|
||||||
const teleportTarget = computed(() =>
|
|
||||||
settingStore.get('Comfy.UseNewMenu') === 'Top'
|
|
||||||
? '.comfyui-body-top'
|
|
||||||
: '.comfyui-body-bottom'
|
|
||||||
)
|
|
||||||
const showTopMenu = computed(
|
const showTopMenu = computed(
|
||||||
() => betaMenuEnabled.value && !workspaceState.focusMode
|
() => betaMenuEnabled.value && !workspaceState.focusMode
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -203,13 +203,13 @@ export class ComfyApp {
|
|||||||
this.vueAppReady = false
|
this.vueAppReady = false
|
||||||
this.ui = new ComfyUI(this)
|
this.ui = new ComfyUI(this)
|
||||||
this.api = api
|
this.api = api
|
||||||
this.bodyTop = $el('div.comfyui-body-top', { parent: document.body })
|
// Dummy placeholder elements before GraphCanvas is mounted.
|
||||||
this.bodyLeft = $el('div.comfyui-body-left', { parent: document.body })
|
this.bodyTop = $el('div.comfyui-body-top')
|
||||||
this.bodyRight = $el('div.comfyui-body-right', { parent: document.body })
|
this.bodyLeft = $el('div.comfyui-body-left')
|
||||||
this.bodyBottom = $el('div.comfyui-body-bottom', { parent: document.body })
|
this.bodyRight = $el('div.comfyui-body-right')
|
||||||
this.canvasContainer = $el('div.graph-canvas-container', {
|
this.bodyBottom = $el('div.comfyui-body-bottom')
|
||||||
parent: document.body
|
this.canvasContainer = $el('div.graph-canvas-container')
|
||||||
})
|
|
||||||
this.menu = new ComfyAppMenu(this)
|
this.menu = new ComfyAppMenu(this)
|
||||||
this.bypassBgColor = '#FF00FF'
|
this.bypassBgColor = '#FF00FF'
|
||||||
|
|
||||||
@@ -774,6 +774,12 @@ export class ComfyApp {
|
|||||||
* Set up the app on the page
|
* Set up the app on the page
|
||||||
*/
|
*/
|
||||||
async setup(canvasEl: HTMLCanvasElement) {
|
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.canvasEl = canvasEl
|
||||||
this.resizeCanvas()
|
this.resizeCanvas()
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- Top menu bar needs to load before the GraphCanvas as it needs to host
|
<div class="comfyui-body grid h-screen w-screen overflow-hidden">
|
||||||
the menu buttons added by legacy extension scripts.-->
|
<div class="comfyui-body-top" id="comfyui-body-top">
|
||||||
<TopMenubar />
|
<TopMenubar v-if="useNewMenu === 'Top'" />
|
||||||
<GraphCanvas @ready="onGraphReady" />
|
</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 />
|
<GlobalToast />
|
||||||
<UnloadWindowConfirmDialog v-if="!isElectron()" />
|
<UnloadWindowConfirmDialog v-if="!isElectron()" />
|
||||||
<BrowserTabTitle />
|
<BrowserTabTitle />
|
||||||
@@ -13,7 +23,7 @@
|
|||||||
import { useEventListener } from '@vueuse/core'
|
import { useEventListener } from '@vueuse/core'
|
||||||
import type { ToastMessageOptions } from 'primevue/toast'
|
import type { ToastMessageOptions } from 'primevue/toast'
|
||||||
import { useToast } from 'primevue/usetoast'
|
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 { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
import BrowserTabTitle from '@/components/BrowserTabTitle.vue'
|
import BrowserTabTitle from '@/components/BrowserTabTitle.vue'
|
||||||
@@ -126,9 +136,11 @@ watchEffect(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const useNewMenu = computed(() => {
|
||||||
|
return settingStore.get('Comfy.UseNewMenu')
|
||||||
|
})
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const useNewMenu = settingStore.get('Comfy.UseNewMenu')
|
if (useNewMenu.value === 'Disabled') {
|
||||||
if (useNewMenu === 'Disabled') {
|
|
||||||
app.ui.menuContainer.style.setProperty('display', 'block')
|
app.ui.menuContainer.style.setProperty('display', 'block')
|
||||||
app.ui.restoreMenuPosition()
|
app.ui.restoreMenuPosition()
|
||||||
} else {
|
} else {
|
||||||
@@ -226,3 +238,85 @@ const onGraphReady = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
</script>
|
</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>
|
||||||
|
|||||||