mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 11:11:53 +00:00
fix vue node color change
This commit is contained in:
52
browser_tests/tests/vueNodes/nodeStates/colors.spec.ts
Normal file
52
browser_tests/tests/vueNodes/nodeStates/colors.spec.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import {
|
||||||
|
comfyExpect as expect,
|
||||||
|
comfyPageFixture as test
|
||||||
|
} from '../../../fixtures/ComfyPage'
|
||||||
|
|
||||||
|
test.describe('Vue Node Custom Colors', () => {
|
||||||
|
test.beforeEach(async ({ comfyPage }) => {
|
||||||
|
await comfyPage.setSetting('Comfy.UseNewMenu', 'Top')
|
||||||
|
await comfyPage.setSetting('Comfy.Canvas.SelectionToolbox', true)
|
||||||
|
await comfyPage.setSetting('Comfy.VueNodes.Enabled', true)
|
||||||
|
await comfyPage.vueNodes.waitForNodes()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('displays color picker button and allows color selection', async ({
|
||||||
|
comfyPage
|
||||||
|
}) => {
|
||||||
|
const loadCheckpointNode = comfyPage.page.locator('[data-node-id]').filter({
|
||||||
|
hasText: 'Load Checkpoint'
|
||||||
|
})
|
||||||
|
await loadCheckpointNode.getByText('Load Checkpoint').click()
|
||||||
|
|
||||||
|
await comfyPage.page.locator('.selection-toolbox .pi-circle-fill').click()
|
||||||
|
await comfyPage.page
|
||||||
|
.locator('.color-picker-container')
|
||||||
|
.locator('i[data-testid="blue"]')
|
||||||
|
.click()
|
||||||
|
|
||||||
|
await expect(comfyPage.canvas).toHaveScreenshot(
|
||||||
|
'vue-node-custom-color-blue.png'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: implement loading node colors from workflow in Vue system
|
||||||
|
test.fail('should load node colors from workflow', async ({ comfyPage }) => {
|
||||||
|
await comfyPage.loadWorkflow('nodes/every_node_color')
|
||||||
|
await expect(comfyPage.canvas).toHaveScreenshot(
|
||||||
|
'vue-node-custom-colors-dark-all-colors.png'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: implement loading node colors from workflow in Vue system
|
||||||
|
test.fail(
|
||||||
|
'should show brightened node colors on light theme',
|
||||||
|
async ({ comfyPage }) => {
|
||||||
|
await comfyPage.setSetting('Comfy.ColorPalette', 'light')
|
||||||
|
await comfyPage.loadWorkflow('nodes/every_node_color')
|
||||||
|
await expect(comfyPage.canvas).toHaveScreenshot(
|
||||||
|
'vue-node-custom-colors-light-all-colors.png'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
@@ -41,6 +41,8 @@ export interface VueNodeData {
|
|||||||
collapsed?: boolean
|
collapsed?: boolean
|
||||||
pinned?: boolean
|
pinned?: boolean
|
||||||
}
|
}
|
||||||
|
color?: string
|
||||||
|
bgcolor?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GraphNodeManager {
|
export interface GraphNodeManager {
|
||||||
@@ -126,7 +128,9 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
|
|||||||
widgets: safeWidgets,
|
widgets: safeWidgets,
|
||||||
inputs: node.inputs ? [...node.inputs] : undefined,
|
inputs: node.inputs ? [...node.inputs] : undefined,
|
||||||
outputs: node.outputs ? [...node.outputs] : undefined,
|
outputs: node.outputs ? [...node.outputs] : undefined,
|
||||||
flags: node.flags ? { ...node.flags } : undefined
|
flags: node.flags ? { ...node.flags } : undefined,
|
||||||
|
color: node.color || undefined,
|
||||||
|
bgcolor: node.bgcolor || undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,6 +453,24 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
|
|||||||
...currentData,
|
...currentData,
|
||||||
mode: typeof event.newValue === 'number' ? event.newValue : 0
|
mode: typeof event.newValue === 'number' ? event.newValue : 0
|
||||||
})
|
})
|
||||||
|
break
|
||||||
|
case 'color':
|
||||||
|
vueNodeData.set(nodeId, {
|
||||||
|
...currentData,
|
||||||
|
color:
|
||||||
|
typeof event.newValue === 'string'
|
||||||
|
? event.newValue
|
||||||
|
: undefined
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'bgcolor':
|
||||||
|
vueNodeData.set(nodeId, {
|
||||||
|
...currentData,
|
||||||
|
bgcolor:
|
||||||
|
typeof event.newValue === 'string'
|
||||||
|
? event.newValue
|
||||||
|
: undefined
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
|
|||||||
@@ -332,6 +332,9 @@ export class LGraphNode
|
|||||||
|
|
||||||
/** @inheritdoc {@link IColorable.setColorOption} */
|
/** @inheritdoc {@link IColorable.setColorOption} */
|
||||||
setColorOption(colorOption: ColorOption | null): void {
|
setColorOption(colorOption: ColorOption | null): void {
|
||||||
|
const oldColor = this.color
|
||||||
|
const oldBgcolor = this.bgcolor
|
||||||
|
|
||||||
if (colorOption == null) {
|
if (colorOption == null) {
|
||||||
delete this.color
|
delete this.color
|
||||||
delete this.bgcolor
|
delete this.bgcolor
|
||||||
@@ -339,6 +342,29 @@ export class LGraphNode
|
|||||||
this.color = colorOption.color
|
this.color = colorOption.color
|
||||||
this.bgcolor = colorOption.bgcolor
|
this.bgcolor = colorOption.bgcolor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger property change events for Vue node synchronization
|
||||||
|
if (this.graph) {
|
||||||
|
const newColor = this.color // undefined if deleted
|
||||||
|
const newBgcolor = this.bgcolor // undefined if deleted
|
||||||
|
|
||||||
|
if (oldColor !== newColor) {
|
||||||
|
this.graph.trigger('node:property:changed', {
|
||||||
|
nodeId: this.id,
|
||||||
|
property: 'color',
|
||||||
|
oldValue: oldColor,
|
||||||
|
newValue: newColor
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (oldBgcolor !== newBgcolor) {
|
||||||
|
this.graph.trigger('node:property:changed', {
|
||||||
|
nodeId: this.id,
|
||||||
|
property: 'bgcolor',
|
||||||
|
oldValue: oldBgcolor,
|
||||||
|
newValue: newBgcolor
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritdoc {@link IColorable.getColorOption} */
|
/** @inheritdoc {@link IColorable.getColorOption} */
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
:style="[
|
:style="[
|
||||||
{
|
{
|
||||||
transform: `translate(${position.x ?? 0}px, ${(position.y ?? 0) - LiteGraph.NODE_TITLE_HEIGHT}px)`,
|
transform: `translate(${position.x ?? 0}px, ${(position.y ?? 0) - LiteGraph.NODE_TITLE_HEIGHT}px)`,
|
||||||
zIndex: zIndex
|
zIndex: zIndex,
|
||||||
|
backgroundColor: nodeData.bgcolor || ''
|
||||||
},
|
},
|
||||||
dragStyle
|
dragStyle
|
||||||
]"
|
]"
|
||||||
@@ -49,7 +50,13 @@
|
|||||||
</template>
|
</template>
|
||||||
<!-- Header only updates on title/color changes -->
|
<!-- Header only updates on title/color changes -->
|
||||||
<NodeHeader
|
<NodeHeader
|
||||||
v-memo="[nodeData.title, isCollapsed, nodeData.flags?.pinned]"
|
v-memo="[
|
||||||
|
nodeData.title,
|
||||||
|
nodeData.color,
|
||||||
|
nodeData.bgcolor,
|
||||||
|
isCollapsed,
|
||||||
|
nodeData.flags?.pinned
|
||||||
|
]"
|
||||||
:node-data="nodeData"
|
:node-data="nodeData"
|
||||||
:readonly="readonly"
|
:readonly="readonly"
|
||||||
:collapsed="isCollapsed"
|
:collapsed="isCollapsed"
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ import { useErrorHandling } from '@/composables/useErrorHandling'
|
|||||||
import { st } from '@/i18n'
|
import { st } from '@/i18n'
|
||||||
import { useNodeTooltips } from '@/renderer/extensions/vueNodes/composables/useNodeTooltips'
|
import { useNodeTooltips } from '@/renderer/extensions/vueNodes/composables/useNodeTooltips'
|
||||||
import { app } from '@/scripts/app'
|
import { app } from '@/scripts/app'
|
||||||
|
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
|
||||||
|
import { adjustColor } from '@/utils/colorUtil'
|
||||||
import { normalizeI18nKey } from '@/utils/formatUtil'
|
import { normalizeI18nKey } from '@/utils/formatUtil'
|
||||||
import {
|
import {
|
||||||
getLocatorIdFromNodeData,
|
getLocatorIdFromNodeData,
|
||||||
@@ -123,6 +125,30 @@ const tooltipConfig = computed(() => {
|
|||||||
return createTooltipConfig(description)
|
return createTooltipConfig(description)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Header style that replicates LiteGraph's ColorOption and drawNode logic
|
||||||
|
const headerStyle = computed(() => {
|
||||||
|
if (!nodeData?.color) {
|
||||||
|
return { backgroundColor: '' } // Explicitly clear background color
|
||||||
|
}
|
||||||
|
|
||||||
|
const colorPaletteStore = useColorPaletteStore()
|
||||||
|
let headerColor = nodeData.color
|
||||||
|
|
||||||
|
// Apply base header darkening to replicate LiteGraph's ColorOption system
|
||||||
|
// When header and body colors are the same/similar, darken the header
|
||||||
|
if (nodeData.bgcolor && nodeData.color === nodeData.bgcolor) {
|
||||||
|
// Darken header relative to body (opposite of light theme adjustment)
|
||||||
|
headerColor = adjustColor(nodeData.color, { lightness: -0.15 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply light theme lightening on top of base darkening (same as drawNode monkey patch)
|
||||||
|
if (colorPaletteStore.completedActivePalette.light_theme) {
|
||||||
|
headerColor = adjustColor(headerColor, { lightness: 0.5 })
|
||||||
|
}
|
||||||
|
|
||||||
|
return { backgroundColor: headerColor }
|
||||||
|
})
|
||||||
|
|
||||||
const resolveTitle = (info: VueNodeData | undefined) => {
|
const resolveTitle = (info: VueNodeData | undefined) => {
|
||||||
const title = (info?.title ?? '').trim()
|
const title = (info?.title ?? '').trim()
|
||||||
if (title.length > 0) return title
|
if (title.length > 0) return title
|
||||||
|
|||||||
Reference in New Issue
Block a user