diff --git a/src/components/graph/GraphCanvas.vue b/src/components/graph/GraphCanvas.vue index 8327aa058..e4cf189ad 100644 --- a/src/components/graph/GraphCanvas.vue +++ b/src/components/graph/GraphCanvas.vue @@ -27,7 +27,6 @@ class="w-full h-full touch-none" /> - @@ -53,7 +52,6 @@ import BottomPanel from '@/components/bottomPanel/BottomPanel.vue' import SubgraphBreadcrumb from '@/components/breadcrumb/SubgraphBreadcrumb.vue' import DomWidgets from '@/components/graph/DomWidgets.vue' import GraphCanvasMenu from '@/components/graph/GraphCanvasMenu.vue' -import NodeBadge from '@/components/graph/NodeBadge.vue' import NodeTooltip from '@/components/graph/NodeTooltip.vue' import SelectionOverlay from '@/components/graph/SelectionOverlay.vue' import SelectionToolbox from '@/components/graph/SelectionToolbox.vue' @@ -62,6 +60,7 @@ import NodeSearchboxPopover from '@/components/searchbox/NodeSearchBoxPopover.vu import SideToolbar from '@/components/sidebar/SideToolbar.vue' import SecondRowWorkflowTabs from '@/components/topbar/SecondRowWorkflowTabs.vue' import { useChainCallback } from '@/composables/functional/useChainCallback' +import { useNodeBadge } from '@/composables/node/useNodeBadge' import { useCanvasDrop } from '@/composables/useCanvasDrop' import { useContextMenuTranslation } from '@/composables/useContextMenuTranslation' import { useCopy } from '@/composables/useCopy' @@ -254,6 +253,7 @@ const workflowPersistence = useWorkflowPersistence() // @ts-expect-error fixme ts strict error useCanvasDrop(canvasRef) useLitegraphSettings() +useNodeBadge() onMounted(async () => { useGlobalLitegraph() diff --git a/src/components/graph/NodeBadge.vue b/src/components/graph/NodeBadge.vue deleted file mode 100644 index f52aabb40..000000000 --- a/src/components/graph/NodeBadge.vue +++ /dev/null @@ -1,114 +0,0 @@ - - - diff --git a/src/composables/node/useNodeBadge.ts b/src/composables/node/useNodeBadge.ts new file mode 100644 index 000000000..be629bd03 --- /dev/null +++ b/src/composables/node/useNodeBadge.ts @@ -0,0 +1,122 @@ +import { + BadgePosition, + LGraphBadge, + type LGraphNode +} from '@comfyorg/litegraph' +import _ from 'lodash' +import { computed, onMounted, watch } from 'vue' + +import { app } from '@/scripts/app' +import { useExtensionStore } from '@/stores/extensionStore' +import { ComfyNodeDefImpl, useNodeDefStore } from '@/stores/nodeDefStore' +import { useSettingStore } from '@/stores/settingStore' +import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore' +import { NodeBadgeMode } from '@/types/nodeSource' + +/** + * Add LGraphBadge to LGraphNode based on settings. + * + * Following badges are added: + * - Node ID badge + * - Node source badge + * - Node life cycle badge + * - API node credits badge + */ +export const useNodeBadge = () => { + const settingStore = useSettingStore() + const extensionStore = useExtensionStore() + const colorPaletteStore = useColorPaletteStore() + + const nodeSourceBadgeMode = computed( + () => + settingStore.get('Comfy.NodeBadge.NodeSourceBadgeMode') as NodeBadgeMode + ) + const nodeIdBadgeMode = computed( + () => settingStore.get('Comfy.NodeBadge.NodeIdBadgeMode') as NodeBadgeMode + ) + const nodeLifeCycleBadgeMode = computed( + () => + settingStore.get( + 'Comfy.NodeBadge.NodeLifeCycleBadgeMode' + ) as NodeBadgeMode + ) + + watch([nodeSourceBadgeMode, nodeIdBadgeMode, nodeLifeCycleBadgeMode], () => { + app.graph?.setDirtyCanvas(true, true) + }) + + const nodeDefStore = useNodeDefStore() + function badgeTextVisible( + nodeDef: ComfyNodeDefImpl | null, + badgeMode: NodeBadgeMode + ): boolean { + return !( + badgeMode === NodeBadgeMode.None || + (nodeDef?.isCoreNode && badgeMode === NodeBadgeMode.HideBuiltIn) + ) + } + + onMounted(() => { + extensionStore.registerExtension({ + name: 'Comfy.NodeBadge', + nodeCreated(node: LGraphNode) { + node.badgePosition = BadgePosition.TopRight + + const badge = computed(() => { + const nodeDef = nodeDefStore.fromLGraphNode(node) + return new LGraphBadge({ + text: _.truncate( + [ + badgeTextVisible(nodeDef, nodeIdBadgeMode.value) + ? `#${node.id}` + : '', + badgeTextVisible(nodeDef, nodeLifeCycleBadgeMode.value) + ? nodeDef?.nodeLifeCycleBadgeText ?? '' + : '', + badgeTextVisible(nodeDef, nodeSourceBadgeMode.value) + ? nodeDef?.nodeSource?.badgeText ?? '' + : '' + ] + .filter((s) => s.length > 0) + .join(' '), + { + length: 31 + } + ), + fgColor: + colorPaletteStore.completedActivePalette.colors.litegraph_base + .BADGE_FG_COLOR, + bgColor: + colorPaletteStore.completedActivePalette.colors.litegraph_base + .BADGE_BG_COLOR + }) + }) + + node.badges.push(() => badge.value) + + if (node.constructor.nodeData?.api_node) { + const creditsBadge = computed(() => { + return new LGraphBadge({ + text: '', + iconOptions: { + unicode: '\ue96b', + fontFamily: 'PrimeIcons', + color: '#FABC25', + bgColor: '#353535', + fontSize: 8 + }, + fgColor: + colorPaletteStore.completedActivePalette.colors.litegraph_base + .BADGE_FG_COLOR, + bgColor: + colorPaletteStore.completedActivePalette.colors.litegraph_base + .BADGE_BG_COLOR + }) + }) + + node.badges.push(() => creditsBadge.value) + } + } + }) + }) +}