mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2025-01-11 10:25:16 +00:00
Color palette setting
This commit is contained in:
parent
d3a375c8fb
commit
4b9e11053c
351
web/extensions/core/colorPalette.js
Normal file
351
web/extensions/core/colorPalette.js
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
import { app } from "/scripts/app.js";
|
||||||
|
import { $el } from "/scripts/ui.js";
|
||||||
|
import { api } from "/scripts/api.js";
|
||||||
|
|
||||||
|
// Manage color palettes
|
||||||
|
|
||||||
|
const colorPalettes = {
|
||||||
|
"palette_1": {
|
||||||
|
"id": "palette_1",
|
||||||
|
"name": "Palette 1",
|
||||||
|
"colors": {
|
||||||
|
"node_slot": {
|
||||||
|
"CLIP": "#FFD500", // bright yellow
|
||||||
|
"CLIP_VISION": "#A8DADC", // light blue-gray
|
||||||
|
"CLIP_VISION_OUTPUT": "#ad7452", // rusty brown-orange
|
||||||
|
"CONDITIONING": "#FFA931", // vibrant orange-yellow
|
||||||
|
"CONTROL_NET": "#6EE7B7", // soft mint green
|
||||||
|
"IMAGE": "#64B5F6", // bright sky blue
|
||||||
|
"LATENT": "#FF9CF9", // light pink-purple
|
||||||
|
"MASK": "#81C784", // muted green
|
||||||
|
"MODEL": "#B39DDB", // light lavender-purple
|
||||||
|
"STYLE_MODEL": "#C2FFAE", // light green-yellow
|
||||||
|
"VAE": "#FF6E6E", // bright red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"palette_2": {
|
||||||
|
"id": "palette_2",
|
||||||
|
"name": "Palette 2",
|
||||||
|
"colors": {
|
||||||
|
"node_slot": {
|
||||||
|
"CLIP": "#556B2F", // Dark Olive Green
|
||||||
|
"CLIP_VISION": "#4B0082", // Indigo
|
||||||
|
"CLIP_VISION_OUTPUT": "#006400", // Green
|
||||||
|
"CONDITIONING": "#FF1493", // Deep Pink
|
||||||
|
"CONTROL_NET": "#8B4513", // Saddle Brown
|
||||||
|
"IMAGE": "#8B0000", // Dark Red
|
||||||
|
"LATENT": "#00008B", // Dark Blue
|
||||||
|
"MASK": "#2F4F4F", // Dark Slate Grey
|
||||||
|
"MODEL": "#FF8C00", // Dark Orange
|
||||||
|
"STYLE_MODEL": "#004A4A", // Sherpa Blue
|
||||||
|
"UPSCALE_MODEL": "#4A004A", // Tyrian Purple
|
||||||
|
"VAE": "#4F394F", // Loulou
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const id = "Comfy.ColorPalette";
|
||||||
|
const idCustomColorPalettes = "Comfy.CustomColorPalettes";
|
||||||
|
const defaultColorPaletteId = "palette_1";
|
||||||
|
const els = {}
|
||||||
|
// const ctxMenu = LiteGraph.ContextMenu;
|
||||||
|
app.registerExtension({
|
||||||
|
name: id,
|
||||||
|
init() {
|
||||||
|
const sortObjectKeys = (unordered) => {
|
||||||
|
return Object.keys(unordered).sort().reduce((obj, key) => {
|
||||||
|
obj[key] = unordered[key];
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSlotTypes = async () => {
|
||||||
|
var types = [];
|
||||||
|
|
||||||
|
const defs = await api.getNodeDefs();
|
||||||
|
for (const nodeId in defs) {
|
||||||
|
const nodeData = defs[nodeId];
|
||||||
|
|
||||||
|
var inputs = nodeData["input"]["required"];
|
||||||
|
if (nodeData["input"]["optional"] != undefined){
|
||||||
|
inputs = Object.assign({}, nodeData["input"]["required"], nodeData["input"]["optional"])
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const inputName in inputs) {
|
||||||
|
const inputData = inputs[inputName];
|
||||||
|
const type = inputData[0];
|
||||||
|
|
||||||
|
if (!Array.isArray(type)) {
|
||||||
|
types.push(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const o in nodeData["output"]) {
|
||||||
|
const output = nodeData["output"][o];
|
||||||
|
types.push(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return types;
|
||||||
|
};
|
||||||
|
|
||||||
|
const completeColorPalette = async (colorPalette) => {
|
||||||
|
var types = await getSlotTypes();
|
||||||
|
|
||||||
|
for (const type of types) {
|
||||||
|
if (!colorPalette.colors.node_slot[type]) {
|
||||||
|
colorPalette.colors.node_slot[type] = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
colorPalette.colors.node_slot = sortObjectKeys(colorPalette.colors.node_slot);
|
||||||
|
|
||||||
|
return colorPalette;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getColorPaletteTemplate = async () => {
|
||||||
|
let colorPalette = {
|
||||||
|
"id": "my_color_palette_unique_id",
|
||||||
|
"name": "My Color Palette",
|
||||||
|
"colors": {
|
||||||
|
"node_slot": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return completeColorPalette(colorPalette);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCustomColorPalettes = () => {
|
||||||
|
return app.ui.settings.getSettingValue(idCustomColorPalettes, {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setCustomColorPalettes = (customColorPalettes) => {
|
||||||
|
return app.ui.settings.setSettingValue(idCustomColorPalettes, customColorPalettes);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addCustomColorPalette = async (colorPalette) => {
|
||||||
|
if (typeof(colorPalette) !== "object") {
|
||||||
|
app.ui.dialog.show("Invalid color palette");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!colorPalette.id) {
|
||||||
|
app.ui.dialog.show("Color palette missing id");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!colorPalette.name) {
|
||||||
|
app.ui.dialog.show("Color palette missing name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!colorPalette.colors) {
|
||||||
|
app.ui.dialog.show("Color palette missing colors");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colorPalette.colors.node_slot && typeof(colorPalette.colors.node_slot) !== "object") {
|
||||||
|
app.ui.dialog.show("Invalid color palette colors.node_slot");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let customColorPalettes = getCustomColorPalettes();
|
||||||
|
customColorPalettes[colorPalette.id] = colorPalette;
|
||||||
|
setCustomColorPalettes(customColorPalettes);
|
||||||
|
|
||||||
|
for (const option of els.select.childNodes) {
|
||||||
|
if (option.value === "custom_" + colorPalette.id) {
|
||||||
|
els.select.removeChild(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
els.select.append($el("option", { textContent: colorPalette.name + " (custom)", value: "custom_" + colorPalette.id, selected: true }));
|
||||||
|
|
||||||
|
setColorPalette("custom_" + colorPalette.id);
|
||||||
|
await loadColorPalette(colorPalette);
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteCustomColorPalette = async (colorPaletteId) => {
|
||||||
|
let customColorPalettes = getCustomColorPalettes();
|
||||||
|
delete customColorPalettes[colorPaletteId];
|
||||||
|
setCustomColorPalettes(customColorPalettes);
|
||||||
|
|
||||||
|
for (const option of els.select.childNodes) {
|
||||||
|
if (option.value === defaultColorPaletteId) {
|
||||||
|
option.selected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option.value === "custom_" + colorPaletteId) {
|
||||||
|
els.select.removeChild(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setColorPalette(defaultColorPaletteId);
|
||||||
|
await loadColorPalette(getColorPalette());
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadColorPalette = async (colorPalette) => {
|
||||||
|
colorPalette = await completeColorPalette(colorPalette);
|
||||||
|
if (colorPalette.colors) {
|
||||||
|
if (colorPalette.colors.node_slot) {
|
||||||
|
Object.assign(app.canvas.default_connection_color_byType, colorPalette.colors.node_slot);
|
||||||
|
app.canvas.draw(true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getColorPalette = (colorPaletteId) => {
|
||||||
|
if (!colorPaletteId) {
|
||||||
|
colorPaletteId = app.ui.settings.getSettingValue(id, defaultColorPaletteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colorPaletteId.startsWith("custom_")) {
|
||||||
|
colorPaletteId = colorPaletteId.substr(7);
|
||||||
|
let customColorPalettes = getCustomColorPalettes();
|
||||||
|
if (customColorPalettes[colorPaletteId]) {
|
||||||
|
return customColorPalettes[colorPaletteId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return colorPalettes[colorPaletteId];
|
||||||
|
};
|
||||||
|
|
||||||
|
const setColorPalette = (colorPaletteId) => {
|
||||||
|
app.ui.settings.setSettingValue(id, colorPaletteId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fileInput = $el("input", {
|
||||||
|
type: "file",
|
||||||
|
accept: ".json",
|
||||||
|
style: { display: "none" },
|
||||||
|
parent: document.body,
|
||||||
|
onchange: () => {
|
||||||
|
let file = fileInput.files[0];
|
||||||
|
|
||||||
|
if (file.type === "application/json" || file.name.endsWith(".json")) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = async () => {
|
||||||
|
await addCustomColorPalette(JSON.parse(reader.result));
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
app.ui.settings.addSetting({
|
||||||
|
id,
|
||||||
|
name: "Color Palette",
|
||||||
|
type: (name, setter, value) => {
|
||||||
|
let options = [];
|
||||||
|
|
||||||
|
for (const c in colorPalettes) {
|
||||||
|
const colorPalette = colorPalettes[c];
|
||||||
|
options.push($el("option", { textContent: colorPalette.name, value: colorPalette.id, selected: colorPalette.id === value }));
|
||||||
|
}
|
||||||
|
|
||||||
|
let customColorPalettes = getCustomColorPalettes();
|
||||||
|
for (const c in customColorPalettes) {
|
||||||
|
const colorPalette = customColorPalettes[c];
|
||||||
|
options.push($el("option", { textContent: colorPalette.name + " (custom)", value: "custom_" + colorPalette.id, selected: "custom_" + colorPalette.id === value }));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $el("div", [
|
||||||
|
$el("label", { textContent: name || id }, [
|
||||||
|
els.select = $el("select", {
|
||||||
|
onchange: (e) => {
|
||||||
|
setter(e.target.value);
|
||||||
|
}
|
||||||
|
}, options)
|
||||||
|
]),
|
||||||
|
$el("input", {
|
||||||
|
type: "button",
|
||||||
|
value: "Export",
|
||||||
|
onclick: async () => {
|
||||||
|
const colorPaletteId = app.ui.settings.getSettingValue(id, defaultColorPaletteId);
|
||||||
|
const colorPalette = await completeColorPalette(getColorPalette(colorPaletteId));
|
||||||
|
const json = JSON.stringify(colorPalette, null, 2); // convert the data to a JSON string
|
||||||
|
const blob = new Blob([json], { type: "application/json" });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = $el("a", {
|
||||||
|
href: url,
|
||||||
|
download: colorPaletteId + ".json",
|
||||||
|
style: { display: "none" },
|
||||||
|
parent: document.body,
|
||||||
|
});
|
||||||
|
a.click();
|
||||||
|
setTimeout(function () {
|
||||||
|
a.remove();
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
$el("input", {
|
||||||
|
type: "button",
|
||||||
|
value: "Import",
|
||||||
|
onclick: () => {
|
||||||
|
fileInput.click();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
$el("input", {
|
||||||
|
type: "button",
|
||||||
|
value: "Template",
|
||||||
|
onclick: async () => {
|
||||||
|
const colorPalette = await getColorPaletteTemplate();
|
||||||
|
const json = JSON.stringify(colorPalette, null, 2); // convert the data to a JSON string
|
||||||
|
const blob = new Blob([json], { type: "application/json" });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = $el("a", {
|
||||||
|
href: url,
|
||||||
|
download: "color_palette.json",
|
||||||
|
style: { display: "none" },
|
||||||
|
parent: document.body,
|
||||||
|
});
|
||||||
|
a.click();
|
||||||
|
setTimeout(function () {
|
||||||
|
a.remove();
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
$el("input", {
|
||||||
|
type: "button",
|
||||||
|
value: "Delete",
|
||||||
|
onclick: async () => {
|
||||||
|
let colorPaletteId = app.ui.settings.getSettingValue(id, defaultColorPaletteId);
|
||||||
|
|
||||||
|
if (colorPalettes[colorPaletteId]) {
|
||||||
|
app.ui.dialog.show("You cannot delete built-in color palette");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colorPaletteId.startsWith("custom_")) {
|
||||||
|
colorPaletteId = colorPaletteId.substr(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
await deleteCustomColorPalette(colorPaletteId);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
defaultValue: defaultColorPaletteId,
|
||||||
|
async onChange(value) {
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colorPalettes[value]) {
|
||||||
|
await loadColorPalette(colorPalettes[value]);
|
||||||
|
} else if (value.startsWith("custom_")) {
|
||||||
|
value = value.substr(7);
|
||||||
|
let customColorPalettes = getCustomColorPalettes();
|
||||||
|
if (customColorPalettes[value]) {
|
||||||
|
await loadColorPalette(customColorPalettes[value]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
@ -576,27 +576,6 @@ class ComfyApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup slot colors for types
|
|
||||||
*/
|
|
||||||
setupSlotColors() {
|
|
||||||
let colors = {
|
|
||||||
"CLIP": "#FFD500", // bright yellow
|
|
||||||
"CLIP_VISION": "#A8DADC", // light blue-gray
|
|
||||||
"CLIP_VISION_OUTPUT": "#ad7452", // rusty brown-orange
|
|
||||||
"CONDITIONING": "#FFA931", // vibrant orange-yellow
|
|
||||||
"CONTROL_NET": "#6EE7B7", // soft mint green
|
|
||||||
"IMAGE": "#64B5F6", // bright sky blue
|
|
||||||
"LATENT": "#FF9CF9", // light pink-purple
|
|
||||||
"MASK": "#81C784", // muted green
|
|
||||||
"MODEL": "#B39DDB", // light lavender-purple
|
|
||||||
"STYLE_MODEL": "#C2FFAE", // light green-yellow
|
|
||||||
"VAE": "#FF6E6E", // bright red
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.assign(this.canvas.default_connection_color_byType, colors);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the app on the page
|
* Set up the app on the page
|
||||||
*/
|
*/
|
||||||
@ -614,8 +593,6 @@ class ComfyApp {
|
|||||||
const canvas = (this.canvas = new LGraphCanvas(canvasEl, this.graph));
|
const canvas = (this.canvas = new LGraphCanvas(canvasEl, this.graph));
|
||||||
this.ctx = canvasEl.getContext("2d");
|
this.ctx = canvasEl.getContext("2d");
|
||||||
|
|
||||||
this.setupSlotColors();
|
|
||||||
|
|
||||||
this.graph.start();
|
this.graph.start();
|
||||||
|
|
||||||
function resizeCanvas() {
|
function resizeCanvas() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { api } from "./api.js";
|
import { api } from "./api.js";
|
||||||
|
|
||||||
function $el(tag, propsOrChildren, children) {
|
export function $el(tag, propsOrChildren, children) {
|
||||||
const split = tag.split(".");
|
const split = tag.split(".");
|
||||||
const element = document.createElement(split.shift());
|
const element = document.createElement(split.shift());
|
||||||
element.classList.add(...split);
|
element.classList.add(...split);
|
||||||
@ -114,6 +114,17 @@ class ComfySettingsDialog extends ComfyDialog {
|
|||||||
this.settings = [];
|
this.settings = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSettingValue(id, defaultValue) {
|
||||||
|
const settingId = "Comfy.Settings." + id;
|
||||||
|
const v = localStorage[settingId];
|
||||||
|
return v == null ? defaultValue : JSON.parse(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSettingValue(id, value) {
|
||||||
|
const settingId = "Comfy.Settings." + id;
|
||||||
|
localStorage[settingId] = JSON.stringify(value);
|
||||||
|
}
|
||||||
|
|
||||||
addSetting({ id, name, type, defaultValue, onChange }) {
|
addSetting({ id, name, type, defaultValue, onChange }) {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
throw new Error("Settings must have an ID");
|
throw new Error("Settings must have an ID");
|
||||||
@ -142,7 +153,7 @@ class ComfySettingsDialog extends ComfyDialog {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (typeof type === "function") {
|
if (typeof type === "function") {
|
||||||
return type(name, setter);
|
return type(name, setter, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -64,6 +64,12 @@ body {
|
|||||||
margin-bottom: 20px; /* Add some margin between the text and the close button*/
|
margin-bottom: 20px; /* Add some margin between the text and the close button*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comfy-modal select,
|
||||||
|
.comfy-modal input[type=button],
|
||||||
|
.comfy-modal input[type=checkbox] {
|
||||||
|
margin: 3px 3px 3px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.comfy-modal button {
|
.comfy-modal button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #aaaaaa;
|
color: #aaaaaa;
|
||||||
|
Loading…
Reference in New Issue
Block a user