Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 30 additions & 60 deletions src/components/graph/selectionToolbox/ColorPickerButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
>
<template #option="{ option }">
<i
v-tooltip.top="option.localizedName"
v-tooltip.top="
typeof option.localizedName === 'function'
? option.localizedName()
: option.localizedName
"
class="pi pi-circle-fill"
:style="{
color: isLightTheme ? option.value.light : option.value.dark
Expand All @@ -48,78 +52,38 @@ import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'

import Button from '@/components/ui/button/Button.vue'
import type { NodeColorOption } from '@/composables/graph/useNodeColorOptions'
import { useNodeColorOptions } from '@/composables/graph/useNodeColorOptions'
import type { IColorable } from '@/lib/litegraph/src/interfaces'
import type {
ColorOption as CanvasColorOption,
Positionable
} from '@/lib/litegraph/src/litegraph'
import {
LGraphCanvas,
LiteGraph,
isColorable
} from '@/lib/litegraph/src/litegraph'
import { isColorable } from '@/lib/litegraph/src/litegraph'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
import { adjustColor } from '@/utils/colorUtil'
import { getItemsColorOption } from '@/utils/litegraphUtil'

const { t } = useI18n()
const canvasStore = useCanvasStore()
const colorPaletteStore = useColorPaletteStore()
const workflowStore = useWorkflowStore()
const isLightTheme = computed(
() => colorPaletteStore.completedActivePalette.light_theme
)
const toLightThemeColor = (color: string) =>
adjustColor(color, { lightness: 0.5 })

const showColorPicker = ref(false)

type ColorOption = {
name: string
localizedName: string
value: {
dark: string
light: string
}
}
const { colorOptions, NO_COLOR_OPTION, applyColorToItems, isLightTheme } =
useNodeColorOptions()

const NO_COLOR_OPTION: ColorOption = {
name: 'noColor',
localizedName: t('color.noColor'),
value: {
dark: LiteGraph.NODE_DEFAULT_BGCOLOR,
light: toLightThemeColor(LiteGraph.NODE_DEFAULT_BGCOLOR)
}
}
const colorOptions: ColorOption[] = [
NO_COLOR_OPTION,
...Object.entries(LGraphCanvas.node_colors).map(([name, color]) => ({
name,
localizedName: t(`color.${name}`),
value: {
dark: color.bgcolor,
light: toLightThemeColor(color.bgcolor)
}
}))
]
const showColorPicker = ref(false)

