Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2b2d6d8
cleanup: Standardize iconify lucide icon uses to the class form
DrJKL Oct 3, 2025
8171de3
cleanup: Remove safelist now that the icon classes are used explicitly
DrJKL Oct 3, 2025
1e261a0
style: first step in making the nodes themeable: LGraphNode
DrJKL Oct 3, 2025
aea30b6
style: More variable to token migration
DrJKL Oct 3, 2025
22963a8
style: More migrations, renderer/extension/vueNodes/components
DrJKL Oct 3, 2025
e9be6a3
style: tokens for tooltips
DrJKL Oct 3, 2025
00c912d
style: More migrations. Some of these seem very different than other …
DrJKL Oct 3, 2025
c6ea97a
style: More migrations, dialogs as a top level category?
DrJKL Oct 3, 2025
d124767
style: Migrate subgraph node pieces. Why aren't these using the base …
DrJKL Oct 3, 2025
b51a5a9
style: add targetable color token for the node header
DrJKL Oct 4, 2025
c750bb0
WIP: Starting to sync palette colors to use in Vue nodes
DrJKL Oct 4, 2025
95f0505
fix: Wrong backdrop color for the status indicator
DrJKL Oct 4, 2025
52924ed
WIP: More property mappings
DrJKL Oct 4, 2025
8bebd20
style: Make sure the color applies to the subgraph button too
DrJKL Oct 4, 2025
9684e3f
style: Fix border property and collapsed header rounding
DrJKL Oct 4, 2025
934b43a
style: Change enter subgraph icon
DrJKL Oct 4, 2025
f40516e
fix:Special cases for light/dark mode
DrJKL Oct 4, 2025
7aec211
fix: Make the collapse button a button
DrJKL Oct 4, 2025
e7f5bf9
fix: Collapse button sizing
DrJKL Oct 4, 2025
181d2f9
Fix: add back a little sizing to the button
DrJKL Oct 5, 2025
70336ed
test: update unit tests
DrJKL Oct 5, 2025
85a5326
[automated] Update test expectations
invalid-email-address Oct 5, 2025
e6b0fd5
cleanup: remove comprehensiveness check toggle @Myestery
DrJKL Oct 5, 2025
18ceb17
test: Update locator for selected nodes
DrJKL Oct 5, 2025
0581d30
test: Update collapse locators
DrJKL Oct 5, 2025
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
2 changes: 1 addition & 1 deletion .storybook/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ This Storybook setup includes:

## Icon Usage in Storybook

In this project, the `<i-lucide:... />` syntax from unplugin-icons is not supported in Storybook.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude and Codex thank you.

In this project, the `<i class="icon-[lucide--folder]" />` syntax from unplugin-icons is not supported in Storybook.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-blocker: This should go in the root CLAUDE.md as well. Will prevent many bad generations.


**Example:**

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ pnpm format
The project supports three types of icons, all with automatic imports (no manual imports needed):

1. **PrimeIcons** - Built-in PrimeVue icons using CSS classes: `<i class="pi pi-plus" />`
2. **Iconify Icons** - 200,000+ icons from various libraries: `<i-lucide:settings />`, `<i-mdi:folder />`
2. **Iconify Icons** - 200,000+ icons from various libraries: `<i class="icon-[lucide--settings]" />`, `<iclass="icon-[mdi--folder]" />`
3. **Custom Icons** - Your own SVG icons: `<i-comfy:workflow />`

