Merge pull request #1 from tusharbhutt/dev

Initial pull from Dev to Main
This commit is contained in:
tusharbhutt
2025-07-20 13:59:15 -06:00
committed by GitHub
12 changed files with 1790 additions and 2 deletions
+20
View File
@@ -0,0 +1,20 @@
name: Publish to Comfy registry
on:
workflow_dispatch:
push:
branches:
- main
paths:
- "pyproject.toml"
jobs:
publish-node:
name: Publish Custom Node to registry
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Publish Custom Node
uses: Comfy-Org/publish-node-action@main
with:
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }} ## Add your own personal access token to your Github Repository secrets and reference it here.
+94 -2
View File
@@ -1,2 +1,94 @@
# Endless-Buttons
Some basic custom JavaScript files for the ComfyUI user interface
# Endless Sea of Stars Buttons
Some basic custom JavaScript files for the ComfyUI user interface. Features:
+ Fontifier: a script that allows you to change fonts and font sizes for ComfyUI nodes
+ More to come (maybe)
When using the [ComfyUI](https://github.com/comfyanonymous/ComfyUI) interface for AI art generation, I sometimes find that the standard nodes and the many custom nodes out there don't work the way I want them to, or how I think they should.
Rightly or wrongly, I was teaching myself a bit of Python back in 2023 to get some nodes up and running to do what I'd like, and I now I am doing the same for JavaScript. Yes, I am using ChatGPT, Copilot, Claude and others, and yes, I am a glutton for punishment. There are no promises that these scripts will work for you or that I will maintain them. Feel free to do with them as you wish, according to the license model.
***
**UPDATE: JUL 20, 2025**
+ **Cloned the scripts from [Endless Sea of Stars Nodes](https://github.com/tusharbhutt/Endless-Nodes) so you can just download the scripts if you want**
+ Added the Endless 🌊✨ Tools button to taskbar. This acts as a centralized repository of all my scripts
+ Introduced the Endless 🌊✨ Fontifier, a script that allows you to dynamically change fonts and sizes.
+ No need to dive into CSS to change text size
+ Allows changes to the title areas, connector text, widgets, and more
+ Adjust the height of the title bar and other areas too, to accommodate the new font size
## Installation Instructions
It’s preferable to install from the ComfyUI Node Manager, but for direct installation, do this:
+ Navigate to your /ComfyUI/custom_nodes/ folder
+ In Windows, you can then right-click to start a command prompt and type:
`git clone https://github.com/tusharbhutt/Endless-Buttons`
If installed correctly, you should see a button in the main ComfyUI taskbar that look like this:
Endless 🌊✨ Tools
and when you click it, a floating toolbar with available scripts will be enabled. **DON'T SEE THE BUTTON IN THE TOOLBAR? PRESS CTRL-ALT-E TO BRING THE TOOLBAR**
***
## Assistance Requests
I am not a programmer, nor do I care to be. I have a fulltime job that eats up 50-60 hours a week and I made these scripts for myself. I’ve tested the scripts on my system and uploaded them as they seem to work. They may or may not work for you or on your system.
If you have issues, ask me **nicely** for help. Your tone matters; I'm too old and tired to pay attention to people who think I blew up their machines, and if how I react to you if you are difficult bothers you, some self-reflection is in order on your part. You are not "forthright" or "honest" or "direct", you're merely an ass if you think badgering people is justifiable to get what you want. The world has too many assholes, don't make me think you're another one.
***
## Button List
A helper script places a button on your task bar called "Endless 🌊✨ Tools":
![endlesstools](./img/endlesstools.png)
**IF YOU DO NOT SEE IT, PRESS CTRL-ALT-E TO BRING UP A FLOATING TOOLBAR THAT CAN BE MOVED AROUND** This is the central toolbar that contains all the scripts I have made for this collection
### Endless 🌊✨ Fontifier
I always found it odd that in the early days of ComfyUI, you could not change the font size for various node elements. Sure you could manually go into the CSS styling in a user file, but that is not user friendly. Later versions have allowed you to change the widget text size, but that's it. Yes, you can zoom in, but... now you've lost your larger view of the workflow. If you have a 4K monitor and old eyes, too bad so sad for you. Click the Endless 🌊✨ Tools button to bring up the floating toolbar and you should see a choice for "🌊✨ Fontifier". Clicking it shows the dialog box below:
![fontifierbox](./img/fontifierbox.png)
Drag the box around by clicking and holding the title. To cancel, you can simply click outside the dialog box or press the escape key. With this dialog box, you can do the following:
+ Globally change the font size for all text elements
+ Change the fonts themselves
+ Instead of a global change, select various elements to resize
+ Adjust the height of the title bar or connectors and other input areas
Once you make your changes, you can preview them and then choose to apply or cancel. Changed your mind? Load the box again and press the reset key.
![fontifiernode](./img/fontifiernode.png)
***
## Usage License and Restrictions
See [GPL Licensing V3](https://www.gnu.org/licenses/gpl-3.0.en.html#license-text) for usage. You may modify this code as long as you keep the credits for this repository and for those noted in the credit section below. **YOU ARE EXPRESSLY FORBIDDEN FROM USING THESE SCRIPTS TO CREATE ANY IMAGES OR ARTWORK THAT VIOLATES THE STABLE DIFFUSION [ACCEPTABLE USE POLICY](https://stability.ai/use-policy) OR THE USAGE POLICY FROM [BLACK FOREST LABS](https://bfl.ai/legal/usage-policy).**
For example, don't be a mouth-breather who creates fake nudes or sexual content of **anyone, even if you have their consent**. JUST. DON’T. BE. AN. ASSHOLE. I call this my "Don't Be an Asshole™" licensing model (I'm kidding about the trademark but not about the message).
The author expressly disclaims any liability for any images you create using these nodes.
***
## Disclaimer
These scripts may or may not be maintained. They work on my system but may not on yours. Feel free to send in a bug report if you find one!
***
## Credits
+ Inspiration for the Fontifier came from having old eyes and a 4K screen
+ Anthropic Claude and OpenAI ChatGPT are actively used for coding creation/assistance
+ Thanks to all the node and script creators out there, most who toil away with little or no appreciation
#
+16
View File
@@ -0,0 +1,16 @@
# buttons/__init__.py
# =========================
# 💉 Set JavaScript
# =========================
WEB_DIRECTORY = "./web/"
# Version info
__version__ = "1.0.2"
print("\n===============================")
print(f"Endless Sea of Stars Buttons v{__version__} loaded successfully! 🌠")
print("Endless 🌊✨ Tools menu: Ctrl+Alt+E if toolbar button is missing")
print("===============================\n")
+1
View File
@@ -0,0 +1 @@
July 20/25, V1.0.2: Introducing the Endless Fontifier, a JavaScript file that adds allows the user to change font sizes and fonts for various text elements on the ComfyUI interface.
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

+15
View File
@@ -0,0 +1,15 @@
[project]
name = "endless-buttons"
description = "A small set of JavaScript files I created for myself. The scripts provide Quality of Life enhancements to the ComfyUI interface, such as changing fonts and font sizes."
version = "1.0.2"
license = { file = "LICENSE" }
dependencies = ""
[project.urls]
Repository = "https://github.com/tusharbhutt/Endless-Buttons"
# Used by Comfy Registry https://comfyregistry.org
[tool.comfy]
PublisherId = "tusharbhutt"
DisplayName = "Endless 🌊✨ Butons"
Icon = "https://raw.githubusercontent.com/tusharbhutt/Endless-Buttons/main/img/icon.png"
+460
View File
@@ -0,0 +1,460 @@
// ComfyUI Endless 🌊✨ Fontifier - Fixed Version
import { registerEndlessTool } from './endless_ui_helpers.js';
(function() {
'use strict';
// Store original ComfyUI default values for reset functionality
const originalValues = {
NODE_TEXT_SIZE: 14,
NODE_SUBTEXT_SIZE: 12,
NODE_TITLE_HEIGHT: 30,
DEFAULT_GROUP_FONT: 24,
NODE_FONT: 'Arial',
NODE_SLOT_HEIGHT: 20,
NODE_WIDGET_HEIGHT: 20,
WIDGET_TEXT_SIZE: 12 // Added widget text size to original values
};
// Current values (will be updated as user changes them)
let currentValues = { ...originalValues };
// Values when dialog opens (for cancel/preview rollback)
let dialogOpenValues = {};
// Get ComfyUI theme colors
function getComfyUIColors() {
const computedStyle = getComputedStyle(document.documentElement);
return {
background: computedStyle.getPropertyValue('--comfy-menu-bg') || '#353535',
backgroundSecondary: computedStyle.getPropertyValue('--comfy-input-bg') || '#222',
border: computedStyle.getPropertyValue('--border-color') || '#999',
text: computedStyle.getPropertyValue('--input-text') || '#ddd',
textSecondary: computedStyle.getPropertyValue('--descrip-text') || '#999',
accent: computedStyle.getPropertyValue('--comfy-menu-bg') || '#0f0f0f'
};
}
function makeDraggable(dialog) {
const header = dialog.querySelector('h2');
if (!header) return;
let offsetX = 0, offsetY = 0, isDown = false;
header.style.cursor = 'move';
header.style.userSelect = 'none';
header.onmousedown = (e) => {
e.preventDefault();
isDown = true;
const rect = dialog.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
const onMouseMove = (e) => {
if (!isDown) return;
e.preventDefault();
dialog.style.left = `${e.clientX - offsetX}px`;
dialog.style.top = `${e.clientY - offsetY}px`;
dialog.style.transform = 'none';
};
const onMouseUp = () => {
isDown = false;
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
};
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
};
}
// Function to capture current ComfyUI settings
function captureCurrentSettings() {
const settings = {
NODE_TEXT_SIZE: (typeof LiteGraph !== 'undefined' && LiteGraph.NODE_TEXT_SIZE) ? LiteGraph.NODE_TEXT_SIZE : originalValues.NODE_TEXT_SIZE,
NODE_SUBTEXT_SIZE: (typeof LiteGraph !== 'undefined' && LiteGraph.NODE_SUBTEXT_SIZE) ? LiteGraph.NODE_SUBTEXT_SIZE : originalValues.NODE_SUBTEXT_SIZE,
NODE_TITLE_HEIGHT: (typeof LiteGraph !== 'undefined' && LiteGraph.NODE_TITLE_HEIGHT) ? LiteGraph.NODE_TITLE_HEIGHT : originalValues.NODE_TITLE_HEIGHT,
DEFAULT_GROUP_FONT: (typeof LiteGraph !== 'undefined' && LiteGraph.DEFAULT_GROUP_FONT) ? LiteGraph.DEFAULT_GROUP_FONT : originalValues.DEFAULT_GROUP_FONT,
NODE_FONT: (typeof LiteGraph !== 'undefined' && LiteGraph.NODE_FONT) ? LiteGraph.NODE_FONT : originalValues.NODE_FONT,
NODE_SLOT_HEIGHT: (typeof LiteGraph !== 'undefined' && LiteGraph.NODE_SLOT_HEIGHT) ? LiteGraph.NODE_SLOT_HEIGHT : originalValues.NODE_SLOT_HEIGHT,
WIDGET_TEXT_SIZE: currentValues.WIDGET_TEXT_SIZE // Get current widget text size
};
console.log('📸 Captured current settings:', settings);
return settings;
}
function createFontifierDialog() {
// Remove existing dialog if present
const existingDialog = document.getElementById('fontifier-dialog');
if (existingDialog) {
existingDialog.remove();
}
// Capture current settings when dialog opens
currentValues = captureCurrentSettings();
dialogOpenValues = { ...currentValues };
const colors = getComfyUIColors();
// Create dialog container
const dialog = document.createElement('div');
dialog.id = 'fontifier-dialog';
dialog.className = 'comfyui-dialog';
dialog.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: ${colors.background};
border: 1px solid ${colors.border};
border-radius: 8px;
padding: 20px;
z-index: 10000;
width: 520px;
max-height: 80vh;
overflow-y: auto;
font-family: Arial, sans-serif;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
color: ${colors.text};
`;
// Create backdrop - REMOVE the onclick handler to prevent accidental cancellation
const backdrop = document.createElement('div');
backdrop.className = 'comfyui-backdrop';
backdrop.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 9999;
`;
// Removed the onclick handler to prevent accidental cancellation
dialog.innerHTML = `
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; border-bottom: 1px solid ${colors.border}; padding-bottom: 15px;">
<h2 style="color: ${colors.text}; margin: 0; font-size: 16px;">🌊✨ Endless Fontifier</h2>
<button id="close-dialog" style="background: ${colors.backgroundSecondary}; border: 1px solid ${colors.border}; color: ${colors.text}; padding: 6px 12px; border-radius: 4px; cursor: pointer;">✕</button>
</div>
<div style="margin-bottom: 12px; padding: 12px; background: ${colors.backgroundSecondary}; border-radius: 6px; border: 1px solid ${colors.border};">
<h3 style="color: ${colors.text}; margin: 0 0 10px 0; font-size: 16px;">Global Scale</h3>
<div style="display: flex; align-items: center; gap: 12px;">
<label style="color: ${colors.textSecondary}; min-width: 80px; font-size: 12px;">Scale All:</label>
<input type="range" id="global-scale" min="0.5" max="3" step="0.1" value="1" style="flex: 1; accent-color: ${colors.accent};">
<input type="number" id="global-scale-num" min="0.5" max="3" step="0.1" value="1" style="width: 70px; padding: 6px; background: ${colors.background}; border: 1px solid ${colors.border}; color: ${colors.text}; border-radius: 4px; font-size: 12px;">
</div>
</div>
<div style="margin-bottom: 12px; padding: 12px; background: ${colors.backgroundSecondary}; border-radius: 6px; border: 1px solid ${colors.border};">
<h3 style="color: ${colors.text}; margin: 0 0 12px 0; font-size: 16px;">Font Family</h3>
<select id="font-family" style="width: 100%; padding: 8px; background: ${colors.background}; border: 1px solid ${colors.border}; color: ${colors.text}; border-radius: 4px; font-size: 12px;">
<option value="Arial">Arial</option>
<option value="Helvetica">Helvetica</option>
<option value="Times New Roman">Times New Roman</option>
<option value="Courier New">Courier New</option>
<option value="Verdana">Verdana</option>
<option value="Georgia">Georgia</option>
<option value="Comic Sans MS">Comic Sans MS</option>
<option value="Impact">Impact</option>
<option value="Trebuchet MS">Trebuchet MS</option>
<option value="Tahoma">Tahoma</option>
</select>
</div>
<div style="margin-bottom: 12px; padding: 12px; background: ${colors.backgroundSecondary}; border-radius: 6px; border: 1px solid ${colors.border};">
<h3 style="color: ${colors.text}; margin: 0 0 12px 0; font-size: 16px;">Text Element Sizes</h3>
<div style="margin-bottom: 10px;">
<label style="color: ${colors.text}; display: block; margin-bottom: 4px; font-size: 12px; font-weight: bold;">Node Title Text</label>
<div style="color: ${colors.textSecondary}; font-size: 11px; margin-bottom: 5px;">The main title text at the top of each node (e.g., "KSampler", "VAE Decode")</div>
<div style="display: flex; align-items: center; gap: 10px;">
<input type="range" id="node-text-size" min="8" max="32" value="${currentValues.NODE_TEXT_SIZE}" style="flex: 1; accent-color: ${colors.accent};">
<input type="number" id="node-text-size-num" min="8" max="32" value="${currentValues.NODE_TEXT_SIZE}" style="width: 60px; padding: 5px; background: ${colors.background}; border: 1px solid ${colors.border}; color: ${colors.text}; border-radius: 4px; font-size: 12px;">
</div>
</div>
<div style="margin-bottom: 10px;">
<label style="color: ${colors.text}; display: block; margin-bottom: 4px; font-size: 12px; font-weight: bold;">Widget Labels & Values</label>
<div style="color: ${colors.textSecondary}; font-size: 11px; margin-bottom: 5px;">Text inside nodes: parameter names and values (e.g., "steps: 20", "cfg: 8.0")</div>
<div style="display: flex; align-items: center; gap: 10px;">
<input type="range" id="node-subtext-size" min="6" max="24" value="${currentValues.NODE_SUBTEXT_SIZE}" style="flex: 1; accent-color: ${colors.accent};">
<input type="number" id="node-subtext-size-num" min="6" max="24" value="${currentValues.NODE_SUBTEXT_SIZE}" style="width: 60px; padding: 5px; background: ${colors.background}; border: 1px solid ${colors.border}; color: ${colors.text}; border-radius: 4px; font-size: 12px;">
</div>
</div>
<div style="margin-bottom: 10px;">
<label style="color: ${colors.text}; display: block; margin-bottom: 4px; font-size: 12px; font-weight: bold;">Widget Text Input Size</label>
<div style="color: ${colors.textSecondary}; font-size: 11px; margin-bottom: 5px;">Font size for text inside input boxes, dropdowns, and textareas in nodes.</div>
<div style="display: flex; align-items: center; gap: 10px;">
<input type="range" id="widget-text-size" min="8" max="24" value="${currentValues.WIDGET_TEXT_SIZE}" style="flex: 1; accent-color: ${colors.accent};">
<input type="number" id="widget-text-size-num" min="8" max="24" value="${currentValues.WIDGET_TEXT_SIZE}" style="width: 60px; padding: 5px; background: ${colors.background}; border: 1px solid ${colors.border}; color: ${colors.text}; border-radius: 4px; font-size: 12px;">
</div>
</div>
<div style="margin-bottom: 10px;">
<label style="color: ${colors.text}; display: block; margin-bottom: 4px; font-size: 12px; font-weight: bold;">Node Title Area Height</label>
<div style="color: ${colors.textSecondary}; font-size: 11px; margin-bottom: 5px;">Height of the colored title bar area at the top of nodes</div>
<div style="display: flex; align-items: center; gap: 10px;">
<input type="range" id="title-height" min="20" max="60" value="${currentValues.NODE_TITLE_HEIGHT}" style="flex: 1; accent-color: ${colors.accent};">
<input type="number" id="title-height-num" min="20" max="60" value="${currentValues.NODE_TITLE_HEIGHT}" style="width: 60px; padding: 5px; background: ${colors.background}; border: 1px solid ${colors.border}; color: ${colors.text}; border-radius: 4px; font-size: 12px;">
</div>
</div>
<div style="margin-bottom: 10px;">
<label style="color: ${colors.text}; display: block; margin-bottom: 4px; font-size: 12px; font-weight: bold;">Connection Slot Height</label>
<div style="color: ${colors.textSecondary}; font-size: 11px; margin-bottom: 5px;">Height of input/output connection points on node sides</div>
<div style="display: flex; align-items: center; gap: 10px;">
<input type="range" id="slot-height" min="12" max="40" value="${currentValues.NODE_SLOT_HEIGHT}" style="flex: 1; accent-color: ${colors.accent};">
<input type="number" id="slot-height-num" min="12" max="40" value="${currentValues.NODE_SLOT_HEIGHT}" style="width: 60px; padding: 5px; background: ${colors.background}; border: 1px solid ${colors.border}; color: ${colors.text}; border-radius: 4px; font-size: 12px;">
</div>
</div>
<div style="margin-bottom: 10px;">
<label style="color: ${colors.text}; display: block; margin-bottom: 4px; font-size: 12px; font-weight: bold;">Group Label Size</label>
<div style="color: ${colors.textSecondary}; font-size: 11px; margin-bottom: 5px;">Text size for node group labels (when nodes are grouped together)</div>
<div style="display: flex; align-items: center; gap: 10px;">
<input type="range" id="group-font-size" min="12" max="48" value="${currentValues.DEFAULT_GROUP_FONT}" style="flex: 1; accent-color: ${colors.accent};">
<input type="number" id="group-font-size-num" min="12" max="48" value="${currentValues.DEFAULT_GROUP_FONT}" style="width: 60px; padding: 5px; background: ${colors.background}; border: 1px solid ${colors.border}; color: ${colors.text}; border-radius: 4px; font-size: 12px;">
</div>
</div>
</div>
<div style="display: flex; gap: 10px; justify-content: center; padding-top: 15px; border-top: 1px solid ${colors.border};">
<button id="apply-btn" style="padding: 8px 16px; background: ${colors.backgroundSecondary}; border: 1px solid ${colors.border}; color: ${colors.text}; border-radius: 4px; cursor: pointer; font-size: 12px; transition: border-width 0.2s ease; background-image: linear-gradient(rgba(128, 255, 128, 0.08), rgba(128, 255, 128, 0.08));">Apply & Close</button>
<button id="preview-btn" style="padding: 8px 16px; background: ${colors.backgroundSecondary}; border: 1px solid ${colors.border}; color: ${colors.text}; border-radius: 4px; cursor: pointer; font-size: 12px; transition: border-width 0.2s ease;">Preview</button>
<button id="reset-btn" style="padding: 8px 16px; background: ${colors.backgroundSecondary}; border: 1px solid ${colors.border}; color: ${colors.text}; border-radius: 4px; cursor: pointer; font-size: 12px; transition: border-width 0.2s ease;">Reset to Defaults</button>
<button id="cancel-btn" style="padding: 8px 16px; background: ${colors.backgroundSecondary}; border: 1px solid ${colors.border}; color: ${colors.textSecondary}; border-radius: 4px; cursor: pointer; font-size: 12px; transition: border-width 0.2s ease; background-image: linear-gradient(rgba(255, 128, 128, 0.08), rgba(255, 128, 128, 0.08));">Cancel</button>
</div>
`;
document.body.appendChild(backdrop);
document.body.appendChild(dialog);
// ESC key handler - restore original values on escape
function escHandler(e) {
if (e.key === 'Escape') {
restoreSettings(dialogOpenValues);
backdrop.remove();
dialog.remove();
document.removeEventListener('keydown', escHandler);
}
}
document.addEventListener('keydown', escHandler);
// Set up event handlers
setupDialogHandlers(dialog, backdrop);
// Set font family to current value
dialog.querySelector('#font-family').value = currentValues.NODE_FONT;
}
// Function to restore settings
function restoreSettings(settings) {
applySettingsToComfyUI(settings);
console.log('🔄 Settings restored:', settings);
}
// Separated function to apply settings to ComfyUI
function applySettingsToComfyUI(settings) {
if (typeof LiteGraph !== 'undefined') {
LiteGraph.NODE_TEXT_SIZE = settings.NODE_TEXT_SIZE;
LiteGraph.NODE_SUBTEXT_SIZE = settings.NODE_SUBTEXT_SIZE;
LiteGraph.NODE_TITLE_HEIGHT = settings.NODE_TITLE_HEIGHT;
LiteGraph.NODE_SLOT_HEIGHT = settings.NODE_SLOT_HEIGHT;
LiteGraph.NODE_WIDGET_HEIGHT = settings.NODE_SLOT_HEIGHT;
LiteGraph.DEFAULT_GROUP_FONT = settings.DEFAULT_GROUP_FONT;
LiteGraph.DEFAULT_GROUP_FONT_SIZE = settings.DEFAULT_GROUP_FONT;
LiteGraph.NODE_FONT = settings.NODE_FONT || settings.FONT_FAMILY;
LiteGraph.DEFAULT_FONT = settings.NODE_FONT || settings.FONT_FAMILY;
LiteGraph.GROUP_FONT = settings.NODE_FONT || settings.FONT_FAMILY;
if (typeof app !== 'undefined' && app.canvas) {
app.canvas.setDirty(true, true);
if (app.canvas.draw) {
setTimeout(() => app.canvas.draw(true, true), 100);
}
}
const canvases = document.querySelectorAll('canvas');
canvases.forEach(canvas => {
if (canvas.getContext) {
const ctx = canvas.getContext('2d');
const originalWidth = canvas.width;
canvas.width = originalWidth + 1;
canvas.width = originalWidth;
}
});
}
// Apply widget font size to CSS
let styleTag = document.getElementById('fontifier-widget-text-style');
if (!styleTag) {
styleTag = document.createElement('style');
styleTag.id = 'fontifier-widget-text-style';
document.head.appendChild(styleTag);
}
styleTag.textContent = `
canvas ~ * .widget input, canvas ~ * .widget select, canvas ~ * .widget textarea,
canvas ~ * .comfy-multiline-input, canvas ~ * .comfy-input,
canvas ~ * input.comfy-multiline-input, canvas ~ * textarea.comfy-multiline-input,
canvas ~ * [class*="comfy-input"], canvas ~ * [class*="comfy-multiline"],
canvas ~ * .comfyui-widget input, canvas ~ * .comfyui-widget select, canvas ~ * .comfyui-widget textarea,
canvas ~ * [class*="widget"] input, canvas ~ * [class*="widget"] select, canvas ~ * [class*="widget"] textarea,
canvas ~ * .litegraph input, canvas ~ * .litegraph select, canvas ~ * .litegraph textarea,
.litegraph input, .litegraph select, .litegraph textarea {
font-size: ${settings.WIDGET_TEXT_SIZE}px !important;
font-family: ${settings.NODE_FONT || settings.FONT_FAMILY} !important;
}
/* Exclude the fontifier dialog itself */
#fontifier-dialog input, #fontifier-dialog select, #fontifier-dialog textarea {
font-size: 14px !important;
font-family: Arial !important;
}
`;
}
function setupDialogHandlers(dialog, backdrop) {
makeDraggable(dialog);
// Sync sliders with number inputs
const elements = [
'global-scale',
'node-text-size',
'node-subtext-size',
'title-height',
'slot-height',
'group-font-size',
'widget-text-size'
];
elements.forEach(id => {
const slider = dialog.querySelector(`#${id}`);
const numberInput = dialog.querySelector(`#${id}-num`);
slider.oninput = () => {
numberInput.value = slider.value;
if (id === 'global-scale') {
const globalScaleNum = dialog.querySelector('#global-scale-num');
globalScaleNum.value = slider.value;
}
};
numberInput.oninput = () => {
slider.value = numberInput.value;
};
});
// Global scale handler - now includes widget text size
const globalScale = dialog.querySelector('#global-scale');
const globalScaleNum = dialog.querySelector('#global-scale-num');
function updateGlobalScale() {
const scale = parseFloat(globalScale.value);
globalScaleNum.value = scale;
// Update all individual controls including widget text size
const updates = [
['node-text-size', originalValues.NODE_TEXT_SIZE],
['node-subtext-size', originalValues.NODE_SUBTEXT_SIZE],
['title-height', originalValues.NODE_TITLE_HEIGHT],
['slot-height', originalValues.NODE_SLOT_HEIGHT],
['group-font-size', originalValues.DEFAULT_GROUP_FONT],
['widget-text-size', originalValues.WIDGET_TEXT_SIZE] // Added widget text size to global scaling
];
updates.forEach(([id, originalValue]) => {
const newValue = Math.round(originalValue * scale);
dialog.querySelector(`#${id}`).value = newValue;
dialog.querySelector(`#${id}-num`).value = newValue;
});
}
globalScale.oninput = updateGlobalScale;
globalScaleNum.oninput = () => {
globalScale.value = globalScaleNum.value;
updateGlobalScale();
};
// Button handlers
dialog.querySelector('#close-dialog').onclick = () => {
restoreSettings(dialogOpenValues);
backdrop.remove();
dialog.remove();
};
dialog.querySelector('#reset-btn').onclick = () => {
dialog.querySelector('#global-scale').value = 1;
dialog.querySelector('#global-scale-num').value = 1;
dialog.querySelector('#node-text-size').value = originalValues.NODE_TEXT_SIZE;
dialog.querySelector('#node-text-size-num').value = originalValues.NODE_TEXT_SIZE;
dialog.querySelector('#node-subtext-size').value = originalValues.NODE_SUBTEXT_SIZE;
dialog.querySelector('#node-subtext-size-num').value = originalValues.NODE_SUBTEXT_SIZE;
dialog.querySelector('#title-height').value = originalValues.NODE_TITLE_HEIGHT;
dialog.querySelector('#title-height-num').value = originalValues.NODE_TITLE_HEIGHT;
dialog.querySelector('#slot-height').value = originalValues.NODE_SLOT_HEIGHT;
dialog.querySelector('#slot-height-num').value = originalValues.NODE_SLOT_HEIGHT;
dialog.querySelector('#group-font-size').value = originalValues.DEFAULT_GROUP_FONT;
dialog.querySelector('#group-font-size-num').value = originalValues.DEFAULT_GROUP_FONT;
dialog.querySelector('#widget-text-size').value = originalValues.WIDGET_TEXT_SIZE;
dialog.querySelector('#widget-text-size-num').value = originalValues.WIDGET_TEXT_SIZE;
dialog.querySelector('#font-family').value = 'Arial';
};
dialog.querySelector('#preview-btn').onclick = () => applyChanges(dialog, false);
dialog.querySelector('#apply-btn').onclick = () => {
applyChanges(dialog, true);
backdrop.remove();
dialog.remove();
};
dialog.querySelector('#cancel-btn').onclick = () => {
restoreSettings(dialogOpenValues);
backdrop.remove();
dialog.remove();
};
// Add hover effects to buttons
const buttons = dialog.querySelectorAll('button');
buttons.forEach(button => {
button.style.boxSizing = 'border-box';
button.style.minWidth = button.offsetWidth + 'px';
button.addEventListener('mouseenter', () => {
button.style.borderWidth = '2px';
button.style.padding = '7px 15px';
});
button.addEventListener('mouseleave', () => {
button.style.borderWidth = '1px';
button.style.padding = '8px 16px';
});
});
}
function applyChanges(dialog, permanent = false) {
const newValues = {
NODE_TEXT_SIZE: parseInt(dialog.querySelector('#node-text-size').value),
NODE_SUBTEXT_SIZE: parseInt(dialog.querySelector('#node-subtext-size').value),
NODE_TITLE_HEIGHT: parseInt(dialog.querySelector('#title-height').value),
NODE_SLOT_HEIGHT: parseInt(dialog.querySelector('#slot-height').value),
DEFAULT_GROUP_FONT: parseInt(dialog.querySelector('#group-font-size').value),
FONT_FAMILY: dialog.querySelector('#font-family').value,
NODE_FONT: dialog.querySelector('#font-family').value,
WIDGET_TEXT_SIZE: parseInt(dialog.querySelector('#widget-text-size').value)
};
applySettingsToComfyUI(newValues);
console.log('🌊✨ Fontifier applied:', newValues);
if (permanent) {
currentValues = { ...newValues };
console.log('🌊✨ Fontifier changes applied permanently (until page refresh)');
}
}
registerEndlessTool("Fontifier", createFontifierDialog);
})();
File diff suppressed because it is too large Load Diff
+164
View File
@@ -0,0 +1,164 @@
// === 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.background};
color: ${colors.text};
padding: 12px;
border: 1px solid ${colors.accent};
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
z-index: 99999;
transition: opacity 0.2s ease;
opacity: 1;
min-width: 180px;
`;
const dragBar = document.createElement("div");
dragBar.textContent = "→ Drag Me With This ←";
dragBar.style.cssText = `
padding: 4px;
background: rgba(255, 255, 255, 0.05);
cursor: move;
font-size: 12px;
text-align: center;
user-select: none;
border-bottom: 1px solid ${colors.border};
`;
menu.appendChild(dragBar);
endlessToolsRegistry.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 = "rgba(255, 255, 255, 0.1)";
btn.onmouseout = () => btn.style.background = "transparent";
btn.onclick = () => {
tool.callback();
menu.remove();
};
menu.appendChild(btn);
});
makeDraggable(menu, dragBar);
document.body.appendChild(menu);
}
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() {
let toolbar = document.querySelector('.comfyui-menu, .comfy-menu, [class*="menu"], [class*="toolbar"]');
if (!toolbar) {
const buttonGroups = document.querySelectorAll('[class*="button-group"], [class*="btn-group"], .comfyui-button-group');
toolbar = Array.from(buttonGroups).find(group => group.querySelectorAll('button').length > 0);
}
if (!toolbar) {
const allElements = document.querySelectorAll('*');
toolbar = Array.from(allElements).find(el => {
const buttons = el.querySelectorAll('button');
return buttons.length >= 2 && buttons.length <= 10;
});
}
if (!toolbar) {
toolbar = Array.from(document.querySelectorAll(".comfyui-button-group")).find(div =>
Array.from(div.querySelectorAll("button")).some(btn => btn.title === "Share")
);
}
return toolbar;
}
function getComfyUIColors() {
const computedStyle = getComputedStyle(document.documentElement);
return {
background: computedStyle.getPropertyValue('--comfy-menu-bg') || '#353535',
backgroundSecondary: computedStyle.getPropertyValue('--comfy-input-bg') || '#222',
border: computedStyle.getPropertyValue('--border-color') || '#999',
text: computedStyle.getPropertyValue('--input-text') || '#ddd',
accent: computedStyle.getPropertyValue('--comfy-accent-color') || '#5fc0e9' // fallback soft blue
};
}
function makeDraggable(element, handle = element) {
let offsetX = 0, offsetY = 0, isDown = false;
handle.onmousedown = (e) => {
isDown = true;
const rect = element.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
element.style.cursor = 'move';
element.style.position = 'fixed';
element.style.right = 'auto';
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;
};
};
}