const selectedColorOption = ref<ColorOption | null>(null)
const applyColor = (colorOption: ColorOption | null) => {
const colorName = colorOption?.name ?? NO_COLOR_OPTION.name
const canvasColorOption =
colorName === NO_COLOR_OPTION.name
? null
: LGraphCanvas.node_colors[colorName]
const selectedColorOption = ref<NodeColorOption | null>(null)
const applyColor = (colorOption: NodeColorOption | null) => {
const colorName = colorOption?.name ?? NO_COLOR_OPTION.value.name

for (const item of canvasStore.selectedItems) {
if (isColorable(item)) {
item.setColorOption(canvasColorOption)
}
}
const colorableItems = canvasStore.selectedItems
.filter(isColorable)
.map((item) => item as unknown as IColorable)
applyColorToItems(colorableItems, colorName)

canvasStore.canvas?.setDirty(true, true)
currentColorOption.value = canvasColorOption
currentColorOption.value = getItemsColorOption(canvasStore.selectedItems)
showColorPicker.value = false
workflowStore.activeWorkflow?.changeTracker.checkState()
}
Expand All @@ -128,27 +92,33 @@ const currentColorOption = ref<CanvasColorOption | null>(null)
const currentColor = computed(() =>
currentColorOption.value
? isLightTheme.value
? toLightThemeColor(currentColorOption.value?.bgcolor)
? colorOptions.value.find(
(option: NodeColorOption) =>
option.value.dark === currentColorOption.value?.bgcolor
)?.value.light
: currentColorOption.value?.bgcolor
: null
)

const localizedCurrentColorName = computed(() => {
if (!currentColorOption.value?.bgcolor) return null
const colorOption = colorOptions.find(
(option) =>
const colorOption = colorOptions.value.find(
(option: NodeColorOption) =>
option.value.dark === currentColorOption.value?.bgcolor ||
option.value.light === currentColorOption.value?.bgcolor
)
return colorOption?.localizedName ?? NO_COLOR_OPTION.localizedName
const name = colorOption?.localizedName ?? NO_COLOR_OPTION.value.localizedName
return typeof name === 'function' ? name() : name
})

const updateColorSelectionFromNode = (
newSelectedItems: Raw<Positionable[]>
) => {
showColorPicker.value = false
selectedColorOption.value = null
currentColorOption.value = getItemsColorOption(newSelectedItems)
}

watch(
() => canvasStore.selectedItems,
(newSelectedItems) => {
Expand Down
108 changes: 23 additions & 85 deletions src/components/rightSidePanel/settings/SetNodeColor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,103 +2,37 @@
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'

import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import { LGraphCanvas, LiteGraph } from '@/lib/litegraph/src/litegraph'
import type { ColorOption } from '@/lib/litegraph/src/litegraph'
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
import { adjustColor } from '@/utils/colorUtil'
import { useNodeColorOptions } from '@/composables/graph/useNodeColorOptions'
import type { IColorable } from '@/lib/litegraph/src/interfaces'
import { cn } from '@/utils/tailwindUtil'

import LayoutField from './LayoutField.vue'

/**
* Good design limits dependencies and simplifies the interface of the abstraction layer.
* Here, we only care about the getColorOption and setColorOption methods,
* and do not concern ourselves with other methods.
*/
type PickedNode = Pick<LGraphNode, 'getColorOption' | 'setColorOption'>

const { nodes } = defineProps<{ nodes: PickedNode[] }>()
const { nodes } = defineProps<{ nodes: IColorable[] }>()
const emit = defineEmits<{ (e: 'changed'): void }>()

const { t } = useI18n()

const colorPaletteStore = useColorPaletteStore()

type NodeColorOption = {
name: string
localizedName: () => string
value: {
dark: string
light: string
ringDark: string
ringLight: string
}
}

const nodeColorEntries = Object.entries(LGraphCanvas.node_colors)

function getColorValue(color: string): NodeColorOption['value'] {
return {
dark: adjustColor(color, { lightness: 0.3 }),
light: adjustColor(color, { lightness: 0.4 }),
ringDark: adjustColor(color, { lightness: 0.5 }),
ringLight: adjustColor(color, { lightness: 0.1 })
}
}

const NO_COLOR_OPTION: NodeColorOption = {
name: 'noColor',
localizedName: () => t('color.noColor'),
value: getColorValue(LiteGraph.NODE_DEFAULT_BGCOLOR)
}

const colorOptions: NodeColorOption[] = [
NO_COLOR_OPTION,
...nodeColorEntries.map(([name, color]) => ({
name,
localizedName: () => t(`color.${name}`),
value: getColorValue(color.bgcolor)
}))
]

const isLightTheme = computed(
() => colorPaletteStore.completedActivePalette.light_theme
)

const nodeColor = computed<NodeColorOption['name'] | null>({
const { colorOptions, applyColorToItems, getCurrentColorName, isLightTheme } =
useNodeColorOptions({
includeRingColors: true,
lightnessAdjustments: {
dark: 0.3,
light: 0.4,
ringDark: 0.5,
ringLight: 0.1
},
localizedNameAsFunction: true
})

const nodeColor = computed<string | null>({
get() {
if (nodes.length === 0) return null
const theColorOptions = nodes.map((item) => item.getColorOption())

let colorOption: ColorOption | null | false = theColorOptions[0]
if (!theColorOptions.every((option) => option === colorOption)) {
colorOption = false
}

if (colorOption === false) return null
if (colorOption == null || (!colorOption.bgcolor && !colorOption.color))
return NO_COLOR_OPTION.name
return (
nodeColorEntries.find(
([_, color]) =>
color.bgcolor === colorOption.bgcolor &&
color.color === colorOption.color
)?.[0] ?? null
)
return getCurrentColorName(nodes)
},
set(colorName) {
if (colorName === null) return

const canvasColorOption =
colorName === NO_COLOR_OPTION.name
? null
: LGraphCanvas.node_colors[colorName]

for (const item of nodes) {
item.setColorOption(canvasColorOption)
}

applyColorToItems(nodes, colorName)
emit('changed')
}
})
Expand All @@ -123,7 +57,11 @@ const nodeColor = computed<NodeColorOption['name'] | null>({
@click="nodeColor = option.name"
>
<div
v-tooltip.top="option.localizedName()"
v-tooltip.top="
typeof option.localizedName === 'function'
? option.localizedName()
: option.localizedName
"
:class="cn('size-4 rounded-full ring-2 ring-gray-500/10')"
:style="{
backgroundColor: isLightTheme
Expand Down
8 changes: 6 additions & 2 deletions src/composables/graph/useGroupMenuOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useWorkflowStore } from '@/platform/workflow/management/stores/workflow
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'

import { useCanvasRefresh } from './useCanvasRefresh'
import type { NodeColorOption } from './useNodeColorOptions'
import type { MenuOption } from './useMoreOptionsMenu'
import { useNodeCustomization } from './useNodeCustomization'

Expand Down Expand Up @@ -65,8 +66,11 @@ export function useGroupMenuOptions() {
label: t('contextMenu.Color'),
icon: 'icon-[lucide--palette]',
hasSubmenu: true,
submenu: colorOptions.map((colorOption) => ({
label: colorOption.localizedName,
submenu: colorOptions.value.map((colorOption: NodeColorOption) => ({
label:
typeof colorOption.localizedName === 'function'
? colorOption.localizedName()
: colorOption.localizedName,
color: isLightTheme.value
? colorOption.value.light
: colorOption.value.dark,
Expand Down
Loading