mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-18 22:10:03 +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
|
||||
pinned?: boolean
|
||||
}
|
||||
color?: string
|
||||
bgcolor?: string
|
||||
}
|
||||
|
||||
export interface GraphNodeManager {
|
||||
@@ -126,7 +128,9 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
|
||||
widgets: safeWidgets,
|
||||
inputs: node.inputs ? [...node.inputs] : 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,
|
||||
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 (
|
||||
|
||||
@@ -332,6 +332,9 @@ export class LGraphNode
|
||||
|
||||
/** @inheritdoc {@link IColorable.setColorOption} */
|
||||
setColorOption(colorOption: ColorOption | null): void {
|
||||
const oldColor = this.color
|
||||
const oldBgcolor = this.bgcolor
|
||||
|
||||
if (colorOption == null) {
|
||||
delete this.color
|
||||
delete this.bgcolor
|
||||
@@ -339,6 +342,29 @@ export class LGraphNode
|
||||
this.color = colorOption.color
|
||||
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} */
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
:style="[
|
||||
{
|
||||
transform: `translate(${position.x ?? 0}px, ${(position.y ?? 0) - LiteGraph.NODE_TITLE_HEIGHT}px)`,
|
||||
zIndex: zIndex
|
||||
zIndex: zIndex,
|
||||
backgroundColor: nodeData.bgcolor || ''
|
||||
},
|
||||
dragStyle
|
||||
]"
|
||||
@@ -49,7 +50,13 @@
|
||||
</template>
|
||||
<!-- Header only updates on title/color changes -->
|
||||
<NodeHeader
|
||||
v-memo="[nodeData.title, isCollapsed, nodeData.flags?.pinned]"
|
||||
v-memo="[
|
||||
nodeData.title,
|
||||
nodeData.color,
|
||||
nodeData.bgcolor,
|
||||
isCollapsed,
|
||||
nodeData.flags?.pinned
|
||||
]"
|
||||
:node-data="nodeData"
|
||||
:readonly="readonly"
|
||||
:collapsed="isCollapsed"
|
||||
|
||||
@@ -73,6 +73,8 @@ import { useErrorHandling } from '@/composables/useErrorHandling'
|
||||
import { st } from '@/i18n'
|
||||
import { useNodeTooltips } from '@/renderer/extensions/vueNodes/composables/useNodeTooltips'
|
||||
import { app } from '@/scripts/app'
|
||||
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
|
||||
import { adjustColor } from '@/utils/colorUtil'
|
||||
import { normalizeI18nKey } from '@/utils/formatUtil'
|
||||
import {
|
||||
getLocatorIdFromNodeData,
|
||||
@@ -123,6 +125,30 @@ const tooltipConfig = computed(() => {
|
||||
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 title = (info?.title ?? '').trim()
|
||||
if (title.length > 0) return title
|
||||
|
||||
Reference in New Issue
Block a user