@comfyorg/design-system 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/package.json +43 -0
- package/src/css/_palette.css +55 -0
- package/src/css/base.css +8 -0
- package/src/css/comfyIconSet.js +30 -0
- package/src/css/fonts.css +17 -0
- package/src/css/iconifyDynamicPlugin.ts +49 -0
- package/src/css/lucideStrokePlugin.js +88 -0
- package/src/css/style.css +1909 -0
- package/src/icons/3d-decomp.svg +3 -0
- package/src/icons/README.md +363 -0
- package/src/icons/ai-model.svg +1 -0
- package/src/icons/anthropic.svg +1 -0
- package/src/icons/batch-images-node.svg +3 -0
- package/src/icons/bfl.svg +10 -0
- package/src/icons/bria.svg +18 -0
- package/src/icons/brightness-contrast.svg +3 -0
- package/src/icons/bytedance.svg +13 -0
- package/src/icons/canny-to-image.svg +3 -0
- package/src/icons/canny-to-video.svg +3 -0
- package/src/icons/canny.svg +3 -0
- package/src/icons/channels.svg +5 -0
- package/src/icons/chromatic-aberration.svg +3 -0
- package/src/icons/claude.svg +1 -0
- package/src/icons/comfy-c.svg +4 -0
- package/src/icons/comfy-logo.svg +3 -0
- package/src/icons/credits.svg +3 -0
- package/src/icons/depth-to-image.svg +3 -0
- package/src/icons/depth-to-video.svg +3 -0
- package/src/icons/dial.svg +3 -0
- package/src/icons/elevenlabs.svg +1 -0
- package/src/icons/extensions-blocks.svg +1 -0
- package/src/icons/file-output.svg +3 -0
- package/src/icons/frames-to-video.svg +3 -0
- package/src/icons/gemini.svg +25 -0
- package/src/icons/get-video-components.svg +3 -0
- package/src/icons/glow.svg +4 -0
- package/src/icons/grain.svg +4 -0
- package/src/icons/grok.svg +10 -0
- package/src/icons/hitpaw.svg +10 -0
- package/src/icons/ideogram.svg +3 -0
- package/src/icons/image-ai-edit.svg +5 -0
- package/src/icons/image-batch.svg +3 -0
- package/src/icons/image-blur.svg +3 -0
- package/src/icons/image-canny.svg +3 -0
- package/src/icons/image-captioning.svg +3 -0
- package/src/icons/image-collage.svg +3 -0
- package/src/icons/image-compare.svg +3 -0
- package/src/icons/image-depth.svg +3 -0
- package/src/icons/image-edit.svg +3 -0
- package/src/icons/image-inpaint.svg +3 -0
- package/src/icons/image-invert.svg +3 -0
- package/src/icons/image-outpaint.svg +3 -0
- package/src/icons/image-outpainting.svg +3 -0
- package/src/icons/image-remove-background.svg +3 -0
- package/src/icons/image-rotate.svg +3 -0
- package/src/icons/image-select-object-segmentation.svg +3 -0
- package/src/icons/image-shader.svg +3 -0
- package/src/icons/image-sharpen.svg +3 -0
- package/src/icons/image-to-3d.svg +3 -0
- package/src/icons/image-to-image.svg +3 -0
- package/src/icons/image-to-layers.svg +3 -0
- package/src/icons/image-to-video.svg +3 -0
- package/src/icons/image-upscale.svg +3 -0
- package/src/icons/image-vectorize.svg +3 -0
- package/src/icons/kling.svg +38 -0
- package/src/icons/load-3d.svg +3 -0
- package/src/icons/load-audio.svg +3 -0
- package/src/icons/load-video.svg +3 -0
- package/src/icons/lora-loader.svg +3 -0
- package/src/icons/ltxv.svg +10 -0
- package/src/icons/luma.svg +35 -0
- package/src/icons/magnific.svg +14 -0
- package/src/icons/mask.svg +14 -0
- package/src/icons/meshy.svg +33 -0
- package/src/icons/minimax.svg +14 -0
- package/src/icons/moonvalley-marey.svg +18 -0
- package/src/icons/node.svg +1 -0
- package/src/icons/open-ai-chat-node.svg +3 -0
- package/src/icons/openai.svg +10 -0
- package/src/icons/pin.svg +4 -0
- package/src/icons/pixverse.svg +15 -0
- package/src/icons/play.svg +1 -0
- package/src/icons/pose-to-image.svg +3 -0
- package/src/icons/pose-to-video.svg +3 -0
- package/src/icons/quiver.svg +3 -0
- package/src/icons/recraft.svg +11 -0
- package/src/icons/reve.svg +10 -0
- package/src/icons/rodin.svg +18 -0
- package/src/icons/runway.svg +10 -0
- package/src/icons/save-3d.svg +3 -0
- package/src/icons/save-audio.svg +3 -0
- package/src/icons/save-video.svg +3 -0
- package/src/icons/send.svg +3 -0
- package/src/icons/sora.svg +9 -0
- package/src/icons/stability-ai.svg +15 -0
- package/src/icons/template.svg +1 -0
- package/src/icons/tencent.svg +23 -0
- package/src/icons/text-prompt-enhance.svg +3 -0
- package/src/icons/text-to-3d.svg +3 -0
- package/src/icons/text-to-audio.svg +5 -0
- package/src/icons/text-to-image.svg +3 -0
- package/src/icons/text-to-video.svg +3 -0
- package/src/icons/topaz.svg +10 -0
- package/src/icons/tripo.svg +16 -0
- package/src/icons/veo.svg +13 -0
- package/src/icons/video-captioning.svg +3 -0
- package/src/icons/video-edit.svg +3 -0
- package/src/icons/video-enhance.svg +3 -0
- package/src/icons/video-extract-frame.svg +3 -0
- package/src/icons/video-inpaint.svg +3 -0
- package/src/icons/video-interpolation.svg +3 -0
- package/src/icons/video-select-object-segmentation.svg +3 -0
- package/src/icons/video-slice.svg +3 -0
- package/src/icons/video-split-screen.svg +3 -0
- package/src/icons/video-trim.svg +3 -0
- package/src/icons/video-upscale.svg +3 -0
- package/src/icons/vidu.svg +24 -0
- package/src/icons/voice-clone.svg +3 -0
- package/src/icons/wan.svg +13 -0
- package/src/icons/wavespeed.svg +12 -0
- package/src/icons/workflow.svg +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@comfyorg/design-system",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Shared design system for ComfyUI Frontend",
|
|
5
|
+
"homepage": "https://comfy.org",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": {
|
|
8
|
+
"name": "Comfy Org",
|
|
9
|
+
"email": "support@comfy.org",
|
|
10
|
+
"url": "https://www.comfy.org"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/Comfy-Org/ComfyUI_frontend.git"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"src/css",
|
|
18
|
+
"src/icons"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"exports": {
|
|
22
|
+
"./css/*": "./src/css/*",
|
|
23
|
+
"./icons/*": "./src/icons/*"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@iconify-json/lucide": "^1.1.178",
|
|
30
|
+
"@iconify/tailwind4": "^1.2.3",
|
|
31
|
+
"@iconify/tools": "^5.0.3",
|
|
32
|
+
"@iconify/utils": "^3.1.0",
|
|
33
|
+
"tailwindcss-primeui": "^0.6.1",
|
|
34
|
+
"tw-animate-css": "^1.3.8"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"tailwindcss": "^4.3.2",
|
|
38
|
+
"typescript": "^6.0.3"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"typecheck": "tsc --noEmit"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
@theme {
|
|
2
|
+
/* Font Families */
|
|
3
|
+
--font-inter: 'Inter', sans-serif;
|
|
4
|
+
|
|
5
|
+
/* Palette Colors */
|
|
6
|
+
--color-charcoal-100: #55565e;
|
|
7
|
+
--color-charcoal-200: #494a50;
|
|
8
|
+
--color-charcoal-300: #3c3d42;
|
|
9
|
+
--color-charcoal-400: #313235;
|
|
10
|
+
--color-charcoal-500: #2d2e32;
|
|
11
|
+
--color-charcoal-600: #262729;
|
|
12
|
+
--color-charcoal-700: #202121;
|
|
13
|
+
--color-charcoal-800: #171718;
|
|
14
|
+
|
|
15
|
+
--color-neutral-550: #636363;
|
|
16
|
+
|
|
17
|
+
--color-ash-300: #bbbbbb;
|
|
18
|
+
--color-ash-500: #828282;
|
|
19
|
+
--color-ash-800: #444444;
|
|
20
|
+
|
|
21
|
+
--color-smoke-100: #f3f3f3;
|
|
22
|
+
--color-smoke-200: #e9e9e9;
|
|
23
|
+
--color-smoke-300: #e1e1e1;
|
|
24
|
+
--color-smoke-400: #d9d9d9;
|
|
25
|
+
--color-smoke-500: #c5c5c5;
|
|
26
|
+
--color-smoke-600: #b4b4b4;
|
|
27
|
+
--color-smoke-700: #a0a0a0;
|
|
28
|
+
--color-smoke-800: #8a8a8a;
|
|
29
|
+
|
|
30
|
+
/* Plum */
|
|
31
|
+
--color-plum-300: #afa3db;
|
|
32
|
+
--color-plum-400: #8d7fc5;
|
|
33
|
+
--color-plum-500: #6b5ca8;
|
|
34
|
+
--color-plum-600: #49378b;
|
|
35
|
+
|
|
36
|
+
/* Ink */
|
|
37
|
+
--color-ink-100: #5c5362;
|
|
38
|
+
--color-ink-200: #4f4754;
|
|
39
|
+
--color-ink-300: #413b45;
|
|
40
|
+
--color-ink-400: #353139;
|
|
41
|
+
--color-ink-500: #312c34;
|
|
42
|
+
--color-ink-600: #29252c;
|
|
43
|
+
--color-ink-700: #232025;
|
|
44
|
+
--color-ink-800: #19161a;
|
|
45
|
+
--color-ink-900: #151317;
|
|
46
|
+
|
|
47
|
+
--color-white: #ffffff;
|
|
48
|
+
--color-black: #000000;
|
|
49
|
+
|
|
50
|
+
/* Brand Colors */
|
|
51
|
+
--color-electric-400: #f0ff41;
|
|
52
|
+
--color-sapphire-700: #172dd7;
|
|
53
|
+
--color-brand-yellow: var(--color-electric-400);
|
|
54
|
+
--color-brand-blue: var(--color-sapphire-700);
|
|
55
|
+
}
|
package/src/css/base.css
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { cleanupSVG, importDirectorySync, runSVGO } from '@iconify/tools'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
|
|
4
|
+
export const COMFY_ICON_PREFIX = 'comfy'
|
|
5
|
+
|
|
6
|
+
const COMFY_ICONS_DIR = resolve(import.meta.dirname, '../icons')
|
|
7
|
+
|
|
8
|
+
let cached
|
|
9
|
+
|
|
10
|
+
export function loadComfyIconSet() {
|
|
11
|
+
if (cached) return cached
|
|
12
|
+
const iconSet = importDirectorySync(COMFY_ICONS_DIR)
|
|
13
|
+
iconSet.forEachSync((name, type) => {
|
|
14
|
+
if (type !== 'icon') return
|
|
15
|
+
const svg = iconSet.toSVG(name)
|
|
16
|
+
if (!svg) {
|
|
17
|
+
iconSet.remove(name)
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
cleanupSVG(svg)
|
|
22
|
+
runSVGO(svg)
|
|
23
|
+
iconSet.fromSVG(name, svg)
|
|
24
|
+
} catch {
|
|
25
|
+
iconSet.remove(name)
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
cached = iconSet.export()
|
|
29
|
+
return cached
|
|
30
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* Inter Font Family */
|
|
2
|
+
|
|
3
|
+
@font-face {
|
|
4
|
+
font-family: 'Inter';
|
|
5
|
+
src: url('/fonts/inter-latin-normal.woff2') format('woff2');
|
|
6
|
+
font-weight: 100 900;
|
|
7
|
+
font-style: normal;
|
|
8
|
+
font-display: swap;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@font-face {
|
|
12
|
+
font-family: 'Inter';
|
|
13
|
+
src: url('/fonts/inter-latin-italic.woff2') format('woff2');
|
|
14
|
+
font-weight: 100 900;
|
|
15
|
+
font-style: italic;
|
|
16
|
+
font-display: swap;
|
|
17
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { loadIconSet } from '@iconify/tailwind4/lib/helpers/loader.js'
|
|
2
|
+
import { getDynamicCSSRules } from '@iconify/tailwind4/lib/plugins/dynamic.js'
|
|
3
|
+
import { getIconsCSSData } from '@iconify/utils/lib/css/icons'
|
|
4
|
+
import { matchIconName } from '@iconify/utils/lib/icon/name'
|
|
5
|
+
import plugin from 'tailwindcss/plugin'
|
|
6
|
+
|
|
7
|
+
import { COMFY_ICON_PREFIX, loadComfyIconSet } from './comfyIconSet.js'
|
|
8
|
+
|
|
9
|
+
const SCALE = 1.2
|
|
10
|
+
|
|
11
|
+
const options = {
|
|
12
|
+
iconSets: { [COMFY_ICON_PREFIX]: loadComfyIconSet() },
|
|
13
|
+
scale: SCALE
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getModeCSSRules(icon: string, mode: 'mask' | 'background') {
|
|
17
|
+
const nameParts = icon.split(/--|:/)
|
|
18
|
+
if (nameParts.length !== 2) return {}
|
|
19
|
+
|
|
20
|
+
const [prefix, name] = nameParts
|
|
21
|
+
if (!(prefix.match(matchIconName) && name.match(matchIconName))) return {}
|
|
22
|
+
|
|
23
|
+
const iconSet =
|
|
24
|
+
prefix === COMFY_ICON_PREFIX ? loadComfyIconSet() : loadIconSet(prefix)
|
|
25
|
+
if (!iconSet) return {}
|
|
26
|
+
|
|
27
|
+
const generated = getIconsCSSData(iconSet, [name], {
|
|
28
|
+
iconSelector: '.icon',
|
|
29
|
+
mode
|
|
30
|
+
})
|
|
31
|
+
if (generated.css.length !== 1) return {}
|
|
32
|
+
|
|
33
|
+
const size = { width: `${SCALE}em`, height: `${SCALE}em` }
|
|
34
|
+
return { ...generated.common?.rules, ...size, ...generated.css[0].rules }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default plugin(({ matchComponents }) => {
|
|
38
|
+
matchComponents({
|
|
39
|
+
icon: (icon) => {
|
|
40
|
+
try {
|
|
41
|
+
return getDynamicCSSRules(icon, options)
|
|
42
|
+
} catch {
|
|
43
|
+
return {}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
'icon-img': (icon) => getModeCSSRules(icon, 'background'),
|
|
47
|
+
'icon-mask': (icon) => getModeCSSRules(icon, 'mask')
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { getIconsCSSData } from '@iconify/utils/lib/css/icons'
|
|
2
|
+
import { matchIconName } from '@iconify/utils/lib/icon/name'
|
|
3
|
+
import { loadIconSet } from '@iconify/tailwind4/lib/helpers/loader.js'
|
|
4
|
+
import plugin from 'tailwindcss/plugin'
|
|
5
|
+
|
|
6
|
+
import { COMFY_ICON_PREFIX, loadComfyIconSet } from './comfyIconSet.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Tailwind 4 plugin that provides icon variants with configurable
|
|
10
|
+
* stroke-width via class prefix. Supports lucide and comfy icon sets.
|
|
11
|
+
*
|
|
12
|
+
* Usage in CSS:
|
|
13
|
+
* @plugin "./lucideStrokePlugin.js";
|
|
14
|
+
*
|
|
15
|
+
* Usage in templates:
|
|
16
|
+
* <i class="icon-s1-[lucide--settings]" /> <!-- stroke-width: 1 -->
|
|
17
|
+
* <i class="icon-s1.5-[lucide--settings]" /> <!-- stroke-width: 1.5 -->
|
|
18
|
+
* <i class="icon-s2.5-[comfy--workflow]" /> <!-- stroke-width: 2.5 -->
|
|
19
|
+
*
|
|
20
|
+
* The plain `icon-[...]` class keeps each icon's native stroke-width.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const STROKE_WIDTHS = ['1', '1.3', '1.5', '2', '2.5']
|
|
24
|
+
|
|
25
|
+
const LUCIDE_PREFIX = 'lucide'
|
|
26
|
+
const SUPPORTED_PREFIXES = new Set([LUCIDE_PREFIX, COMFY_ICON_PREFIX])
|
|
27
|
+
|
|
28
|
+
const SCALE = 1.2
|
|
29
|
+
|
|
30
|
+
const STROKE_WIDTH_ATTR_RE = /stroke-width="[^"]*"/g
|
|
31
|
+
|
|
32
|
+
class InvalidIconProbeError extends Error {}
|
|
33
|
+
|
|
34
|
+
function resolveIconSet(prefix) {
|
|
35
|
+
if (prefix === COMFY_ICON_PREFIX) return loadComfyIconSet()
|
|
36
|
+
return loadIconSet(prefix)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getDynamicCSSRulesWithStroke(icon, strokeWidth) {
|
|
40
|
+
const nameParts = icon.split(/--|:/)
|
|
41
|
+
if (nameParts.length !== 2) {
|
|
42
|
+
throw new InvalidIconProbeError(`Invalid icon name: "${icon}"`)
|
|
43
|
+
}
|
|
44
|
+
const [prefix, name] = nameParts
|
|
45
|
+
if (!SUPPORTED_PREFIXES.has(prefix)) {
|
|
46
|
+
throw new InvalidIconProbeError(`Unsupported icon prefix: "${prefix}"`)
|
|
47
|
+
}
|
|
48
|
+
if (!(prefix.match(matchIconName) && name.match(matchIconName))) {
|
|
49
|
+
throw new InvalidIconProbeError(`Invalid icon name: "${icon}"`)
|
|
50
|
+
}
|
|
51
|
+
const iconSet = resolveIconSet(prefix)
|
|
52
|
+
if (!iconSet) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
`Cannot load icon set for "${prefix}". Install "@iconify-json/${prefix}" as dev dependency?`
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
const generated = getIconsCSSData(iconSet, [name], {
|
|
58
|
+
iconSelector: '.icon',
|
|
59
|
+
customise: (content) =>
|
|
60
|
+
content.replace(STROKE_WIDTH_ATTR_RE, `stroke-width="${strokeWidth}"`)
|
|
61
|
+
})
|
|
62
|
+
if (generated.css.length !== 1) {
|
|
63
|
+
throw new Error(`Cannot find "${icon}". Bad icon name?`)
|
|
64
|
+
}
|
|
65
|
+
if (SCALE && generated.common?.rules) {
|
|
66
|
+
generated.common.rules.height = SCALE + 'em'
|
|
67
|
+
generated.common.rules.width = SCALE + 'em'
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
...generated.common?.rules,
|
|
71
|
+
...generated.css[0].rules
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default plugin(({ matchComponents }) => {
|
|
76
|
+
for (const sw of STROKE_WIDTHS) {
|
|
77
|
+
matchComponents({
|
|
78
|
+
[`icon-s${sw}`]: (icon) => {
|
|
79
|
+
try {
|
|
80
|
+
return getDynamicCSSRulesWithStroke(icon, sw)
|
|
81
|
+
} catch (err) {
|
|
82
|
+
if (err instanceof InvalidIconProbeError) return {}
|
|
83
|
+
throw err
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
})
|