Tighter image sizing in vue mode (#8702)

Fixes multiple overlapping issues with both the ImagePreviews (LoadImage
node) and LivePreview (Ksampler node) to eliminate empty space and move
the bahviour to be closer to the litegraph implementation.
- NodeWidgets will no longer no longer flex-grow when it contains no
widgets capable of growing
<img width="278" height="585" alt="image"
src="https://github.com/user-attachments/assets/c4c39805-1474-457b-86d1-b64ecf01319f"
/>

- The number of element layers for LivePreview has been reduced. Sizing
is difficult to properly spread across nested flex levels.
- The ImagePreview and LivePreview now have `contain-size` set with a
min height of 220 pixels (the same as the litegraph implementation).
This allows images to "pillarbox" by increasing width without increasing
height.
  | Before | After |
  | ------ | ----- |
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/3fe38a20-47d3-4a77-a0db-63167f76b0be"/>
| <img width="360" alt="after"
src="https://github.com/user-attachments/assets/22dc6bf6-1812-49bb-95a1-3febfb3e40dd"
/>|
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/99b24547-6850-4b46-a972-53411676c78f"
/> | <img width="360" alt="after"
src="https://github.com/user-attachments/assets/0a7783c8-cf93-47aa-8c60-608b9a4b4498"
/>|

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8702-Tighter-image-sizing-in-vue-mode-2ff6d73d3650814196f0d55d81a42e2d)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
This commit is contained in:
AustinMroz
2026-02-06 16:39:26 -08:00
committed by GitHub
parent f53b0879ed
commit e7932f2fc2
6 changed files with 25 additions and 34 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@@ -1,7 +1,7 @@
<template>
<div
v-if="imageUrls.length > 0"
class="image-preview group relative flex size-full min-h-16 min-w-16 flex-col px-2 justify-center"
class="image-preview group relative flex size-full min-h-55 min-w-16 flex-col px-2 justify-center"
@keydown="handleKeyDown"
>
<!-- Image Wrapper -->
@@ -43,7 +43,7 @@
ref="currentImageEl"
:src="currentImageUrl"
:alt="imageAltText"
class="block size-full object-contain pointer-events-none"
class="block size-full object-contain pointer-events-none contain-size"
@load="handleImageLoad"
@error="handleImageError"
/>

View File

@@ -116,9 +116,10 @@
<NodeContent :node-data="nodeData" :media="nodeMedia" />
</div>
<!-- Live mid-execution preview images -->
<div v-if="shouldShowPreviewImg" class="min-h-0 flex-1 px-4">
<LivePreview :image-url="latestPreviewUrl || null" />
</div>
<LivePreview
v-if="shouldShowPreviewImg"
:image-url="latestPreviewUrl"
/>
<!-- Show advanced inputs button for subgraph nodes -->
<div v-if="showAdvancedInputsButton" class="flex justify-center px-3">

View File

@@ -1,30 +1,20 @@
<template>
<div v-if="imageUrl" class="flex h-full min-h-16 w-full min-w-16 flex-col">
<!-- Image Container -->
<template v-if="imageUrl">
<div
class="relative h-88 w-full grow overflow-hidden rounded-[5px] bg-node-component-surface"
v-if="imageError"
class="text-pure-white flex h-full w-full flex-col items-center justify-center text-center"
>
<!-- Error State -->
<div
v-if="imageError"
class="text-pure-white flex h-full w-full flex-col items-center justify-center text-center"
>
<i-lucide:image-off class="mb-1 size-8 text-smoke-500" />
<p class="text-xs text-smoke-400">{{ $t('g.imageFailedToLoad') }}</p>
</div>
<!-- Main Image -->
<img
v-else
:src="imageUrl"
:alt="$t('g.liveSamplingPreview')"
class="pointer-events-none h-full w-full object-contain object-center"
@load="handleImageLoad"
@error="handleImageError"
/>
<i-lucide:image-off class="mb-1 size-8 text-smoke-500" />
<p class="text-xs text-smoke-400">{{ $t('g.imageFailedToLoad') }}</p>
</div>
<!-- Image Dimensions -->
<img
v-else
:src="imageUrl"
:alt="$t('g.liveSamplingPreview')"
class="pointer-events-none w-full object-contain contain-size min-h-55 flex-1"
@load="handleImageLoad"
@error="handleImageError"
/>
<div class="text-node-component-header-text mt-1 text-center text-xs">
{{
imageError
@@ -32,15 +22,14 @@
: actualDimensions || $t('g.calculatingDimensions')
}}
</div>
</div>
</template>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
interface LivePreviewProps {
/** Image URL to display */
imageUrl: string | null
imageUrl: string
}
const props = defineProps<LivePreviewProps>()

View File

@@ -6,14 +6,15 @@
v-else
:class="
cn(
'lg-node-widgets grid grid-cols-[min-content_minmax(80px,max-content)_minmax(125px,auto)] flex-1 gap-y-1 pr-3',
'lg-node-widgets grid grid-cols-[min-content_minmax(80px,max-content)_minmax(125px,auto)] gap-y-1 pr-3',
shouldHandleNodePointerEvents
? 'pointer-events-auto'
: 'pointer-events-none'
)
"
:style="{
'grid-template-rows': gridTemplateRows
'grid-template-rows': gridTemplateRows,
flex: gridTemplateRows.includes('auto') ? 1 : undefined
}"
@pointerdown.capture="handleBringToFront"
@pointerdown="handleWidgetPointerEvent"

View File

@@ -28,7 +28,7 @@ export const useNodePreviewState = (
const latestPreviewUrl = computed(() => {
const urls = previewUrls.value
return urls?.length ? urls.at(-1) : ''
return urls?.length ? urls.at(-1)! : ''
})
const shouldShowPreviewImg = computed(() => {