Icons are powered by the unplugin-icons system, which automatically discovers and imports icons as Vue components. Custom icons are stored in `packages/design-system/src/icons/` and processed by `packages/design-system/src/iconCollection.ts` with automatic validation.
Expand Down
4 changes: 1 addition & 3 deletions browser_tests/fixtures/VueNodeHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ export class VueNodeHelpers {
* Get locator for selected Vue node components (using visual selection indicators)
*/
get selectedNodes(): Locator {
return this.page.locator(
'[data-node-id].outline-black, [data-node-id].outline-white'
)
return this.page.locator('[data-node-id].outline-node-component-outline')
}

/**
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions browser_tests/tests/vueNodes/nodeStates/collapse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,17 @@ test.describe('Vue Node Collapse', () => {

// Check initial expanded state icon
let iconClass = await vueNode.getCollapseIconClass()
expect(iconClass).toContain('pi-chevron-down')
expect(iconClass).not.toContain('-rotate-90')

// Collapse and check icon
await vueNode.toggleCollapse()
iconClass = await vueNode.getCollapseIconClass()
expect(iconClass).toContain('pi-chevron-right')
expect(iconClass).toContain('-rotate-90')

// Expand and check icon
await vueNode.toggleCollapse()
iconClass = await vueNode.getCollapseIconClass()
expect(iconClass).toContain('pi-chevron-down')
expect(iconClass).not.toContain('-rotate-90')
})

test('should preserve title when collapsing/expanding', async ({
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 83 additions & 5 deletions packages/design-system/src/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,90 @@
--color-dark-elevation-2: rgba(from white r g b / 0.03);
}

:root {
--backdrop: var(--color-white);
--dialog-surface: var(--color-neutral-200);
--node-component-border: var(--color-sand-100);
--node-component-executing: var(--color-blue-500);
--node-component-header: var(--fg-color);
--node-component-header-icon: var(--color-stone-200);
--node-component-header-surface: var(--color-white);
--node-component-outline: var(--color-black);
--node-component-ring: rgb(from var(--color-gray-500) r g b / 50%);
--node-component-slot-dot-outline-opacity-mult: 1;
--node-component-slot-dot-outline-opacity: 5%;
--node-component-slot-dot-outline: var(--color-black);
--node-component-slot-text: var(--color-stone-200);
--node-component-surface-highlight: var(--color-stone-100);
--node-component-surface-hovered: var(--color-charcoal-400);
--node-component-surface-selected: var(--color-charcoal-200);
--node-component-surface: var(--color-white);
--node-component-tooltip: var(--color-charcoal-700);
--node-component-tooltip-border: var(--color-sand-100);
--node-component-tooltip-surface: var(--color-white);
--node-component-widget-input: var(--fg-color);
--node-component-widget-input-surface: rgb(from var(--color-zinc-500) r g b / 10%);
--node-component-widget-skeleton-surface: var(--color-zinc-300);
--node-stroke: var(--color-stone-100);
}

.dark-theme {
--backdrop: var(--color-neutral-900);
--dialog-surface: var(--color-neutral-700);
--node-component-border: var(--color-charcoal-600);
--node-component-header-icon: var(--color-slate-300);
--node-component-header-surface: var(--color-charcoal-800);
--node-component-outline: var(--color-white);
--node-component-ring: rgb(var(--color-gray-500) / 20%);
--node-component-slot-dot-outline-opacity: 10%;
--node-component-slot-dot-outline: var(--color-white);
--node-component-slot-text: var(--color-slate-200);
--node-component-surface-highlight: var(--color-slate-100);
--node-component-surface-hovered: var(--color-charcoal-400);
--node-component-surface-selected: var(--color-charcoal-200);
--node-component-surface: var(--color-charcoal-800);
--node-component-tooltip: var(--color-white);
--node-component-tooltip-border: var(--color-slate-300);
--node-component-tooltip-surface: var(--color-charcoal-800);
--node-component-widget-skeleton-surface: var(--color-zinc-800);
--node-stroke: var(--color-slate-100);
}

@theme inline {
--color-node-component-surface: var(--color-charcoal-600);
--color-node-component-surface-highlight: var(--color-slate-100);
--color-node-component-surface-hovered: var(--color-charcoal-400);
--color-node-component-surface-selected: var(--color-charcoal-200);
--color-node-stroke: var(--color-stone-100);
--color-backdrop: var(--backdrop);
--color-dialog-surface: var(--dialog-surface);
--color-node-component-border: var(--node-component-border);
--color-node-component-executing: var(--node-component-executing);
--color-node-component-header: var(--node-component-header);
--color-node-component-header-icon: var(--node-component-header-icon);
--color-node-component-header-surface: var(--node-component-header-surface);
--color-node-component-outline: var(--node-component-outline);
--color-node-component-ring: var(--node-component-ring);
--color-node-component-slot-dot-outline: rgb(
from var(--node-component-slot-dot-outline) r g b /
calc(
var(--node-component-slot-dot-outline-opacity) *
var(--node-component-slot-dot-outline-opacity-mult)
)
);
--color-node-component-slot-text: var(--node-component-slot-text);
--color-node-component-surface-highlight: var(
--node-component-surface-highlight
);
--color-node-component-surface-hovered: var(--node-component-surface-hovered);
--color-node-component-surface-selected: var(--component-surface-selected);
--color-node-component-surface: var(--node-component-surface);
--color-node-component-tooltip: var(--node-component-tooltip);
--color-node-component-tooltip-border: var(--node-component-tooltip-border);
--color-node-component-tooltip-surface: var(--node-component-tooltip-surface);
--color-node-component-widget-input: var(--node-component-widget-input);
--color-node-component-widget-input-surface: var(
--node-component-widget-input-surface
);
--color-node-component-widget-skeleton-surface: var(
--node-component-widget-skeleton-surface
);
--color-node-stroke: var(--node-stroke);
}

@custom-variant dark-theme {
Expand Down
32 changes: 16 additions & 16 deletions packages/design-system/src/icons/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ ComfyUI supports three types of icons that can be used throughout the interface.
```vue
<template>
<!-- Primary icon set: Lucide -->
<i-lucide:download />
<i-lucide:settings />
<i-lucide:workflow class="text-2xl" />
<i class="icon-[lucide--download]" />
<i class="icon-[lucide--settings]" />
<i class="icon-[lucide--workflow]" class="text-2xl" />
<!-- Other popular icon sets -->
<i-mdi:folder-open />
Expand All @@ -41,7 +41,7 @@ ComfyUI supports three types of icons that can be used throughout the interface.
<!-- Carbon Icons -->
<!-- With styling -->
<i-lucide:save class="w-6 h-6 text-blue-500" />
<i class="icon-[lucide--save]" class="w-6 h-6 text-blue-500" />
</template>
```

Expand Down Expand Up @@ -77,7 +77,7 @@ ComfyUI supports three types of icons that can be used throughout the interface.
<!-- Iconify/Custom in button (template) -->
<Button>
<template #icon>
<i-lucide:save />
<i class="icon-[lucide--save]" />
</template>
Save File
</Button>
Expand All @@ -88,8 +88,8 @@ ComfyUI supports three types of icons that can be used throughout the interface.

```vue
<template>
<i-lucide:eye v-if="isVisible" />
<i-lucide:eye-off v-else />
<i class="icon-[lucide--eye]" v-if="isVisible" />
<i class="icon-[lucide--eye-off]" v-else />
<!-- Or with ternary -->
<component :is="isLocked ? 'i-lucide:lock' : 'i-lucide:lock-open'" />
Expand All @@ -100,7 +100,7 @@ ComfyUI supports three types of icons that can be used throughout the interface.

```vue
<template>
<i-lucide:info
<i class="icon-[lucide--info]"
v-tooltip="'Click for more information'"
class="cursor-pointer"
/>
Expand Down Expand Up @@ -174,20 +174,20 @@ No imports needed - icons are auto-discovered!
```vue
<template>
<!-- Size with Tailwind classes -->
<i-lucide:plus class="w-4 h-4" />
<i class="icon-[lucide--plus]" class="w-4 h-4" />
<!-- 16px -->
<i-lucide:plus class="w-6 h-6" />
<i class="icon-[lucide--plus]" class="w-6 h-6" />
<!-- 24px (default) -->
<i-lucide:plus class="w-8 h-8" />
<i class="icon-[lucide--plus]" class="w-8 h-8" />
<!-- 32px -->
<!-- Or text size -->
<i-lucide:plus class="text-sm" />
<i-lucide:plus class="text-2xl" />
<i class="icon-[lucide--plus]" class="text-sm" />
<i class="icon-[lucide--plus]" class="text-2xl" />
<!-- Colors -->
<i-lucide:check class="text-green-500" />
<i-lucide:x class="text-red-500" />
<i class="icon-[lucide--check]" class="text-green-500" />
<i class="icon-[lucide--x]" class="text-red-500" />
</template>
```

Expand Down Expand Up @@ -219,7 +219,7 @@ Always use `currentColor` in SVGs for automatic theme adaptation:
<!-- After -->
<Button>
<template #icon>
<i-lucide:download />
<i class="icon-[lucide--download]" />
</template>
</Button>
</template>
Expand Down
10 changes: 0 additions & 10 deletions packages/design-system/tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,6 @@ import { addDynamicIconSelectors } from '@iconify/tailwind'
import { iconCollection } from './src/iconCollection'

export default {
content: [],
safelist: [
'icon-[lucide--folder]',
'icon-[lucide--package]',
'icon-[lucide--image]',
'icon-[lucide--video]',
'icon-[lucide--box]',
'icon-[lucide--audio-waveform]',
'icon-[lucide--message-circle]'
],
plugins: [
addDynamicIconSelectors({
iconSets: {
Expand Down
14 changes: 10 additions & 4 deletions src/components/actionbar/ComfyQueueButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@
@click="queuePrompt"
>
<template #icon>
<i-lucide:list-start v-if="workspaceStore.shiftDown" />
<i-lucide:play v-else-if="queueMode === 'disabled'" />
<i-lucide:fast-forward v-else-if="queueMode === 'instant'" />
<i-lucide:step-forward v-else-if="queueMode === 'change'" />
<i v-if="workspaceStore.shiftDown" class="icon-[lucide--list-start]" />
<i v-else-if="queueMode === 'disabled'" class="icon-[lucide--play]" />
<i
v-else-if="queueMode === 'instant'"
class="icon-[lucide--fast-forward]"
/>
<i
v-else-if="queueMode === 'change'"
class="icon-[lucide--step-forward]"
/>
</template>
<template #item="{ item }">
<Button
Expand Down
2 changes: 1 addition & 1 deletion src/components/button/MoreButton.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div class="relative inline-flex items-center">
<IconButton @click="toggle">
<i-lucide:more-vertical class="text-sm" />
<i class="icon-[lucide--more-vertical] text-sm" />
</IconButton>

<Popover
Expand Down
26 changes: 13 additions & 13 deletions src/components/custom/widget/WorkflowTemplateSelectorDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
@click="resetFilters"
>
<template #icon>
<i-lucide:filter-x />
<i class="icon-[lucide--filter-x]" />
</template>
</IconTextButton>
</div>
Expand All @@ -49,7 +49,7 @@
:show-clear-button="true"
>
<template #icon>
<i-lucide:cpu />
<i class="icon-[lucide--cpu]" />
</template>
</MultiSelect>

Expand All @@ -63,7 +63,7 @@
:show-clear-button="true"
>
<template #icon>
<i-lucide:target />
<i class="icon-[lucide--target]" />
</template>
</MultiSelect>

Expand All @@ -77,7 +77,7 @@
:show-clear-button="true"
>
<template #icon>
<i-lucide:file-text />
<i class="icon-[lucide--file-text]" />
</template>
</MultiSelect>

Expand All @@ -90,7 +90,7 @@
class="min-w-[270px]"
>
<template #icon>
<i-lucide:arrow-up-down />
<i class="icon-[lucide--arrow-up-down]" />
</template>
</SingleSelect>
</div>
Expand All @@ -111,7 +111,7 @@
v-if="!isLoading && filteredTemplates.length === 0"
class="flex flex-col items-center justify-center h-64 text-neutral-500"
>
<i-lucide:search class="w-12 h-12 mb-4 opacity-50" />
<i class="icon-[lucide--search] w-12 h-12 mb-4 opacity-50" />
<p class="text-lg mb-2">
{{ $t('templateWorkflows.noResults', 'No templates found') }}
</p>
Expand All @@ -128,7 +128,7 @@
<!-- Title -->
<span
v-if="isLoading"
class="inline-block h-8 w-48 bg-neutral-200 dark-theme:bg-neutral-700 rounded animate-pulse"
class="inline-block h-8 w-48 bg-dialog-surface rounded animate-pulse"
></span>

<!-- Template Cards Grid -->
Expand All @@ -148,7 +148,7 @@
<CardTop ratio="landscape">
<template #default>
<div
class="w-full h-full bg-neutral-200 dark-theme:bg-neutral-700 animate-pulse"
class="w-full h-full bg-dialog-surface animate-pulse"
></div>
</template>
</CardTop>
Expand All @@ -157,10 +157,10 @@
<CardBottom>
<div class="px-4 py-3">
<div
class="h-6 bg-neutral-200 dark-theme:bg-neutral-700 rounded animate-pulse mb-2"
class="h-6 bg-dialog-surface rounded animate-pulse mb-2"
></div>
<div
class="h-4 bg-neutral-200 dark-theme:bg-neutral-700 rounded animate-pulse"
class="h-4 bg-dialog-surface rounded animate-pulse"
></div>
</div>
</CardBottom>
Expand Down Expand Up @@ -323,7 +323,7 @@
<CardTop ratio="square">
<template #default>
<div
class="w-full h-full bg-neutral-200 dark-theme:bg-neutral-700 animate-pulse"
class="w-full h-full bg-dialog-surface animate-pulse"
></div>
</template>
</CardTop>
Expand All @@ -332,10 +332,10 @@
<CardBottom>
<div class="px-4 py-3">
<div
class="h-6 bg-neutral-200 dark-theme:bg-neutral-700 rounded animate-pulse mb-2"
class="h-6 bg-dialog-surface rounded animate-pulse mb-2"
></div>
<div
class="h-4 bg-neutral-200 dark-theme:bg-neutral-700 rounded animate-pulse"
class="h-4 bg-dialog-surface rounded animate-pulse"
></div>
</div>
</CardBottom>
Expand Down
Loading
Loading