mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-05 15:40:10 +00:00
171 lines
5.3 KiB
TypeScript
171 lines
5.3 KiB
TypeScript
import _ from 'es-toolkit/compat'
|
|
import { computed, onMounted, watch } from 'vue'
|
|
|
|
import { useNodePricing } from '@/composables/node/useNodePricing'
|
|
import { useComputedWithWidgetWatch } from '@/composables/node/useWatchWidget'
|
|
import {
|
|
BadgePosition,
|
|
LGraphBadge,
|
|
type LGraphNode
|
|
} from '@/lib/litegraph/src/litegraph'
|
|
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'
|
|
import { adjustColor } from '@/utils/colorUtil'
|
|
|
|
/**
|
|
* 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
|
|
)
|
|
|
|
const showApiPricingBadge = computed(() =>
|
|
settingStore.get('Comfy.NodeBadge.ShowApiPricing')
|
|
)
|
|
|
|
watch(
|
|
[
|
|
nodeSourceBadgeMode,
|
|
nodeIdBadgeMode,
|
|
nodeLifeCycleBadgeMode,
|
|
showApiPricingBadge
|
|
],
|
|
() => {
|
|
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(() => {
|
|
const nodePricing = useNodePricing()
|
|
|
|
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 && showApiPricingBadge.value) {
|
|
// Get the pricing function to determine if this node has dynamic pricing
|
|
const pricingConfig = nodePricing.getNodePricingConfig(node)
|
|
const hasDynamicPricing =
|
|
typeof pricingConfig?.displayPrice === 'function'
|
|
|
|
let creditsBadge
|
|
const createBadge = () => {
|
|
const price = nodePricing.getNodeDisplayPrice(node)
|
|
|
|
const isLightTheme =
|
|
colorPaletteStore.completedActivePalette.light_theme
|
|
return new LGraphBadge({
|
|
text: price,
|
|
iconOptions: {
|
|
unicode: '\ue96b',
|
|
fontFamily: 'PrimeIcons',
|
|
color: isLightTheme
|
|
? adjustColor('#FABC25', { lightness: 0.5 })
|
|
: '#FABC25',
|
|
bgColor: isLightTheme
|
|
? adjustColor('#654020', { lightness: 0.5 })
|
|
: '#654020',
|
|
fontSize: 8
|
|
},
|
|
fgColor:
|
|
colorPaletteStore.completedActivePalette.colors.litegraph_base
|
|
.BADGE_FG_COLOR,
|
|
bgColor: isLightTheme
|
|
? adjustColor('#8D6932', { lightness: 0.5 })
|
|
: '#8D6932'
|
|
})
|
|
}
|
|
|
|
if (hasDynamicPricing) {
|
|
// For dynamic pricing nodes, use computed that watches widget changes
|
|
const relevantWidgetNames = nodePricing.getRelevantWidgetNames(
|
|
node.constructor.nodeData?.name
|
|
)
|
|
|
|
const computedWithWidgetWatch = useComputedWithWidgetWatch(node, {
|
|
widgetNames: relevantWidgetNames,
|
|
triggerCanvasRedraw: true
|
|
})
|
|
|
|
creditsBadge = computedWithWidgetWatch(createBadge)
|
|
} else {
|
|
// For static pricing nodes, use regular computed
|
|
creditsBadge = computed(createBadge)
|
|
}
|
|
|
|
node.badges.push(() => creditsBadge.value)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|