mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 03:01:54 +00:00
feat: vue node preivew when searchnig or using sidebar workbench
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
<!-- Reference:
|
<!-- Reference:
|
||||||
https://github.com/Nuked88/ComfyUI-N-Sidebar/blob/7ae7da4a9761009fb6629bc04c683087a3e168db/app/js/functions/sb_fn.js#L149
|
https://github.com/Nuked88/ComfyUI-N-Sidebar/blob/7ae7da4a9761009fb6629bc04c683087a3e168db/app/js/functions/sb_fn.js#L149
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="_sb_node_preview">
|
<LGraphNodePreview v-if="shouldRenderVueNodes" :node-def="nodeDef" />
|
||||||
|
<div v-else class="_sb_node_preview">
|
||||||
<div class="_sb_table">
|
<div class="_sb_table">
|
||||||
<div
|
<div
|
||||||
class="node_header text-ellipsis mr-4"
|
class="node_header text-ellipsis mr-4"
|
||||||
@@ -85,6 +85,8 @@ https://github.com/Nuked88/ComfyUI-N-Sidebar/blob/7ae7da4a9761009fb6629bc04c6830
|
|||||||
import _ from 'es-toolkit/compat'
|
import _ from 'es-toolkit/compat'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
import { useVueFeatureFlags } from '@/composables/useVueFeatureFlags'
|
||||||
|
import LGraphNodePreview from '@/renderer/extensions/vueNodes/components/LGraphNodePreview.vue'
|
||||||
import type { ComfyNodeDef as ComfyNodeDefV2 } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
import type { ComfyNodeDef as ComfyNodeDefV2 } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||||
import { useWidgetStore } from '@/stores/widgetStore'
|
import { useWidgetStore } from '@/stores/widgetStore'
|
||||||
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
|
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
|
||||||
@@ -94,6 +96,8 @@ const { nodeDef } = defineProps<{
|
|||||||
nodeDef: ComfyNodeDefV2
|
nodeDef: ComfyNodeDefV2
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const { shouldRenderVueNodes } = useVueFeatureFlags()
|
||||||
|
|
||||||
const colorPaletteStore = useColorPaletteStore()
|
const colorPaletteStore = useColorPaletteStore()
|
||||||
const litegraphColors = computed(
|
const litegraphColors = computed(
|
||||||
() => colorPaletteStore.completedActivePalette.colors.litegraph_base
|
() => colorPaletteStore.completedActivePalette.colors.litegraph_base
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scale-75">
|
||||||
|
<div
|
||||||
|
class="bg-white dark-theme:bg-charcoal-800 lg-node absolute rounded-2xl border border-solid border-sand-100 dark-theme:border-charcoal-600 outline-transparent -outline-offset-2 outline-2 pointer-events-none"
|
||||||
|
>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<NodeHeader :node-data="nodeData" :readonly="readonly" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4 relative">
|
||||||
|
<div class="bg-sand-100 dark-theme:bg-charcoal-600 h-px mx-0 w-full" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-4 pb-4">
|
||||||
|
<NodeSlots
|
||||||
|
v-memo="[nodeData.inputs?.length, nodeData.outputs?.length]"
|
||||||
|
:node-data="nodeData"
|
||||||
|
:readonly="readonly"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<NodeWidgets
|
||||||
|
v-if="nodeData.widgets?.length"
|
||||||
|
v-memo="[nodeData.widgets?.length]"
|
||||||
|
:node-data="nodeData"
|
||||||
|
:readonly="readonly"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<NodeContent
|
||||||
|
v-if="hasCustomContent"
|
||||||
|
:node-data="nodeData"
|
||||||
|
:readonly="readonly"
|
||||||
|
:image-urls="nodeImageUrls"
|
||||||
|
/>
|
||||||
|
<!-- Live preview image -->
|
||||||
|
<!-- <div v-if="shouldShowPreviewImg" class="px-4">
|
||||||
|
<img
|
||||||
|
:src="latestPreviewUrl"
|
||||||
|
alt="preview"
|
||||||
|
class="w-full max-h-64 object-contain"
|
||||||
|
/>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
import type { VueNodeData } from '@/composables/graph/useGraphNodeManager'
|
||||||
|
import NodeContent from '@/renderer/extensions/vueNodes/components/NodeContent.vue'
|
||||||
|
import NodeHeader from '@/renderer/extensions/vueNodes/components/NodeHeader.vue'
|
||||||
|
import NodeSlots from '@/renderer/extensions/vueNodes/components/NodeSlots.vue'
|
||||||
|
import NodeWidgets from '@/renderer/extensions/vueNodes/components/NodeWidgets.vue'
|
||||||
|
import type { ComfyNodeDef as ComfyNodeDefV2 } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||||
|
import { useWidgetStore } from '@/stores/widgetStore'
|
||||||
|
|
||||||
|
const { nodeDef } = defineProps<{
|
||||||
|
nodeDef: ComfyNodeDefV2
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const widgetStore = useWidgetStore()
|
||||||
|
|
||||||
|
// Convert nodeDef into VueNodeData
|
||||||
|
const nodeData = computed<VueNodeData>(() => {
|
||||||
|
// Convert inputs to widgets (those that have widget constructors)
|
||||||
|
const widgets = Object.entries(nodeDef.inputs || {})
|
||||||
|
.filter(([_, input]) => widgetStore.inputIsWidget(input))
|
||||||
|
.map(([name, input]) => ({
|
||||||
|
name,
|
||||||
|
type: input.widgetType || input.type,
|
||||||
|
value:
|
||||||
|
input.default !== undefined
|
||||||
|
? input.default
|
||||||
|
: input.type === 'COMBO' &&
|
||||||
|
Array.isArray(input.options) &&
|
||||||
|
input.options.length > 0
|
||||||
|
? input.options[0]
|
||||||
|
: undefined,
|
||||||
|
options: {
|
||||||
|
...input,
|
||||||
|
hidden: input.hidden,
|
||||||
|
advanced: input.advanced,
|
||||||
|
values: input.type === 'COMBO' ? input.options : undefined // For combo widgets
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Filter non-widget inputs for slots
|
||||||
|
const inputs = Object.entries(nodeDef.inputs || {})
|
||||||
|
.filter(([_, input]) => !widgetStore.inputIsWidget(input))
|
||||||
|
.map(([name, input]) => ({
|
||||||
|
name,
|
||||||
|
type: input.type,
|
||||||
|
shape: input.isOptional ? 'HollowCircle' : undefined
|
||||||
|
}))
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: `preview-${nodeDef.name}`,
|
||||||
|
title: nodeDef.display_name || nodeDef.name,
|
||||||
|
type: nodeDef.name,
|
||||||
|
mode: 0, // Normal mode
|
||||||
|
selected: false,
|
||||||
|
executing: false,
|
||||||
|
widgets,
|
||||||
|
inputs,
|
||||||
|
outputs: nodeDef.outputs || [],
|
||||||
|
flags: {
|
||||||
|
collapsed: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const readonly = true
|
||||||
|
|
||||||
|
const hasCustomContent = computed(() => {
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
const nodeImageUrls = computed(() => {
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user