Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Includes 30 custom nodes committed directly, 7 Civitai-exclusive loras stored via Git LFS, and a setup script that installs all dependencies and downloads HuggingFace-hosted models on vast.ai. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
198 lines
7.6 KiB
JavaScript
198 lines
7.6 KiB
JavaScript
import { app } from "../../scripts/app.js";
|
|
import { iconGear, iconStarFilled, logoRgthreeAsync } from "../../rgthree/common/media/svgs.js";
|
|
import { $el, empty } from "../../rgthree/common/utils_dom.js";
|
|
import { SERVICE as BOOKMARKS_SERVICE } from "./services/bookmarks_services.js";
|
|
import { SERVICE as CONFIG_SERVICE } from "./services/config_service.js";
|
|
import { RgthreeConfigDialog } from "./config.js";
|
|
import { wait } from "../../rgthree/common/shared_utils.js";
|
|
let rgthreeButtonGroup = null;
|
|
function addRgthreeTopBarButtons() {
|
|
var _a, _b, _c;
|
|
if (!CONFIG_SERVICE.getFeatureValue("comfy_top_bar_menu.enabled")) {
|
|
if ((_a = rgthreeButtonGroup === null || rgthreeButtonGroup === void 0 ? void 0 : rgthreeButtonGroup.element) === null || _a === void 0 ? void 0 : _a.parentElement) {
|
|
rgthreeButtonGroup.element.parentElement.removeChild(rgthreeButtonGroup.element);
|
|
}
|
|
return;
|
|
}
|
|
else if (rgthreeButtonGroup) {
|
|
(_b = app.menu) === null || _b === void 0 ? void 0 : _b.settingsGroup.element.before(rgthreeButtonGroup.element);
|
|
return;
|
|
}
|
|
const buttons = [];
|
|
const rgthreeButton = new RgthreeComfyButton({
|
|
icon: "<svg></svg>",
|
|
tooltip: "rgthree-comfy",
|
|
primary: true,
|
|
enabled: true,
|
|
classList: "comfyui-button comfyui-menu-mobile-collapse primary",
|
|
});
|
|
buttons.push(rgthreeButton);
|
|
logoRgthreeAsync().then((t) => {
|
|
rgthreeButton.setIcon(t);
|
|
});
|
|
rgthreeButton.withPopup(new RgthreeComfyPopup({ target: rgthreeButton.element }, $el("menu.rgthree-menu.rgthree-top-menu", {
|
|
children: [
|
|
$el("li", {
|
|
child: $el("button.rgthree-button-reset", {
|
|
html: iconGear + "Settings (rgthree-comfy)",
|
|
onclick: () => new RgthreeConfigDialog().show(),
|
|
}),
|
|
}),
|
|
$el("li", {
|
|
child: $el("button.rgthree-button-reset", {
|
|
html: iconStarFilled + "Star on Github",
|
|
onclick: () => window.open("https://github.com/rgthree/rgthree-comfy", "_blank"),
|
|
}),
|
|
}),
|
|
],
|
|
})), "click");
|
|
if (CONFIG_SERVICE.getFeatureValue("comfy_top_bar_menu.button_bookmarks.enabled")) {
|
|
const bookmarksListEl = $el("menu.rgthree-menu.rgthree-top-menu");
|
|
bookmarksListEl.appendChild($el("li.rgthree-message", {
|
|
child: $el("span", { text: "No bookmarks in current workflow." }),
|
|
}));
|
|
const bookmarksButton = new RgthreeComfyButton({
|
|
icon: "bookmark",
|
|
tooltip: "Workflow Bookmarks (rgthree-comfy)",
|
|
});
|
|
const bookmarksPopup = new RgthreeComfyPopup({ target: bookmarksButton.element, modal: false }, bookmarksListEl);
|
|
bookmarksPopup.onOpen(() => {
|
|
const bookmarks = BOOKMARKS_SERVICE.getCurrentBookmarks();
|
|
empty(bookmarksListEl);
|
|
if (bookmarks.length) {
|
|
for (const b of bookmarks) {
|
|
bookmarksListEl.appendChild($el("li", {
|
|
child: $el("button.rgthree-button-reset", {
|
|
text: `[${b.shortcutKey}] ${b.title}`,
|
|
onclick: () => {
|
|
b.canvasToBookmark();
|
|
},
|
|
}),
|
|
}));
|
|
}
|
|
}
|
|
else {
|
|
bookmarksListEl.appendChild($el("li.rgthree-message", {
|
|
child: $el("span", { text: "No bookmarks in current workflow." }),
|
|
}));
|
|
}
|
|
});
|
|
bookmarksButton.withPopup(bookmarksPopup, "hover");
|
|
buttons.push(bookmarksButton);
|
|
}
|
|
rgthreeButtonGroup = new RgthreeComfyButtonGroup(...buttons);
|
|
(_c = app.menu) === null || _c === void 0 ? void 0 : _c.settingsGroup.element.before(rgthreeButtonGroup.element);
|
|
}
|
|
app.registerExtension({
|
|
name: "rgthree.TopMenu",
|
|
async setup() {
|
|
addRgthreeTopBarButtons();
|
|
CONFIG_SERVICE.addEventListener("config-change", ((e) => {
|
|
var _a, _b;
|
|
if ((_b = (_a = e.detail) === null || _a === void 0 ? void 0 : _a.key) === null || _b === void 0 ? void 0 : _b.includes("features.comfy_top_bar_menu")) {
|
|
addRgthreeTopBarButtons();
|
|
}
|
|
}));
|
|
},
|
|
});
|
|
class RgthreeComfyButtonGroup {
|
|
constructor(...buttons) {
|
|
this.element = $el("div.rgthree-comfybar-top-button-group");
|
|
this.buttons = buttons;
|
|
this.update();
|
|
}
|
|
insert(button, index) {
|
|
this.buttons.splice(index, 0, button);
|
|
this.update();
|
|
}
|
|
append(button) {
|
|
this.buttons.push(button);
|
|
this.update();
|
|
}
|
|
remove(indexOrButton) {
|
|
if (typeof indexOrButton !== "number") {
|
|
indexOrButton = this.buttons.indexOf(indexOrButton);
|
|
}
|
|
if (indexOrButton > -1) {
|
|
const btn = this.buttons.splice(indexOrButton, 1);
|
|
this.update();
|
|
return btn;
|
|
}
|
|
return null;
|
|
}
|
|
update() {
|
|
this.element.replaceChildren(...this.buttons.map((b) => { var _a; return (_a = b["element"]) !== null && _a !== void 0 ? _a : b; }));
|
|
}
|
|
}
|
|
class RgthreeComfyButton {
|
|
constructor(opts) {
|
|
this.element = $el("button.rgthree-comfybar-top-button.rgthree-button-reset.rgthree-button");
|
|
this.iconElement = $el("span.rgthree-button-icon");
|
|
opts.icon && this.setIcon(opts.icon);
|
|
opts.tooltip && this.element.setAttribute("title", opts.tooltip);
|
|
opts.primary && this.element.classList.add("-primary");
|
|
}
|
|
setIcon(iconOrMarkup) {
|
|
const markup = iconOrMarkup.startsWith("<")
|
|
? iconOrMarkup
|
|
: `<i class="mdi mdi-${iconOrMarkup}"></i>`;
|
|
this.iconElement.innerHTML = markup;
|
|
if (!this.iconElement.parentElement) {
|
|
this.element.appendChild(this.iconElement);
|
|
}
|
|
}
|
|
withPopup(popup, trigger) {
|
|
if (trigger === "click") {
|
|
this.element.addEventListener("click", () => {
|
|
popup.open();
|
|
});
|
|
}
|
|
if (trigger === "hover") {
|
|
this.element.addEventListener("pointerenter", () => {
|
|
popup.open();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
class RgthreeComfyPopup {
|
|
constructor(opts, element) {
|
|
this.onOpenFn = null;
|
|
this.onWindowClickBound = this.onWindowClick.bind(this);
|
|
this.element = element;
|
|
this.opts = opts;
|
|
opts.target && (this.target = opts.target);
|
|
opts.modal && this.element.classList.add("-modal");
|
|
}
|
|
async open() {
|
|
if (!this.target) {
|
|
throw new Error("No target for RgthreeComfyPopup");
|
|
}
|
|
if (this.onOpenFn) {
|
|
await this.onOpenFn();
|
|
}
|
|
await wait(16);
|
|
const rect = this.target.getBoundingClientRect();
|
|
this.element.setAttribute("state", "measuring");
|
|
document.body.appendChild(this.element);
|
|
this.element.style.position = "fixed";
|
|
this.element.style.left = `${rect.left}px`;
|
|
this.element.style.top = `${rect.top + rect.height}px`;
|
|
this.element.setAttribute("state", "open");
|
|
if (this.opts.modal) {
|
|
document.body.classList.add("rgthree-modal-menu-open");
|
|
}
|
|
window.addEventListener("click", this.onWindowClickBound);
|
|
}
|
|
close() {
|
|
this.element.remove();
|
|
document.body.classList.remove("rgthree-modal-menu-open");
|
|
window.removeEventListener("click", this.onWindowClickBound);
|
|
}
|
|
onOpen(fn) {
|
|
this.onOpenFn = fn;
|
|
}
|
|
onWindowClick() {
|
|
this.close();
|
|
}
|
|
}
|