mirror of
https://github.com/tusharbhutt/Endless-Nodes.git
synced 2026-03-24 13:42:11 -03:00
Added minimap and node spawner
Added minimap and node spawner
This commit is contained in:
276
web/endless_ui_helpers.js
Normal file
276
web/endless_ui_helpers.js
Normal file
@@ -0,0 +1,276 @@
|
||||
// === Endless 🌊✨ Tools UI Helper ===
|
||||
|
||||
const endlessToolsRegistry = [];
|
||||
|
||||
export function registerEndlessTool(name, callback) {
|
||||
endlessToolsRegistry.push({ name, callback });
|
||||
}
|
||||
|
||||
export function injectEndlessToolsButton() {
|
||||
const toolbar = findToolbar();
|
||||
if (!toolbar || document.getElementById("endless-tools-button")) return;
|
||||
|
||||
const btn = document.createElement("button");
|
||||
btn.id = "endless-tools-button";
|
||||
btn.textContent = "Endless 🌊✨ Tools";
|
||||
btn.className = "comfyui-button";
|
||||
btn.style.marginLeft = "8px";
|
||||
btn.onclick = showEndlessToolMenu;
|
||||
toolbar.appendChild(btn);
|
||||
}
|
||||
|
||||
export function showEndlessToolMenu() {
|
||||
document.getElementById("endless-tools-float")?.remove();
|
||||
|
||||
const colors = getComfyUIColors();
|
||||
|
||||
const menu = document.createElement("div");
|
||||
menu.id = "endless-tools-float";
|
||||
menu.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: ${colors.menu};
|
||||
color: ${colors.inputText};
|
||||
padding: 12px;
|
||||
border: 1px solid ${colors.accent};
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
||||
z-index: 99999;
|
||||
opacity: 1;
|
||||
width: fit-content;
|
||||
transition: opacity 0.2s ease;
|
||||
`;
|
||||
|
||||
const dragBar = document.createElement("div");
|
||||
dragBar.textContent = "Endless 🌊✨ Tools Drag Bar";
|
||||
dragBar.style.cssText = `
|
||||
padding: 4px;
|
||||
background: ${toRGBA(colors.inputText, 0.05)};
|
||||
cursor: move;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
user-select: none;
|
||||
border-bottom: 1px solid ${colors.border};
|
||||
`;
|
||||
menu.appendChild(dragBar);
|
||||
|
||||
endlessToolsRegistry.sort((a, b) => a.name.localeCompare(b.name)).forEach(tool => {
|
||||
const btn = document.createElement("div");
|
||||
btn.textContent = `🌊✨ ${tool.name}`;
|
||||
btn.style.cssText = `
|
||||
padding: 6px 10px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: background 0.2s ease;
|
||||
`;
|
||||
btn.onmouseover = () => btn.style.background = toRGBA(colors.inputText, 0.1);
|
||||
btn.onmouseout = () => btn.style.background = "transparent";
|
||||
btn.onclick = () => {
|
||||
tool.callback();
|
||||
menu.remove();
|
||||
};
|
||||
menu.appendChild(btn);
|
||||
});
|
||||
|
||||
makeDraggable(menu, dragBar);
|
||||
|
||||
// Live theme updater
|
||||
function updateMenuTheme(newColors = getComfyUIColors()) {
|
||||
menu.style.background = newColors.menu;
|
||||
menu.style.color = newColors.inputText;
|
||||
menu.style.borderColor = newColors.accent;
|
||||
menu.style.boxShadow = newColors.shadow;
|
||||
dragBar.style.background = toRGBA(newColors.inputText, 0.05);
|
||||
dragBar.style.borderBottomColor = newColors.border;
|
||||
}
|
||||
|
||||
const unregister = onThemeChange(updateMenuTheme);
|
||||
menu.remove = ((orig => function () {
|
||||
unregister();
|
||||
orig.call(this);
|
||||
})(menu.remove));
|
||||
|
||||
document.body.appendChild(menu);
|
||||
}
|
||||
|
||||
// === Hotkeys ===
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.ctrlKey && e.altKey && e.key.toLowerCase() === 'e') {
|
||||
showEndlessToolMenu();
|
||||
e.preventDefault();
|
||||
}
|
||||
if (e.key === "Escape") {
|
||||
document.getElementById("endless-tools-float")?.remove();
|
||||
}
|
||||
});
|
||||
|
||||
console.log("Endless 🌊✨ Tools menu: press Ctrl+Alt+E if toolbar button is missing.");
|
||||
|
||||
function waitForToolbarAndInject() {
|
||||
if (document.querySelector('.comfyui-menu')) {
|
||||
injectEndlessToolsButton();
|
||||
return;
|
||||
}
|
||||
const observer = new MutationObserver(() => {
|
||||
if (document.querySelector('.comfyui-menu')) {
|
||||
injectEndlessToolsButton();
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
}
|
||||
waitForToolbarAndInject();
|
||||
|
||||
function findToolbar() {
|
||||
return (
|
||||
document.querySelector('.comfyui-menu, .comfy-menu, [class*="menu"], [class*="toolbar"]') ||
|
||||
Array.from(document.querySelectorAll('[class*="button-group"], [class*="btn-group"], .comfyui-button-group'))
|
||||
.find(g => g.querySelectorAll('button').length > 0) ||
|
||||
Array.from(document.querySelectorAll('*'))
|
||||
.find(el => {
|
||||
const buttons = el.querySelectorAll('button');
|
||||
return buttons.length >= 2 && buttons.length <= 10;
|
||||
}) ||
|
||||
Array.from(document.querySelectorAll(".comfyui-button-group"))
|
||||
.find(div => Array.from(div.querySelectorAll("button")).some(btn => btn.title === "Share"))
|
||||
);
|
||||
}
|
||||
|
||||
// === Live Theme Monitoring ===
|
||||
let themeObserver = null;
|
||||
const themeCallbacks = new Set();
|
||||
|
||||
export function onThemeChange(callback) {
|
||||
themeCallbacks.add(callback);
|
||||
if (themeCallbacks.size === 1) startThemeObserver();
|
||||
return () => {
|
||||
themeCallbacks.delete(callback);
|
||||
if (themeCallbacks.size === 0) stopThemeObserver();
|
||||
};
|
||||
}
|
||||
|
||||
function startThemeObserver() {
|
||||
if (themeObserver) return;
|
||||
themeObserver = new MutationObserver(() => {
|
||||
clearTimeout(window.themeChangeTimeout);
|
||||
window.themeChangeTimeout = setTimeout(() => {
|
||||
const newColors = getComfyUIColors();
|
||||
themeCallbacks.forEach(cb => cb(newColors));
|
||||
}, 100);
|
||||
});
|
||||
themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class', 'style', 'data-theme'] });
|
||||
themeObserver.observe(document.body, { attributes: true, attributeFilter: ['class', 'style', 'data-theme'] });
|
||||
}
|
||||
|
||||
function stopThemeObserver() {
|
||||
if (themeObserver) {
|
||||
themeObserver.disconnect();
|
||||
themeObserver = null;
|
||||
}
|
||||
}
|
||||
|
||||
export function getComfyUIColors() {
|
||||
const computed = getComputedStyle(document.documentElement);
|
||||
const getVar = name => computed.getPropertyValue(name).trim() || null;
|
||||
return {
|
||||
fg: getVar("--fg-color") || "#ddd",
|
||||
bg: getVar("--bg-color") || "#353535",
|
||||
menu: getVar("--comfy-menu-bg") || "#353535",
|
||||
menuSecondary: getVar("--comfy-menu-secondary-bg") || "#222",
|
||||
inputBg: getVar("--comfy-input-bg") || "#222",
|
||||
inputText: getVar("--input-text") || "#ddd",
|
||||
descriptionText: getVar("--descrip-text") || "#999",
|
||||
dragText: getVar("--drag-text") || "#ddd",
|
||||
errorText: getVar("--error-text") || "#f44336",
|
||||
border: getVar("--border-color") || "#999",
|
||||
accent: getVar("--comfy-accent") || getVar("--comfy-accent-color") || "#4a90e2",
|
||||
hoverBg: getVar("--content-hover-bg") || "rgba(255,255,255,0.1)",
|
||||
hoverFg: getVar("--content-hover-fg") || "#fff",
|
||||
shadow: getVar("--bar-shadow") || "0 2px 10px rgba(0,0,0,0.3)",
|
||||
dialogBg: getVar("--comfy-menu-bg") || getVar("--bg-color") || "#353535",
|
||||
buttonHoverBg: getVar("--content-hover-bg") || "rgba(255,255,255,0.1)"
|
||||
};
|
||||
}
|
||||
|
||||
export function toRGBA(color, alpha = 0.2) {
|
||||
if (!color) return `rgba(128,128,128,${alpha})`;
|
||||
color = color.trim();
|
||||
if (color.startsWith('#')) {
|
||||
const hex = color.slice(1);
|
||||
const fullHex = hex.length === 3 ? hex.split('').map(c => c + c).join('') : hex;
|
||||
const bigint = parseInt(fullHex, 16);
|
||||
const r = (bigint >> 16) & 255, g = (bigint >> 8) & 255, b = bigint & 255;
|
||||
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
||||
}
|
||||
if (color.startsWith('rgb')) {
|
||||
const rgb = color.match(/\d+/g);
|
||||
if (rgb?.length >= 3) return `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${alpha})`;
|
||||
}
|
||||
return `rgba(128,128,128,${alpha})`;
|
||||
}
|
||||
|
||||
export function blendColors(color1, color2, ratio) {
|
||||
const c1 = toRGBA(color1, 1).match(/\d+/g);
|
||||
const c2 = toRGBA(color2, 1).match(/\d+/g);
|
||||
if (!c1 || !c2) return color1;
|
||||
const r = Math.round(c1[0] * (1 - ratio) + c2[0] * ratio);
|
||||
const g = Math.round(c1[1] * (1 - ratio) + c2[1] * ratio);
|
||||
const b = Math.round(c1[2] * (1 - ratio) + c2[2] * ratio);
|
||||
return `rgb(${r}, ${g}, ${b})`;
|
||||
}
|
||||
|
||||
export function addButtonHoverEffects(container) {
|
||||
container?.querySelectorAll('button').forEach(button => {
|
||||
button.addEventListener('mouseenter', () => {
|
||||
button.style.boxShadow = '0 0 0 1px currentColor';
|
||||
button.style.filter = 'brightness(1.1)';
|
||||
button.style.transform = 'translateY(-1px)';
|
||||
});
|
||||
button.addEventListener('mouseleave', () => {
|
||||
button.style.boxShadow = 'none';
|
||||
button.style.filter = 'brightness(1)';
|
||||
button.style.transform = 'translateY(0px)';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function makeDraggable(element, handle = element) {
|
||||
let offsetX = 0, offsetY = 0, isDown = false;
|
||||
handle.onmousedown = (e) => {
|
||||
isDown = true;
|
||||
if (element.style.position !== 'fixed') {
|
||||
element.style.position = 'fixed';
|
||||
element.style.right = 'auto';
|
||||
}
|
||||
const rect = element.getBoundingClientRect();
|
||||
offsetX = e.clientX - rect.left;
|
||||
offsetY = e.clientY - rect.top;
|
||||
element.style.cursor = 'move';
|
||||
document.onmousemove = (e) => {
|
||||
if (!isDown) return;
|
||||
element.style.left = `${e.clientX - offsetX}px`;
|
||||
element.style.top = `${e.clientY - offsetY}px`;
|
||||
element.style.transform = 'none';
|
||||
};
|
||||
document.onmouseup = () => {
|
||||
isDown = false;
|
||||
element.style.cursor = 'default';
|
||||
document.onmousemove = null;
|
||||
document.onmouseup = null;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// === Global exposure for F12 ===
|
||||
window.EndlessHelpers = {
|
||||
registerEndlessTool,
|
||||
injectEndlessToolsButton,
|
||||
showEndlessToolMenu,
|
||||
onThemeChange,
|
||||
getComfyUIColors,
|
||||
toRGBA,
|
||||
blendColors,
|
||||
addButtonHoverEffects,
|
||||
makeDraggable
|
||||
};
|
||||
Reference in New Issue
Block a user