Simula_r
2025-10-02 13:58:47 -07:00
committed by GitHub
parent 3818ba5d17
commit 0d3d258995
13 changed files with 370 additions and 43 deletions

View File

@@ -101,7 +101,7 @@
<NodeContent
v-if="hasCustomContent"
:node-data="nodeData"
:image-urls="nodeImageUrls"
:media="nodeMedia"
/>
<!-- Live preview image -->
<div v-if="shouldShowPreviewImg" class="px-4">
@@ -267,10 +267,10 @@ onMounted(() => {
// Track collapsed state
const isCollapsed = computed(() => nodeData.flags?.collapsed ?? false)
// Check if node has custom content (like image outputs)
// Check if node has custom content (like image/video outputs)
const hasCustomContent = computed(() => {
// Show custom content if node has image outputs
return nodeImageUrls.value.length > 0
// Show custom content if node has media outputs
return !!nodeMedia.value && nodeMedia.value.urls.length > 0
})
// Computed classes and conditions for better reusability
@@ -340,26 +340,29 @@ const nodeOutputs = useNodeOutputStore()
const nodeOutputLocatorId = computed(() =>
nodeData.subgraphId ? `${nodeData.subgraphId}:${nodeData.id}` : nodeData.id
)
const nodeImageUrls = computed(() => {
const newOutputs = nodeOutputs.nodeOutputs[nodeOutputLocatorId.value]
const lgraphNode = computed(() => {
const locatorId = getLocatorIdFromNodeData(nodeData)
// Use root graph for getNodeByLocatorId since it needs to traverse from root
const rootGraph = app.graph?.rootGraph || app.graph
if (!rootGraph) {
return []
}
if (!rootGraph) return null
return getNodeByLocatorId(rootGraph, locatorId)
})
const node = getNodeByLocatorId(rootGraph, locatorId)
const nodeMedia = computed(() => {
const newOutputs = nodeOutputs.nodeOutputs[nodeOutputLocatorId.value]
const node = lgraphNode.value
// Note: Despite the field name "images", videos are also included.
// The actual media type is determined by node.previewMediaType
// TODO: fix the backend to return videos using the vidoes key instead of the images key
if (node && newOutputs?.images?.length) {
const urls = nodeOutputs.getNodeImageUrls(node)
if (urls) {
return urls
if (urls && urls.length > 0) {
const type = node.previewMediaType === 'video' ? 'video' : 'image'
return { type, urls } as const
}
}
// Clear URLs if no outputs or no images
return []
return undefined
})
const nodeContainerRef = ref()

View File

@@ -5,9 +5,15 @@
<div v-else class="lg-node-content">
<!-- Default slot for custom content -->
<slot>
<VideoPreview
v-if="hasMedia && media?.type === 'video'"
:image-urls="media.urls"
:node-id="nodeId"
class="mt-2"
/>
<ImagePreview
v-if="hasImages"
:image-urls="props.imageUrls || []"
v-else-if="hasMedia && media?.type === 'image'"
:image-urls="media.urls"
:node-id="nodeId"
class="mt-2"
/>
@@ -20,24 +26,24 @@ import { computed, onErrorCaptured, ref } from 'vue'
import type { VueNodeData } from '@/composables/graph/useGraphNodeManager'
import { useErrorHandling } from '@/composables/useErrorHandling'
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
import VideoPreview from '../VideoPreview.vue'
import ImagePreview from './ImagePreview.vue'
interface NodeContentProps {
node?: LGraphNode // For backwards compatibility
nodeData?: VueNodeData // New clean data structure
imageUrls?: string[]
nodeData?: VueNodeData
media?: {
type: 'image' | 'video'
urls: string[]
}
}
const props = defineProps<NodeContentProps>()
const hasImages = computed(() => props.imageUrls && props.imageUrls.length > 0)
const hasMedia = computed(() => props.media && props.media.urls.length > 0)
// Get node ID from nodeData or node prop
const nodeId = computed(() => {
return props.nodeData?.id?.toString() || props.node?.id?.toString()
})
// Get node ID from nodeData
const nodeId = computed(() => props.nodeData?.id?.toString())
// Error boundary implementation
const renderError = ref<string | null>(null)