mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 18:52:19 +00:00
Add support for custom light color palette (#2156)
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
import { expect } from '@playwright/test'
|
import { expect } from '@playwright/test'
|
||||||
|
|
||||||
|
import type { Palette } from '../src/types/colorPaletteTypes'
|
||||||
import { comfyPageFixture as test } from './fixtures/ComfyPage'
|
import { comfyPageFixture as test } from './fixtures/ComfyPage'
|
||||||
|
|
||||||
const customColorPalettes = {
|
const customColorPalettes: Record<string, Palette> = {
|
||||||
obsidian: {
|
obsidian: {
|
||||||
version: 102,
|
version: 102,
|
||||||
id: 'obsidian',
|
id: 'obsidian',
|
||||||
@@ -128,6 +129,19 @@ const customColorPalettes = {
|
|||||||
'tr-odd-bg-color': 'rgba(19,19,19,.9)'
|
'tr-odd-bg-color': 'rgba(19,19,19,.9)'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
// A custom light theme with fg color red
|
||||||
|
light_red: {
|
||||||
|
id: 'light_red',
|
||||||
|
name: 'Light Red',
|
||||||
|
light_theme: true,
|
||||||
|
colors: {
|
||||||
|
node_slot: {},
|
||||||
|
litegraph_base: {},
|
||||||
|
comfy_base: {
|
||||||
|
'fg-color': '#ff0000'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +156,12 @@ test.describe('Color Palette', () => {
|
|||||||
await expect(comfyPage.canvas).toHaveScreenshot(
|
await expect(comfyPage.canvas).toHaveScreenshot(
|
||||||
'custom-color-palette-obsidian-dark.png'
|
'custom-color-palette-obsidian-dark.png'
|
||||||
)
|
)
|
||||||
|
await comfyPage.setSetting('Comfy.ColorPalette', 'light_red')
|
||||||
|
await comfyPage.nextFrame()
|
||||||
|
await expect(comfyPage.canvas).toHaveScreenshot(
|
||||||
|
'custom-color-palette-light-red.png'
|
||||||
|
)
|
||||||
|
|
||||||
await comfyPage.setSetting('Comfy.ColorPalette', 'dark')
|
await comfyPage.setSetting('Comfy.ColorPalette', 'dark')
|
||||||
await comfyPage.nextFrame()
|
await comfyPage.nextFrame()
|
||||||
await expect(comfyPage.canvas).toHaveScreenshot('default-color-palette.png')
|
await expect(comfyPage.canvas).toHaveScreenshot('default-color-palette.png')
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "light",
|
"id": "light",
|
||||||
"name": "Light",
|
"name": "Light",
|
||||||
|
"light_theme": true,
|
||||||
"colors": {
|
"colors": {
|
||||||
"node_slot": {
|
"node_slot": {
|
||||||
"CLIP": "#FFA726",
|
"CLIP": "#FFA726",
|
||||||
@@ -13,7 +14,12 @@
|
|||||||
"MASK": "#9CCC65",
|
"MASK": "#9CCC65",
|
||||||
"MODEL": "#7E57C2",
|
"MODEL": "#7E57C2",
|
||||||
"STYLE_MODEL": "#D4E157",
|
"STYLE_MODEL": "#D4E157",
|
||||||
"VAE": "#FF7043"
|
"VAE": "#FF7043",
|
||||||
|
"NOISE": "#B0B0B0",
|
||||||
|
"GUIDER": "#66FFFF",
|
||||||
|
"SAMPLER": "#ECB4B4",
|
||||||
|
"SIGMAS": "#CDFFCD",
|
||||||
|
"TAESD": "#DCC274"
|
||||||
},
|
},
|
||||||
"litegraph_base": {
|
"litegraph_base": {
|
||||||
"BACKGROUND_IMAGE": "data:image/gif;base64,R0lGODlhZABkALMAAAAAAP///+vr6+rq6ujo6Ofn5+bm5uXl5d3d3f///wAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAABkAGQAAAT/UMhJq7046827HkcoHkYxjgZhnGG6si5LqnIM0/fL4qwwIMAg0CAsEovBIxKhRDaNy2GUOX0KfVFrssrNdpdaqTeKBX+dZ+jYvEaTf+y4W66mC8PUdrE879f9d2mBeoNLfH+IhYBbhIx2jkiHiomQlGKPl4uZe3CaeZifnnijgkESBqipqqusra6vsLGys62SlZO4t7qbuby7CLa+wqGWxL3Gv3jByMOkjc2lw8vOoNSi0czAncXW3Njdx9Pf48/Z4Kbbx+fQ5evZ4u3k1fKR6cn03vHlp7T9/v8A/8Gbp4+gwXoFryXMB2qgwoMMHyKEqA5fxX322FG8tzBcRnMW/zlulPbRncmQGidKjMjyYsOSKEF2FBlJQMCbOHP6c9iSZs+UnGYCdbnSo1CZI5F64kn0p1KnTH02nSoV3dGTV7FFHVqVq1dtWcMmVQZTbNGu72zqXMuW7danVL+6e4t1bEy6MeueBYLXrNO5Ze36jQtWsOG97wIj1vt3St/DjTEORss4nNq2mDP3e7w4r1bFkSET5hy6s2TRlD2/mSxXtSHQhCunXo26NevCpmvD/UU6tuullzULH76q92zdZG/Ltv1a+W+osI/nRmyc+fRi1Xdbh+68+0vv10dH3+77KD/i6IdnX669/frn5Zsjh4/2PXju8+8bzc9/6fj27LFnX11/+IUnXWl7BJfegm79FyB9JOl3oHgSklefgxAC+FmFGpqHIYcCfkhgfCohSKKJVo044YUMttggiBkmp6KFXw1oII24oYhjiDByaKOOHcp3Y5BD/njikSkO+eBREQAAOw==",
|
"BACKGROUND_IMAGE": "data:image/gif;base64,R0lGODlhZABkALMAAAAAAP///+vr6+rq6ujo6Ofn5+bm5uXl5d3d3f///wAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAABkAGQAAAT/UMhJq7046827HkcoHkYxjgZhnGG6si5LqnIM0/fL4qwwIMAg0CAsEovBIxKhRDaNy2GUOX0KfVFrssrNdpdaqTeKBX+dZ+jYvEaTf+y4W66mC8PUdrE879f9d2mBeoNLfH+IhYBbhIx2jkiHiomQlGKPl4uZe3CaeZifnnijgkESBqipqqusra6vsLGys62SlZO4t7qbuby7CLa+wqGWxL3Gv3jByMOkjc2lw8vOoNSi0czAncXW3Njdx9Pf48/Z4Kbbx+fQ5evZ4u3k1fKR6cn03vHlp7T9/v8A/8Gbp4+gwXoFryXMB2qgwoMMHyKEqA5fxX322FG8tzBcRnMW/zlulPbRncmQGidKjMjyYsOSKEF2FBlJQMCbOHP6c9iSZs+UnGYCdbnSo1CZI5F64kn0p1KnTH02nSoV3dGTV7FFHVqVq1dtWcMmVQZTbNGu72zqXMuW7danVL+6e4t1bEy6MeueBYLXrNO5Ze36jQtWsOG97wIj1vt3St/DjTEORss4nNq2mDP3e7w4r1bFkSET5hy6s2TRlD2/mSxXtSHQhCunXo26NevCpmvD/UU6tuullzULH76q92zdZG/Ltv1a+W+osI/nRmyc+fRi1Xdbh+68+0vv10dH3+77KD/i6IdnX669/frn5Zsjh4/2PXju8+8bzc9/6fj27LFnX11/+IUnXWl7BJfegm79FyB9JOl3oHgSklefgxAC+FmFGpqHIYcCfkhgfCohSKKJVo044YUMttggiBkmp6KFXw1oII24oYhjiDByaKOOHcp3Y5BD/njikSkO+eBREQAAOw==",
|
||||||
|
|||||||
@@ -11,14 +11,15 @@
|
|||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
import { useCommandStore } from '@/stores/commandStore'
|
import { useCommandStore } from '@/stores/commandStore'
|
||||||
import { useSettingStore } from '@/stores/settingStore'
|
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
|
||||||
|
|
||||||
import SidebarIcon from './SidebarIcon.vue'
|
import SidebarIcon from './SidebarIcon.vue'
|
||||||
|
|
||||||
const settingStore = useSettingStore()
|
const colorPaletteStore = useColorPaletteStore()
|
||||||
const currentTheme = computed(() => settingStore.get('Comfy.ColorPalette'))
|
|
||||||
const icon = computed(() =>
|
const icon = computed(() =>
|
||||||
currentTheme.value !== 'light' ? 'pi pi-moon' : 'pi pi-sun'
|
colorPaletteStore.completedActivePalette.light_theme
|
||||||
|
? 'pi pi-sun'
|
||||||
|
: 'pi pi-moon'
|
||||||
)
|
)
|
||||||
|
|
||||||
const commandStore = useCommandStore()
|
const commandStore = useCommandStore()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import github from '@/assets/palettes/github.json'
|
|||||||
import light from '@/assets/palettes/light.json'
|
import light from '@/assets/palettes/light.json'
|
||||||
import nord from '@/assets/palettes/nord.json'
|
import nord from '@/assets/palettes/nord.json'
|
||||||
import solarized from '@/assets/palettes/solarized.json'
|
import solarized from '@/assets/palettes/solarized.json'
|
||||||
import type { ColorPalettes } from '@/types/colorPaletteTypes'
|
import type { ColorPalettes, CompletedPalette } from '@/types/colorPaletteTypes'
|
||||||
|
|
||||||
export const CORE_COLOR_PALETTES: ColorPalettes = {
|
export const CORE_COLOR_PALETTES: ColorPalettes = {
|
||||||
dark,
|
dark,
|
||||||
@@ -15,4 +15,6 @@ export const CORE_COLOR_PALETTES: ColorPalettes = {
|
|||||||
github
|
github
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export const DEFAULT_COLOR_PALETTE = dark
|
export const DEFAULT_COLOR_PALETTE: CompletedPalette = dark
|
||||||
|
export const DEFAULT_DARK_COLOR_PALETTE: CompletedPalette = dark
|
||||||
|
export const DEFAULT_LIGHT_COLOR_PALETTE: CompletedPalette = light
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ import {
|
|||||||
LiteGraph
|
LiteGraph
|
||||||
} from '@comfyorg/litegraph'
|
} from '@comfyorg/litegraph'
|
||||||
|
|
||||||
|
import {
|
||||||
|
DEFAULT_DARK_COLOR_PALETTE,
|
||||||
|
DEFAULT_LIGHT_COLOR_PALETTE
|
||||||
|
} from '@/constants/coreColorPalettes'
|
||||||
import { api } from '@/scripts/api'
|
import { api } from '@/scripts/api'
|
||||||
import { app } from '@/scripts/app'
|
import { app } from '@/scripts/app'
|
||||||
import { useDialogService } from '@/services/dialogService'
|
import { useDialogService } from '@/services/dialogService'
|
||||||
@@ -16,6 +20,7 @@ import { useSettingStore } from '@/stores/settingStore'
|
|||||||
import { useToastStore } from '@/stores/toastStore'
|
import { useToastStore } from '@/stores/toastStore'
|
||||||
import { type ComfyWorkflow, useWorkflowStore } from '@/stores/workflowStore'
|
import { type ComfyWorkflow, useWorkflowStore } from '@/stores/workflowStore'
|
||||||
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'
|
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'
|
||||||
|
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
|
||||||
import { useSearchBoxStore } from '@/stores/workspace/searchBoxStore'
|
import { useSearchBoxStore } from '@/stores/workspace/searchBoxStore'
|
||||||
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
||||||
|
|
||||||
@@ -23,6 +28,7 @@ export function useCoreCommands(): ComfyCommand[] {
|
|||||||
const workflowService = useWorkflowService()
|
const workflowService = useWorkflowService()
|
||||||
const workflowStore = useWorkflowStore()
|
const workflowStore = useWorkflowStore()
|
||||||
const dialogService = useDialogService()
|
const dialogService = useDialogService()
|
||||||
|
const colorPaletteStore = useColorPaletteStore()
|
||||||
const getTracker = () => workflowStore.activeWorkflow?.changeTracker
|
const getTracker = () => workflowStore.activeWorkflow?.changeTracker
|
||||||
|
|
||||||
const getSelectedNodes = (): LGraphNode[] => {
|
const getSelectedNodes = (): LGraphNode[] => {
|
||||||
@@ -410,18 +416,18 @@ export function useCoreCommands(): ComfyCommand[] {
|
|||||||
label: 'Toggle Theme (Dark/Light)',
|
label: 'Toggle Theme (Dark/Light)',
|
||||||
versionAdded: '1.3.12',
|
versionAdded: '1.3.12',
|
||||||
function: (() => {
|
function: (() => {
|
||||||
let previousDarkTheme: string = 'dark'
|
let previousDarkTheme: string = DEFAULT_DARK_COLOR_PALETTE.id
|
||||||
|
let previousLightTheme: string = DEFAULT_LIGHT_COLOR_PALETTE.id
|
||||||
|
|
||||||
// Official light theme is the only light theme supported now.
|
|
||||||
const isDarkMode = (themeId: string) => themeId !== 'light'
|
|
||||||
return () => {
|
return () => {
|
||||||
const settingStore = useSettingStore()
|
const settingStore = useSettingStore()
|
||||||
const currentTheme = settingStore.get('Comfy.ColorPalette')
|
const theme = colorPaletteStore.completedActivePalette
|
||||||
if (isDarkMode(currentTheme)) {
|
if (theme.light_theme) {
|
||||||
previousDarkTheme = currentTheme
|
previousLightTheme = theme.id
|
||||||
settingStore.set('Comfy.ColorPalette', 'light')
|
|
||||||
} else {
|
|
||||||
settingStore.set('Comfy.ColorPalette', previousDarkTheme)
|
settingStore.set('Comfy.ColorPalette', previousDarkTheme)
|
||||||
|
} else {
|
||||||
|
previousDarkTheme = theme.id
|
||||||
|
settingStore.set('Comfy.ColorPalette', previousLightTheme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import { computed, ref } from 'vue'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
CORE_COLOR_PALETTES,
|
CORE_COLOR_PALETTES,
|
||||||
DEFAULT_COLOR_PALETTE
|
DEFAULT_COLOR_PALETTE,
|
||||||
|
DEFAULT_DARK_COLOR_PALETTE,
|
||||||
|
DEFAULT_LIGHT_COLOR_PALETTE
|
||||||
} from '@/constants/coreColorPalettes'
|
} from '@/constants/coreColorPalettes'
|
||||||
import type {
|
import type {
|
||||||
ColorPalettes,
|
ColorPalettes,
|
||||||
@@ -63,20 +65,24 @@ export const useColorPaletteStore = defineStore('colorPalette', () => {
|
|||||||
palette.colors.comfy_base['comfy-menu-bg']
|
palette.colors.comfy_base['comfy-menu-bg']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultPalette = palette.light_theme
|
||||||
|
? DEFAULT_LIGHT_COLOR_PALETTE
|
||||||
|
: DEFAULT_DARK_COLOR_PALETTE
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...palette,
|
...palette,
|
||||||
colors: {
|
colors: {
|
||||||
...palette.colors,
|
...palette.colors,
|
||||||
node_slot: {
|
node_slot: {
|
||||||
...DEFAULT_COLOR_PALETTE.colors.node_slot,
|
...defaultPalette.colors.node_slot,
|
||||||
...palette.colors.node_slot
|
...palette.colors.node_slot
|
||||||
},
|
},
|
||||||
litegraph_base: {
|
litegraph_base: {
|
||||||
...DEFAULT_COLOR_PALETTE.colors.litegraph_base,
|
...defaultPalette.colors.litegraph_base,
|
||||||
...palette.colors.litegraph_base
|
...palette.colors.litegraph_base
|
||||||
},
|
},
|
||||||
comfy_base: {
|
comfy_base: {
|
||||||
...DEFAULT_COLOR_PALETTE.colors.comfy_base,
|
...defaultPalette.colors.comfy_base,
|
||||||
...palette.colors.comfy_base
|
...palette.colors.comfy_base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,8 @@ export const paletteSchema = z
|
|||||||
.object({
|
.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
colors: partialColorsSchema
|
colors: partialColorsSchema,
|
||||||
|
light_theme: z.boolean().optional()
|
||||||
})
|
})
|
||||||
.passthrough()
|
.passthrough()
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
import { useEventListener } from '@vueuse/core'
|
import { useEventListener } from '@vueuse/core'
|
||||||
import type { ToastMessageOptions } from 'primevue/toast'
|
import type { ToastMessageOptions } from 'primevue/toast'
|
||||||
import { useToast } from 'primevue/usetoast'
|
import { useToast } from 'primevue/usetoast'
|
||||||
import { computed, onBeforeUnmount, onMounted, watch, watchEffect } from 'vue'
|
import { onBeforeUnmount, onMounted, watch, watchEffect } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
import BrowserTabTitle from '@/components/BrowserTabTitle.vue'
|
import BrowserTabTitle from '@/components/BrowserTabTitle.vue'
|
||||||
@@ -41,6 +41,7 @@ import {
|
|||||||
import { useServerConfigStore } from '@/stores/serverConfigStore'
|
import { useServerConfigStore } from '@/stores/serverConfigStore'
|
||||||
import { useSettingStore } from '@/stores/settingStore'
|
import { useSettingStore } from '@/stores/settingStore'
|
||||||
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'
|
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'
|
||||||
|
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
|
||||||
import { useSidebarTabStore } from '@/stores/workspace/sidebarTabStore'
|
import { useSidebarTabStore } from '@/stores/workspace/sidebarTabStore'
|
||||||
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
||||||
import { StatusWsMessageStatus } from '@/types/apiTypes'
|
import { StatusWsMessageStatus } from '@/types/apiTypes'
|
||||||
@@ -51,18 +52,16 @@ const { t } = useI18n()
|
|||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const settingStore = useSettingStore()
|
const settingStore = useSettingStore()
|
||||||
const executionStore = useExecutionStore()
|
const executionStore = useExecutionStore()
|
||||||
|
const colorPaletteStore = useColorPaletteStore()
|
||||||
const theme = computed<string>(() => settingStore.get('Comfy.ColorPalette'))
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
theme,
|
() => colorPaletteStore.completedActivePalette,
|
||||||
(newTheme) => {
|
(newTheme) => {
|
||||||
const DARK_THEME_CLASS = 'dark-theme'
|
const DARK_THEME_CLASS = 'dark-theme'
|
||||||
const isDarkTheme = newTheme !== 'light'
|
if (newTheme.light_theme) {
|
||||||
if (isDarkTheme) {
|
|
||||||
document.body.classList.add(DARK_THEME_CLASS)
|
|
||||||
} else {
|
|
||||||
document.body.classList.remove(DARK_THEME_CLASS)
|
document.body.classList.remove(DARK_THEME_CLASS)
|
||||||
|
} else {
|
||||||
|
document.body.classList.add(DARK_THEME_CLASS)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
|
|||||||
Reference in New Issue
Block a user