diff --git a/.gitignore b/.gitignore
index 6b4e1209a..0579796ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@ dist-ssr
*.njsproj
*.sln
*.sw?
+components.d.ts
# Ignore test data.
tests-ui/data/*
diff --git a/index.html b/index.html
index 75389940c..39dac8fe0 100644
--- a/index.html
+++ b/index.html
@@ -1,55 +1,55 @@
-
-
- ComfyUI
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ ComfyUI
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
index 4237f2ad9..eda5253b8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,6 +24,7 @@
"reflect-metadata": "^0.2.2",
"vue": "^3.4.31",
"vue-i18n": "^9.13.1",
+ "vue-router": "^4.4.3",
"zod": "^3.23.8",
"zod-validation-error": "^3.3.0"
},
@@ -31,6 +32,7 @@
"@babel/core": "^7.24.7",
"@babel/preset-env": "^7.22.20",
"@eslint/js": "^9.8.0",
+ "@iconify/json": "^2.2.245",
"@playwright/test": "^1.44.1",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.17.6",
@@ -59,6 +61,8 @@
"tsx": "^4.15.6",
"typescript": "^5.4.5",
"typescript-eslint": "^8.0.0",
+ "unplugin-icons": "^0.19.3",
+ "unplugin-vue-components": "^0.27.4",
"vite": "^5.2.0",
"vite-plugin-static-copy": "^1.0.5",
"vitest": "^2.0.5",
@@ -112,6 +116,28 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@antfu/install-pkg": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-0.4.1.tgz",
+ "integrity": "sha512-T7yB5QNG29afhWVkVq7XeIMBa5U/vs9mX69YqayXypPRmYzUmzwnYltplHmPtZ4HPCn+sQKeXW8I47wCbuBOjw==",
+ "dev": true,
+ "dependencies": {
+ "package-manager-detector": "^0.2.0",
+ "tinyexec": "^0.3.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@antfu/utils": {
+ "version": "0.7.10",
+ "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz",
+ "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
"node_modules/@atlaskit/pragmatic-drag-and-drop": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@atlaskit/pragmatic-drag-and-drop/-/pragmatic-drag-and-drop-1.2.1.tgz",
@@ -2414,6 +2440,37 @@
"url": "https://github.com/sponsors/nzakas"
}
},
+ "node_modules/@iconify/json": {
+ "version": "2.2.245",
+ "resolved": "https://registry.npmjs.org/@iconify/json/-/json-2.2.245.tgz",
+ "integrity": "sha512-JbruddbGKghBe6fE1mzuo5hhUkisIW4mAdQGAyx0Q6sI52ukeQJHakolc2RQD/yWC3xp7rARNXMzWSXJynJ1vw==",
+ "dev": true,
+ "dependencies": {
+ "@iconify/types": "*",
+ "pathe": "^1.1.2"
+ }
+ },
+ "node_modules/@iconify/types": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
+ "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
+ "dev": true
+ },
+ "node_modules/@iconify/utils": {
+ "version": "2.1.32",
+ "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.1.32.tgz",
+ "integrity": "sha512-LeifFZPPKu28O3AEDpYJNdEbvS4/ojAPyIW+pF/vUpJTYnbTiXUHkCh0bwgFRzKvdpb8H4Fbfd/742++MF4fPQ==",
+ "dev": true,
+ "dependencies": {
+ "@antfu/install-pkg": "^0.4.0",
+ "@antfu/utils": "^0.7.10",
+ "@iconify/types": "^2.0.0",
+ "debug": "^4.3.6",
+ "kolorist": "^1.8.0",
+ "local-pkg": "^0.5.0",
+ "mlly": "^1.7.1"
+ }
+ },
"node_modules/@intlify/core-base": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.13.1.tgz",
@@ -3237,9 +3294,9 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.4.15",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
- "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
@@ -3380,6 +3437,28 @@
"node": ">=12.11.0"
}
},
+ "node_modules/@rollup/pluginutils": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
+ "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.18.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
@@ -5327,6 +5406,12 @@
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
+ "node_modules/confbox": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz",
+ "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==",
+ "dev": true
+ },
"node_modules/config-chain": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
@@ -5544,12 +5629,12 @@
}
},
"node_modules/debug": {
- "version": "4.3.5",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
- "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dev": true,
"dependencies": {
- "ms": "2.1.2"
+ "ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
@@ -9024,6 +9109,12 @@
"node": ">=6"
}
},
+ "node_modules/kolorist": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
+ "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
+ "dev": true
+ },
"node_modules/leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -9252,6 +9343,22 @@
"node": ">=18.0.0"
}
},
+ "node_modules/local-pkg": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz",
+ "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==",
+ "dev": true,
+ "dependencies": {
+ "mlly": "^1.4.2",
+ "pkg-types": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -9409,11 +9516,11 @@
}
},
"node_modules/magic-string": {
- "version": "0.30.10",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz",
- "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==",
+ "version": "0.30.11",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
+ "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==",
"dependencies": {
- "@jridgewell/sourcemap-codec": "^1.4.15"
+ "@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/make-dir": {
@@ -9542,10 +9649,22 @@
"node": ">=16 || 14 >=14.17"
}
},
+ "node_modules/mlly": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz",
+ "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.11.3",
+ "pathe": "^1.1.2",
+ "pkg-types": "^1.1.1",
+ "ufo": "^1.5.3"
+ }
+ },
"node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
"node_modules/mz": {
@@ -9776,6 +9895,12 @@
"integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==",
"dev": true
},
+ "node_modules/package-manager-detector": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.0.tgz",
+ "integrity": "sha512-E385OSk9qDcXhcM9LNSe4sdhx8a9mAPrZ4sMLW+tmxl5ZuGtPUcdFu+MPP2jbgiWAZ6Pfe5soGFMd+0Db5Vrog==",
+ "dev": true
+ },
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
@@ -10019,6 +10144,17 @@
"node": ">=8"
}
},
+ "node_modules/pkg-types": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.0.tgz",
+ "integrity": "sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==",
+ "dev": true,
+ "dependencies": {
+ "confbox": "^0.1.7",
+ "mlly": "^1.7.1",
+ "pathe": "^1.1.2"
+ }
+ },
"node_modules/playwright": {
"version": "1.45.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.1.tgz",
@@ -11207,6 +11343,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/tinyexec": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.0.tgz",
+ "integrity": "sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==",
+ "dev": true
+ },
"node_modules/tinypool": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz",
@@ -11541,6 +11683,12 @@
}
}
},
+ "node_modules/ufo": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",
+ "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==",
+ "dev": true
+ },
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
@@ -11596,6 +11744,130 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/unplugin": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.13.1.tgz",
+ "integrity": "sha512-6Kq1iSSwg7KyjcThRUks9LuqDAKvtnioxbL9iEtB9ctTyBA5OmrB8gZd/d225VJu1w3UpUsKV7eGrvf59J7+VA==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.12.1",
+ "webpack-virtual-modules": "^0.6.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "webpack-sources": "^3"
+ },
+ "peerDependenciesMeta": {
+ "webpack-sources": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/unplugin-icons": {
+ "version": "0.19.3",
+ "resolved": "https://registry.npmjs.org/unplugin-icons/-/unplugin-icons-0.19.3.tgz",
+ "integrity": "sha512-EUegRmsAI6+rrYr0vXjFlIP+lg4fSC4zb62zAZKx8FGXlWAGgEGBCa3JDe27aRAXhistObLPbBPhwa/0jYLFkQ==",
+ "dev": true,
+ "dependencies": {
+ "@antfu/install-pkg": "^0.4.1",
+ "@antfu/utils": "^0.7.10",
+ "@iconify/utils": "^2.1.29",
+ "debug": "^4.3.6",
+ "kolorist": "^1.8.0",
+ "local-pkg": "^0.5.0",
+ "unplugin": "^1.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@svgr/core": ">=7.0.0",
+ "@svgx/core": "^1.0.1",
+ "@vue/compiler-sfc": "^3.0.2 || ^2.7.0",
+ "vue-template-compiler": "^2.6.12",
+ "vue-template-es2015-compiler": "^1.9.0"
+ },
+ "peerDependenciesMeta": {
+ "@svgr/core": {
+ "optional": true
+ },
+ "@svgx/core": {
+ "optional": true
+ },
+ "@vue/compiler-sfc": {
+ "optional": true
+ },
+ "vue-template-compiler": {
+ "optional": true
+ },
+ "vue-template-es2015-compiler": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/unplugin-vue-components": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.27.4.tgz",
+ "integrity": "sha512-1XVl5iXG7P1UrOMnaj2ogYa5YTq8aoh5jwDPQhemwO/OrXW+lPQKDXd1hMz15qxQPxgb/XXlbgo3HQ2rLEbmXQ==",
+ "dev": true,
+ "dependencies": {
+ "@antfu/utils": "^0.7.10",
+ "@rollup/pluginutils": "^5.1.0",
+ "chokidar": "^3.6.0",
+ "debug": "^4.3.6",
+ "fast-glob": "^3.3.2",
+ "local-pkg": "^0.5.0",
+ "magic-string": "^0.30.11",
+ "minimatch": "^9.0.5",
+ "mlly": "^1.7.1",
+ "unplugin": "^1.12.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@babel/parser": "^7.15.8",
+ "@nuxt/kit": "^3.2.2",
+ "vue": "2 || 3"
+ },
+ "peerDependenciesMeta": {
+ "@babel/parser": {
+ "optional": true
+ },
+ "@nuxt/kit": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/unplugin-vue-components/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/unplugin-vue-components/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/update-browserslist-db": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
@@ -12108,6 +12380,20 @@
"vue": "^3.0.0"
}
},
+ "node_modules/vue-router": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.3.tgz",
+ "integrity": "sha512-sv6wmNKx2j3aqJQDMxLFzs/u/mjA9Z5LCgy6BE0f7yFWMjrPLnS/sPNn8ARY/FXw6byV18EFutn5lTO6+UsV5A==",
+ "dependencies": {
+ "@vue/devtools-api": "^6.6.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "vue": "^3.2.0"
+ }
+ },
"node_modules/w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
@@ -12138,6 +12424,12 @@
"node": ">=12"
}
},
+ "node_modules/webpack-virtual-modules": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
+ "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
+ "dev": true
+ },
"node_modules/whatwg-encoding": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
diff --git a/package.json b/package.json
index b80d57144..a4abea1e2 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
"@babel/core": "^7.24.7",
"@babel/preset-env": "^7.22.20",
"@eslint/js": "^9.8.0",
+ "@iconify/json": "^2.2.245",
"@playwright/test": "^1.44.1",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.17.6",
@@ -52,6 +53,8 @@
"tsx": "^4.15.6",
"typescript": "^5.4.5",
"typescript-eslint": "^8.0.0",
+ "unplugin-icons": "^0.19.3",
+ "unplugin-vue-components": "^0.27.4",
"vite": "^5.2.0",
"vite-plugin-static-copy": "^1.0.5",
"vitest": "^2.0.5",
@@ -74,6 +77,7 @@
"reflect-metadata": "^0.2.2",
"vue": "^3.4.31",
"vue-i18n": "^9.13.1",
+ "vue-router": "^4.4.3",
"zod": "^3.23.8",
"zod-validation-error": "^3.3.0"
},
diff --git a/src/App.vue b/src/App.vue
index c8b249fba..e3534e3b2 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,10 +1,10 @@
+
-
diff --git a/src/views/layouts/LayoutDefault.vue b/src/views/layouts/LayoutDefault.vue
new file mode 100644
index 000000000..331f71a38
--- /dev/null
+++ b/src/views/layouts/LayoutDefault.vue
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/tailwind.config.js b/tailwind.config.js
index 956bbf460..4eaa6ac82 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,11 +1,182 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
+
corePlugins: {
preflight: false // This disables Tailwind's base styles
},
+
theme: {
- extend: {}
+ fontSize: {
+ xs: '0.75rem',
+ sm: '0.875rem',
+ base: '1rem',
+ lg: '1.125rem',
+ xl: '1.25rem',
+ '2xl': '1.5rem',
+ '3xl': '1.875rem',
+ '4xl': '2.25rem',
+ '5xl': '3rem',
+ '6xl': '4rem'
+ },
+
+ screens: {
+ sm: '640px',
+ md: '768px',
+ lg: '1024px',
+ xl: '1280px',
+ '2xl': '1536px',
+ '3xl': '1800px',
+ '4xl': '2500px',
+ '5xl': '3200px'
+ },
+
+ spacing: {
+ px: '1px',
+ 0: '0px',
+ 0.5: '0.125rem',
+ 1: '0.25rem',
+ 1.5: '0.375rem',
+ 2: '0.5rem',
+ 2.5: '0.625rem',
+ 3: '0.75rem',
+ 3.5: '0.875rem',
+ 4: '1rem',
+ 4.5: '1.125rem',
+ 5: '1.25rem',
+ 6: '1.5rem',
+ 7: '1.75rem',
+ 8: '2rem',
+ 9: '2.25rem',
+ 10: '2.5rem',
+ 11: '2.75rem',
+ 12: '3rem',
+ 14: '3.5rem',
+ 16: '4rem',
+ 18: '4.5rem',
+ 20: '5rem',
+ 24: '6rem',
+ 28: '7rem',
+ 32: '8rem',
+ 36: '9rem',
+ 40: '10rem',
+ 44: '11rem',
+ 48: '12rem',
+ 52: '13rem',
+ 56: '14rem',
+ 60: '15rem',
+ 64: '16rem',
+ 72: '18rem',
+ 80: '20rem',
+ 84: '22rem',
+ 90: '24rem',
+ 96: '26rem',
+ 100: '28rem',
+ 110: '32rem'
+ },
+
+ extend: {
+ colors: {
+ zinc: {
+ 50: '#fafafa',
+ 100: '#f4f4f5',
+ 200: '#e4e4e7',
+ 300: '#d4d4d8',
+ 400: '#a1a1aa',
+ 500: '#71717a',
+ 600: '#52525b',
+ 700: '#3f3f46',
+ 800: '#27272a',
+ 900: '#18181b',
+ 950: '#09090b'
+ },
+
+ gray: {
+ 50: '#f8fbfc',
+ 100: '#f3f6fa',
+ 200: '#edf2f7',
+ 300: '#e2e8f0',
+ 400: '#cbd5e0',
+ 500: '#a0aec0',
+ 600: '#718096',
+ 700: '#4a5568',
+ 800: '#2d3748',
+ 900: '#1a202c',
+ 950: '#0a1016'
+ },
+
+ teal: {
+ 50: '#f0fdfa',
+ 100: '#e0fcff',
+ 200: '#bef8fd',
+ 300: '#87eaf2',
+ 400: '#54d1db',
+ 500: '#38bec9',
+ 600: '#2cb1bc',
+ 700: '#14919b',
+ 800: '#0e7c86',
+ 900: '#005860',
+ 950: '#022c28'
+ },
+
+ blue: {
+ 50: '#eff6ff',
+ 100: '#ebf8ff',
+ 200: '#bee3f8',
+ 300: '#90cdf4',
+ 400: '#63b3ed',
+ 500: '#4299e1',
+ 600: '#3182ce',
+ 700: '#2b6cb0',
+ 800: '#2c5282',
+ 900: '#2a4365',
+ 950: '#172554'
+ },
+
+ green: {
+ 50: '#fcfff5',
+ 100: '#fafff3',
+ 200: '#eaf9c9',
+ 300: '#d1efa0',
+ 400: '#b2e16e',
+ 500: '#96ce4c',
+ 600: '#7bb53d',
+ 700: '#649934',
+ 800: '#507b2e',
+ 900: '#456829',
+ 950: '#355819'
+ },
+
+ fuchsia: {
+ 50: '#fdf4ff',
+ 100: '#fae8ff',
+ 200: '#f5d0fe',
+ 300: '#f0abfc',
+ 400: '#e879f9',
+ 500: '#d946ef',
+ 600: '#c026d3',
+ 700: '#a21caf',
+ 800: '#86198f',
+ 900: '#701a75',
+ 950: '#4a044e'
+ },
+
+ orange: {
+ 50: '#fff7ed',
+ 100: '#ffedd5',
+ 200: '#fedbb8',
+ 300: '#fbd38d',
+ 400: '#f6ad55',
+ 500: '#ed8936',
+ 600: '#dd6b20',
+ 700: '#c05621',
+ 800: '#9c4221',
+ 900: '#7b341e',
+ 950: '#431407'
+ }
+ }
+ }
},
+
plugins: []
}
diff --git a/vite.config.mts b/vite.config.mts
index 9c1edf3b5..b201251c9 100644
--- a/vite.config.mts
+++ b/vite.config.mts
@@ -1,92 +1,95 @@
-import { defineConfig, Plugin } from 'vite';
-import type { UserConfigExport } from 'vitest/config';
-import vue from '@vitejs/plugin-vue';
-import path from 'path';
-import dotenv from "dotenv";
-dotenv.config();
+import { defineConfig, Plugin } from 'vite'
+import type { UserConfigExport } from 'vitest/config'
+import vue from '@vitejs/plugin-vue'
+import path from 'path'
+import dotenv from "dotenv"
+import Icons from 'unplugin-icons/vite'
+import IconsResolver from 'unplugin-icons/resolver'
+import Components from 'unplugin-vue-components/vite'
-const IS_DEV = process.env.NODE_ENV === 'development';
-const SHOULD_MINIFY = process.env.ENABLE_MINIFY === 'true';
+dotenv.config()
+
+const IS_DEV = process.env.NODE_ENV === 'development'
+const SHOULD_MINIFY = process.env.ENABLE_MINIFY === 'true'
interface ShimResult {
- code: string;
- exports: string[];
+ code: string
+ exports: string[]
}
function isLegacyFile(id: string): boolean {
return id.endsWith('.ts') && (
id.includes("src/extensions/core") ||
id.includes("src/scripts")
- );
+ )
}
function comfyAPIPlugin(): Plugin {
return {
name: 'comfy-api-plugin',
transform(code: string, id: string) {
- if (IS_DEV)
- return null;
+ if (IS_DEV) return null
if (isLegacyFile(id)) {
- const result = transformExports(code, id);
+ const result = transformExports(code, id)
if (result.exports.length > 0) {
- const projectRoot = process.cwd();
- const relativePath = path.relative(path.join(projectRoot, 'src'), id);
- const shimFileName = relativePath.replace(/\.ts$/, '.js');
+ const projectRoot = process.cwd()
+ const relativePath = path.relative(path.join(projectRoot, 'src'), id)
+ const shimFileName = relativePath.replace(/\.ts$/, '.js')
- const shimComment = `// Shim for ${relativePath}\n`;
+ const shimComment = `// Shim for ${relativePath}\n`
this.emitFile({
type: "asset",
fileName: shimFileName,
- source: shimComment + result.exports.join(""),
- });
+ source: shimComment + result.exports.join("")
+ })
}
return {
code: result.code,
map: null // If you're not modifying the source map, return null
- };
+ }
}
}
- };
+ }
}
function transformExports(code: string, id: string): ShimResult {
- const moduleName = getModuleName(id);
- const exports: string[] = [];
- let newCode = code;
+ const moduleName = getModuleName(id)
+ const exports: string[] = []
+ let newCode = code
// Regex to match different types of exports
- const regex = /export\s+(const|let|var|function|class|async function)\s+([a-zA-Z$_][a-zA-Z\d$_]*)(\s|\()/g;
- let match;
+ const regex = /export\s+(const|let|var|function|class|async function)\s+([a-zA-Z$_][a-zA-Z\d$_]*)(\s|\()/g
+ let match
while ((match = regex.exec(code)) !== null) {
- const name = match[2];
+ const name = match[2]
// All exports should be bind to the window object as new API endpoint.
if (exports.length == 0) {
- newCode += `\nwindow.comfyAPI = window.comfyAPI || {};`;
- newCode += `\nwindow.comfyAPI.${moduleName} = window.comfyAPI.${moduleName} || {};`;
+ newCode += `\nwindow.comfyAPI = window.comfyAPI || {};`
+ newCode += `\nwindow.comfyAPI.${moduleName} = window.comfyAPI.${moduleName} || {};`
}
- newCode += `\nwindow.comfyAPI.${moduleName}.${name} = ${name};`;
- exports.push(`export const ${name} = window.comfyAPI.${moduleName}.${name};\n`);
+ newCode += `\nwindow.comfyAPI.${moduleName}.${name} = ${name};`
+ exports.push(`export const ${name} = window.comfyAPI.${moduleName}.${name};\n`)
}
return {
code: newCode,
- exports,
- };
+ exports
+ }
}
function getModuleName(id: string): string {
// Simple example to derive a module name from the file path
- const parts = id.split('/');
- const fileName = parts[parts.length - 1];
- return fileName.replace(/\.\w+$/, ''); // Remove file extension
+ const parts = id.split('/')
+ const fileName = parts[parts.length - 1]
+ return fileName.replace(/\.\w+$/, '') // Remove file extension
}
-const DEV_SERVER_COMFYUI_URL = process.env.DEV_SERVER_COMFYUI_URL || 'http://127.0.0.1:8188';
+const DEV_SERVER_COMFYUI_URL = process.env.DEV_SERVER_COMFYUI_URL || 'http://127.0.0.1:8188'
export default defineConfig({
base: '',
@@ -95,27 +98,43 @@ export default defineConfig({
'/internal': {
target: DEV_SERVER_COMFYUI_URL,
},
+
'/api': {
target: DEV_SERVER_COMFYUI_URL,
// Return empty array for extensions API as these modules
// are not on vite's dev server.
bypass: (req, res, options) => {
if (req.url === '/api/extensions') {
- res.end(JSON.stringify([]));
+ res.end(JSON.stringify([]))
}
- return null;
+ return null
},
},
+
'/ws': {
target: DEV_SERVER_COMFYUI_URL,
- ws: true,
- },
+ ws: true
+ }
}
},
+
plugins: [
vue(),
comfyAPIPlugin(),
+
+ Icons({
+ 'compiler': 'vue3'
+ }),
+
+ Components({
+ dts: true,
+ resolvers: [IconsResolver()],
+ dirs: ['src/components', 'src/layout', 'src/views'],
+ deep: true,
+ extensions: ['vue']
+ })
],
+
build: {
minify: SHOULD_MINIFY ? 'esbuild' : false,
target: 'es2022',
@@ -126,23 +145,27 @@ export default defineConfig({
treeshake: false
}
},
+
esbuild: {
minifyIdentifiers: false,
keepNames: true,
minifySyntax: SHOULD_MINIFY,
- minifyWhitespace: SHOULD_MINIFY,
+ minifyWhitespace: SHOULD_MINIFY
},
+
test: {
globals: true,
environment: 'happy-dom',
- setupFiles: ['./vitest.setup.ts'],
+ setupFiles: ['./vitest.setup.ts']
},
+
define: {
- '__COMFYUI_FRONTEND_VERSION__': JSON.stringify(process.env.npm_package_version),
+ '__COMFYUI_FRONTEND_VERSION__': JSON.stringify(process.env.npm_package_version)
},
+
resolve: {
alias: {
'@': '/src'
}
}
-}) as UserConfigExport;
+}) as UserConfigExport