UI color updates & tweaks (#6381)

## Summary

Small updates to the UI to make it more visually distinct from the graph
nodes and improving the login button

## Changes

- **What**: 
  - Improve theme support with dynamic colors
  - Standardize surface colors/borders
  - Add shadows to all floating UI elements
  - Change side toolbar to be docked by default
  - Decrease side toolbar width
  - Change login button to icon only
  - Update C button to be more distinctive

## Review Focus

- Theme tokens, I am not sure what the overall plan for how these tokens
will be supported for custom user palettes. I've implemented a method
where default variables are chosen that look nice over all existing
themes, but they can be overridden.

## Screenshots

Dark theme updated color
<img width="958" height="615" alt="image"
src="https://github.com/user-attachments/assets/a2c540cf-6c05-4ad3-996b-8b7b80df8d2d"
/>

Themed & updated menu button (active vs hover vs default)
<img width="58" height="338" alt="github"
src="https://github.com/user-attachments/assets/90244ee2-d5ee-4b26-9d99-f4b8439aa372"
/><img width="58" height="338" alt="nord"
src="https://github.com/user-attachments/assets/053e8e7b-d639-4b72-92d2-ec7e2167aab8"
/><img width="58" height="338" alt="arc"
src="https://github.com/user-attachments/assets/3caeb07b-d41b-4d88-83b4-ef8d45d4e5a6"
/><img width="58" height="338" alt="solarized"
src="https://github.com/user-attachments/assets/6ebf6afb-ec3a-436b-90eb-bda40be1c79f"
/><img width="58" height="338" alt="light"
src="https://github.com/user-attachments/assets/fbb7f96a-b722-40c5-86fa-a0732e166972"
/><img width="58" height="338" alt="dark"
src="https://github.com/user-attachments/assets/5459208b-9256-4c55-9373-169e9cd9f09a"
/>

With labels
<img width="58" height="394" alt="labels"
src="https://github.com/user-attachments/assets/f97ee354-35cd-42b8-896f-57ac39644c1d"
/>

Logged out (only visible on desktop)
<img width="323" height="48" alt="logged out"
src="https://github.com/user-attachments/assets/75b71420-0c1b-446f-8cdd-43c68674d346"
/>

Logged in
<img width="355" height="48" alt="logged in"
src="https://github.com/user-attachments/assets/324fd133-a793-49dd-844a-f93dd5d1effb"
/>


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6381-UI-color-updates-tweaks-29b6d73d3650816384d2ef5617a776a0)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
pythongosssss
2025-11-02 20:43:21 +00:00
committed by GitHub
parent e1f707ffe2
commit fd236b3587
42 changed files with 137 additions and 56 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -241,6 +241,18 @@
--border-subtle: var(--color-smoke-400);
--muted-background: var(--color-smoke-700);
--accent-background: var(--color-smoke-800);
/* Default UI element color palette variables */
--palette-contrast-mix-color: #fff;
--palette-interface-panel-surface: var(--comfy-menu-bg);
--palette-interface-stroke: color-mix(in srgb, var(--interface-panel-surface) 75.5%, var(--contrast-mix-color));
--palette-interface-panel-box-shadow: 1px 1px 8px 0 rgb(0 0 0 / 0.4);
--palette-interface-panel-drop-shadow: 1px 1px 4px rgb(0 0 0 / 0.4);
--palette-interface-panel-hover-surface: color-mix(in srgb, var(--interface-panel-surface) 92.5%, var(--contrast-mix-color));
--palette-interface-panel-selected-surface: color-mix(in srgb, var(--interface-panel-surface) 87.5%, var(--contrast-mix-color));
--palette-interface-button-hover-surface: color-mix(in srgb, var(--interface-panel-surface) 82%, var(--contrast-mix-color));
}
.dark-theme {

View File

@@ -4,6 +4,13 @@ import { addDynamicIconSelectors } from '@iconify/tailwind'
import { iconCollection } from './src/iconCollection'
export default {
theme: {
extend: {
boxShadow: {
interface: 'var(--interface-panel-box-shadow)'
}
}
},
plugins: [
addDynamicIconSelectors({
iconSets: {

View File

@@ -52,7 +52,7 @@
"comfy_base": {
"fg-color": "#fff",
"bg-color": "#202020",
"comfy-menu-bg": "#353535",
"comfy-menu-bg": "#11141a",
"comfy-menu-secondary-bg": "#303030",
"comfy-input-bg": "#222",
"input-text": "#ddd",

View File

@@ -68,7 +68,12 @@
"content-fg": "#222",
"content-hover-bg": "#adadad",
"content-hover-fg": "#222",
"bar-shadow": "rgba(16, 16, 16, 0.25) 0 0 0.5rem"
"bar-shadow": "rgba(16, 16, 16, 0.25) 0 0 0.5rem",
"interface-panel-box-shadow": "1px 1px 8px 0 rgba(0, 0, 0, 0.2)",
"interface-panel-drop-shadow": "1px 1px 4px rgba(0, 0, 0, 0.4)",
"interface-panel-hover-surface": "var(--color-gray-200)",
"interface-panel-selected-surface": "color-mix(in srgb, var(--interface-panel-surface) 78%, var(--contrast-mix-color))",
"contrast-mix-color": "#000"
}
}
}

View File

@@ -5,7 +5,7 @@
</div>
<div
class="actionbar-container pointer-events-auto mx-1 flex h-12 items-center rounded-lg px-2 shadow-md"
class="actionbar-container pointer-events-auto mx-1 flex h-12 items-center rounded-lg border border-[var(--interface-stroke)] px-2 shadow-interface"
>
<!-- Support for legacy topbar elements attached by custom scripts, hidden if no elements present -->
<div
@@ -48,6 +48,5 @@ onMounted(() => {
<style scoped>
.actionbar-container {
background-color: var(--comfy-menu-bg);
border: 1px solid var(--p-panel-border-color);
}
</style>

View File

@@ -268,7 +268,9 @@ const panelClass = computed(() =>
cn(
'actionbar pointer-events-auto z1000',
isDragging.value && 'select-none pointer-events-none',
isDocked.value ? 'p-0 static mr-2 border-none bg-transparent' : 'fixed'
isDocked.value
? 'p-0 static mr-2 border-none bg-transparent'
: 'fixed shadow-interface'
)
)
</script>

View File

@@ -1,6 +1,6 @@
<template>
<div
class="subgraph-breadcrumb w-auto drop-shadow-md"
class="subgraph-breadcrumb w-auto drop-shadow-[var(--interface-panel-drop-shadow)]"
:class="{
'subgraph-breadcrumb-collapse': collapseTabs,
'subgraph-breadcrumb-overflow': overflowingTabs
@@ -208,8 +208,8 @@ onUpdated(() => {
:deep(.p-breadcrumb-separator),
:deep(.p-breadcrumb-item) {
@apply h-12;
border-top: 1px solid var(--p-panel-border-color);
border-bottom: 1px solid var(--p-panel-border-color);
border-top: 1px solid var(--interface-stroke);
border-bottom: 1px solid var(--interface-stroke);
background-color: var(--comfy-menu-bg);
}
@@ -221,7 +221,7 @@ onUpdated(() => {
@apply rounded-l-lg;
/* Then collapse the root workflow */
flex-shrink: 5000;
border-left: 1px solid var(--p-panel-border-color);
border-left: 1px solid var(--interface-stroke);
.p-breadcrumb-item-link {
padding-left: var(--p-breadcrumb-item-padding);
@@ -232,7 +232,7 @@ onUpdated(() => {
@apply rounded-r-lg;
/* Then collapse the active item */
flex-shrink: 1;
border-right: 1px solid var(--p-panel-border-color);
border-right: 1px solid var(--interface-stroke);
}
:deep(.p-breadcrumb-item-link:hover),

View File

@@ -56,7 +56,7 @@ describe('UserAvatar', () => {
const avatar = wrapper.findComponent(Avatar)
expect(avatar.exists()).toBe(true)
expect(avatar.props('image')).toBeNull()
expect(avatar.props('icon')).toBe('pi pi-user')
expect(avatar.props('icon')).toBe('icon-[lucide--user]')
})
it('renders with default icon when provided photo Url is null', () => {
@@ -67,7 +67,7 @@ describe('UserAvatar', () => {
const avatar = wrapper.findComponent(Avatar)
expect(avatar.exists()).toBe(true)
expect(avatar.props('image')).toBeNull()
expect(avatar.props('icon')).toBe('pi pi-user')
expect(avatar.props('icon')).toBe('icon-[lucide--user]')
})
it('falls back to icon when image fails to load', async () => {
@@ -82,7 +82,7 @@ describe('UserAvatar', () => {
avatar.vm.$emit('error')
await nextTick()
expect(avatar.props('icon')).toBe('pi pi-user')
expect(avatar.props('icon')).toBe('icon-[lucide--user]')
})
it('uses provided ariaLabel', () => {

View File

@@ -1,7 +1,9 @@
<template>
<Avatar
class="bg-gray-200 dark-theme:bg-[var(--interface-panel-selected-surface)]"
:image="photoUrl ?? undefined"
:icon="hasAvatar ? undefined : 'pi pi-user'"
:icon="hasAvatar ? undefined : 'icon-[lucide--user]'"
:pt:icon:class="{ 'size-4': !hasAvatar }"
shape="circle"
:aria-label="ariaLabel ?? $t('auth.login.userAvatar')"
@error="handleImageError"

View File

@@ -10,8 +10,10 @@
></div>
<ButtonGroup
class="absolute right-0 bottom-0 z-[1200] flex-row gap-1 border-[1px] border-node-border bg-interface-panel-surface p-2"
:style="stringifiedMinimapStyles.buttonGroupStyles"
class="absolute right-0 bottom-0 z-[1200] flex-row gap-1 border-[1px] border-[var(--interface-stroke)] bg-interface-panel-surface p-2"
:style="{
...stringifiedMinimapStyles.buttonGroupStyles
}"
@wheel="canvasInteractions.handleWheel"
>
<CanvasModeSelector

View File

@@ -4,13 +4,11 @@
:width="size"
:height="size"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.8193 0.600586C15.1248 0.600586 15.3296 0.70893 15.459 0.881836C15.5914 1.05888 15.6471 1.33774 15.5527 1.66895L14.8037 4.30176C14.7063 4.64386 14.4729 4.97024 14.1641 5.21191C13.8544 5.45415 13.496 5.58984 13.1699 5.58984H13.1689L9.5791 5.59668H7.90625C7.52654 5.59668 7.19496 5.84986 7.09082 6.21289L5.69434 11.0889C5.63007 11.3133 5.66134 11.5534 5.77734 11.7529L5.83203 11.8359C5.99177 12.0491 6.24252 12.1758 6.50977 12.1758H6.51074L8.88281 12.1709H11.4971C11.7643 12.171 11.9541 12.254 12.084 12.3906L12.1357 12.4521C12.2685 12.6295 12.3249 12.9089 12.2305 13.2402L11.4805 15.8721C11.383 16.2144 11.1498 16.5415 10.8408 16.7832C10.5314 17.0252 10.1736 17.161 9.84766 17.1611H9.84668L6.25684 17.168H3.64258C3.33762 17.1679 3.13349 17.0588 3.00391 16.8857C2.87135 16.7087 2.81482 16.43 2.90918 16.0986L3.39551 14.3887C3.46841 14.1327 3.41794 13.8576 3.25879 13.6445V13.6436C3.09901 13.4303 2.84745 13.3037 2.58008 13.3037H1.18066C0.875088 13.3037 0.670398 13.1953 0.541016 13.0225C0.408483 12.8451 0.351891 12.5655 0.446289 12.2344L2.11914 6.38965L2.30371 5.74707V5.74609C2.40139 5.40341 2.63456 5.07671 2.94336 4.83496C3.25302 4.59258 3.61143 4.45705 3.9375 4.45703H5.6123C5.94484 4.45703 6.24083 4.26316 6.37891 3.9707L6.42773 3.83984L6.98145 1.89551C7.07894 1.55317 7.31212 1.22614 7.62109 0.984375C7.93074 0.742127 8.2892 0.606445 8.61523 0.606445H8.61621L12.1982 0.600586H14.8193Z"
:stroke="color"
stroke-width="1"
v-bind="attributes"
/>
</svg>
</template>
@@ -22,11 +20,18 @@ interface Props {
size?: number | string
color?: string
class?: string
mode?: 'outline' | 'fill'
}
const {
size = 16,
color = 'currentColor',
mode = 'outline',
class: className
} = defineProps<Props>()
const iconClass = computed(() => className || '')
const attributes = computed(() => ({
stroke: mode === 'outline' ? color : undefined,
strokeWidth: mode === 'outline' ? 1 : undefined,
fill: mode === 'fill' ? color : 'none'
}))
</script>

View File

@@ -1,21 +1,23 @@
<template>
<div
class="comfy-menu-button-wrapper flex shrink-0 cursor-pointer flex-col items-center justify-center rounded-t-md p-2 transition-colors"
v-tooltip="{
value: t('sideToolbar.labels.menu'),
showDelay: 300,
hideDelay: 300
}"
class="comfy-menu-button-wrapper flex shrink-0 cursor-pointer flex-col items-center justify-center p-2 transition-colors"
:class="{
'comfy-menu-button-active': menuRef?.visible
}"
@click="onLogoMenuClick($event)"
>
<ComfyLogoTransparent
alt="ComfyUI Logo"
class="comfyui-logo h-[18px] w-[18px]"
/>
<span
v-if="!isSmall"
class="side-bar-button-label mt-1 text-center text-[10px]"
>{{ t('sideToolbar.labels.menu') }}</span
>
<div class="flex h-8 w-8 items-center justify-center rounded-lg bg-black">
<ComfyLogo
alt="ComfyUI Logo"
class="comfyui-logo h-[18px] w-[18px] text-white"
mode="fill"
/>
</div>
</div>
<TieredMenu
@@ -75,7 +77,7 @@ import { computed, nextTick, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import SettingDialogHeader from '@/components/dialog/header/SettingDialogHeader.vue'
import ComfyLogoTransparent from '@/components/icons/ComfyLogoTransparent.vue'
import ComfyLogo from '@/components/icons/ComfyLogo.vue'
import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemplateSelectorDialog'
import SettingDialogContent from '@/platform/settings/components/SettingDialogContent.vue'
import { useTelemetry } from '@/platform/telemetry'
@@ -97,10 +99,6 @@ const colorPaletteService = useColorPaletteService()
const dialogStore = useDialogStore()
const managerState = useManagerState()
const { isSmall = false } = defineProps<{
isSmall?: boolean
}>()
const menuRef = ref<
({ dirty: boolean } & TieredMenuMethods & TieredMenuState) | null
>(null)
@@ -292,12 +290,12 @@ const hasActiveStateSiblings = (item: MenuItem): boolean => {
}
.comfy-menu-button-wrapper:hover {
background: var(--p-button-text-secondary-hover-background);
background: var(--interface-panel-hover-surface);
}
.comfy-menu-button-active,
.comfy-menu-button-active:hover {
background-color: var(--content-hover-bg);
background: var(--interface-panel-selected-surface);
}
.keybinding-tag {

View File

@@ -6,7 +6,8 @@
'small-sidebar': isSmall,
'connected-sidebar': isConnected,
'floating-sidebar': !isConnected,
'overflowing-sidebar': isOverflowing
'overflowing-sidebar': isOverflowing,
'border-r border-[var(--interface-stroke)] shadow-interface': isConnected
}"
>
<div
@@ -18,7 +19,7 @@
"
>
<div ref="topToolbarRef" :class="groupClasses">
<ComfyMenuButton :is-small="isSmall" />
<ComfyMenuButton />
<SidebarIcon
v-for="tab in tabs"
:key="tab.id"
@@ -145,7 +146,7 @@ const isOverflowing = ref(false)
const groupClasses = computed(() =>
cn(
'sidebar-item-group pointer-events-auto flex flex-col items-center overflow-hidden flex-shrink-0' +
(isConnected.value ? '' : ' rounded-lg shadow-md')
(isConnected.value ? '' : ' rounded-lg shadow-interface')
)
)
@@ -214,7 +215,7 @@ onMounted(() => {
--sidebar-padding: 4px;
--sidebar-icon-size: 1rem;
--sidebar-default-floating-width: 56px;
--sidebar-default-floating-width: 48px;
--sidebar-default-connected-width: calc(
var(--sidebar-default-floating-width) + var(--sidebar-padding) * 2
);

View File

@@ -86,7 +86,11 @@ const computedTooltip = computed(() => t(tooltip) + tooltipSuffix)
}
.side-bar-button-selected {
background-color: var(--content-hover-bg);
background-color: var(--interface-panel-selected-surface);
color: var(--content-hover-fg);
}
.side-bar-button:hover {
background-color: var(--interface-panel-hover-surface);
color: var(--content-hover-fg);
}

View File

@@ -3,16 +3,18 @@
<div>
<Button
v-if="isLoggedIn"
class="user-profile-button p-1"
class="user-profile-button p-1 hover:bg-transparent"
severity="secondary"
text
:aria-label="$t('g.currentUser')"
@click="popover?.toggle($event)"
>
<div class="flex items-center rounded-full bg-(--p-content-background)">
<div
class="flex items-center gap-1 rounded-full hover:bg-[var(--interface-button-hover-surface)]"
>
<UserAvatar :photo-url="photoURL" />
<i class="pi pi-chevron-down px-1" :style="{ fontSize: '0.5rem' }" />
<i class="pi pi-chevron-down px-1" :style="{ fontSize: '0.6rem' }" />
</div>
</Button>

View File

@@ -1,15 +1,18 @@
<template>
<Button
v-if="!isLoggedIn"
:label="t('auth.login.loginButton')"
outlined
rounded
severity="secondary"
class="text-neutral border-black/50 px-4 capitalize dark-theme:border-white/50 dark-theme:text-white"
class="size-8 border-black/50 bg-transparent text-black hover:bg-[var(--interface-panel-hover-surface)] dark-theme:border-white/50 dark-theme:text-white"
@click="handleSignIn()"
@mouseenter="showPopover"
@mouseleave="hidePopover"
/>
>
<template #icon>
<i class="icon-[lucide--user] size-4" />
</template>
</Button>
<Popover
ref="popoverRef"
class="p-2"

View File

@@ -1,7 +1,7 @@
<template>
<div
ref="containerRef"
class="workflow-tabs-container flex h-full max-w-full flex-auto flex-row overflow-hidden"
class="workflow-tabs-container flex h-full max-w-full flex-auto flex-row overflow-hidden border-b border-[var(--interface-stroke)] shadow-interface"
:class="{ 'workflow-tabs-container-desktop': isDesktop }"
>
<Button

View File

@@ -122,7 +122,7 @@ export const CORE_SETTINGS: SettingParams[] = [
name: 'Sidebar style',
type: 'combo',
options: ['floating', 'connected'],
defaultValue: 'floating'
defaultValue: 'connected'
},
{
id: 'Comfy.TextareaWidget.FontSize',

View File

@@ -17,7 +17,7 @@
<div
ref="containerRef"
class="litegraph-minimap relative bg-interface-panel-surface"
class="litegraph-minimap relative border border-[var(--interface-stroke)] bg-interface-panel-surface shadow-interface"
:style="containerStyles"
>
<Button

View File

@@ -1,6 +1,6 @@
<template>
<div
class="minimap-panel mr-2 flex flex-col gap-2 bg-interface-panel-surface p-3 text-sm"
class="minimap-panel mr-2 flex flex-col gap-2 bg-interface-panel-surface p-3 text-sm shadow-interface"
:style="panelStyles"
>
<div class="flex items-center gap-2">

View File

@@ -57,7 +57,7 @@ const litegraphBaseSchema = z.object({
BADGE_BG_COLOR: z.string()
})
const comfyBaseSchema = z.object({
export const comfyBaseSchema = z.object({
['fg-color']: z.string(),
['bg-color']: z.string(),
['bg-img']: z.string().optional(),
@@ -75,7 +75,15 @@ const comfyBaseSchema = z.object({
['content-fg']: z.string(),
['content-hover-bg']: z.string(),
['content-hover-fg']: z.string(),
['bar-shadow']: z.string()
['bar-shadow']: z.string(),
['contrast-mix-color']: z.string().optional(),
['interface-stroke']: z.string().optional(),
['interface-panel-surface']: z.string().optional(),
['interface-panel-box-shadow']: z.string().optional(),
['interface-panel-drop-shadow']: z.string().optional(),
['interface-panel-hover-surface']: z.string().optional(),
['interface-panel-selected-surface']: z.string().optional(),
['interface-button-hover-surface']: z.string().optional()
})
const colorsSchema = z.object({

View File

@@ -1,11 +1,12 @@
import { toRaw } from 'vue'
import { z } from 'zod'
import { fromZodError } from 'zod-validation-error'
import { downloadBlob } from '@/base/common/downloadUtil'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { LGraphCanvas, LiteGraph } from '@/lib/litegraph/src/litegraph'
import { useSettingStore } from '@/platform/settings/settingStore'
import { paletteSchema } from '@/schemas/colorPaletteSchema'
import { paletteSchema, comfyBaseSchema } from '@/schemas/colorPaletteSchema'
import type { Colors, Palette } from '@/schemas/colorPaletteSchema'
import { app } from '@/scripts/app'
import { uploadFile } from '@/scripts/utils'
@@ -158,6 +159,26 @@ export const useColorPaletteService = () => {
}
}
/**
* Gets optional keys from a Zod schema object.
*
* @param schema - The Zod schema object to analyze.
* @returns Array of optional key names.
*/
const getOptionalKeys = (schema: z.ZodObject<any, any>) => {
const optionalKeys: string[] = []
const shape = schema.shape
for (const [key, value] of Object.entries(shape)) {
if (value instanceof z.ZodOptional || value instanceof z.ZodDefault) {
optionalKeys.push(key)
}
}
return optionalKeys
}
const optionalComfyBaseKeys = getOptionalKeys(comfyBaseSchema)
/**
* Loads the Comfy color palette.
*
@@ -169,6 +190,16 @@ export const useColorPaletteService = () => {
for (const [key, value] of Object.entries(comfyColorPalette)) {
rootStyle.setProperty('--' + key, value)
}
for (const optionalKey of optionalComfyBaseKeys) {
if (!(optionalKey in comfyColorPalette)) {
rootStyle.setProperty(
'--' + optionalKey,
`var(--palette-${optionalKey})`
)
}
}
const backgroundImage = settingStore.get('Comfy.Canvas.BackgroundImage')
if (backgroundImage) {
rootStyle.setProperty(