Some cleanup and new menu class.
This commit is contained in:
@@ -6,12 +6,15 @@ import {
|
||||
getClosestOrSelf,
|
||||
queryOne,
|
||||
query,
|
||||
setAttributes,
|
||||
} from "rgthree/common/utils_dom.js";
|
||||
import { logoCivitai, link, pencilColored, diskColored } from "rgthree/common/media/svgs.js";
|
||||
import { logoCivitai, link, pencilColored, diskColored, dotdotdot } from "rgthree/common/media/svgs.js";
|
||||
import { RgthreeModelInfo } from "typings/rgthree.js";
|
||||
import { SERVICE as MODEL_INFO_SERVICE } from "rgthree/common/model_info_service.js";
|
||||
import { rgthree } from "./rgthree.js";
|
||||
import { MenuButton } from "rgthree/common/menu.js";
|
||||
import { generateId } from "rgthree/common/shared_utils.js";
|
||||
import { rgthreeApi } from "rgthree/common/rgthree_api.js";
|
||||
|
||||
function injectCss(): Promise<void> {
|
||||
const href = "rgthree/common/css/dialog_model_info.css";
|
||||
@@ -152,20 +155,20 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
const info = this.modelInfo || {};
|
||||
const civitaiLink = info.links?.find((i) => i.includes("civitai.com/models"));
|
||||
const html = `
|
||||
<ul class="rgthree-info-tags">
|
||||
<li title="Type" class="-type -type-${(info.type || "").toLowerCase()}"><span>${
|
||||
<ul class="rgthree-info-area">
|
||||
<li title="Type" class="rgthree-info-tag -type -type-${(info.type || "").toLowerCase()}"><span>${
|
||||
info.type || ""
|
||||
}</span></li>
|
||||
<li title="Base Model" class="-basemodel -basemodel-${(
|
||||
<li title="Base Model" class="rgthree-info-tag -basemodel -basemodel-${(
|
||||
info.baseModel || ""
|
||||
).toLowerCase()}"><span>${info.baseModel || ""}</span></li>
|
||||
<li stub="menu"></li>
|
||||
${
|
||||
!civitaiLink
|
||||
? ""
|
||||
: `
|
||||
<li title="Visit on Civitai" class="-link -civitai"><a href="${civitaiLink}" target="_blank">${logoCivitai} Civitai ${link}</a></li>
|
||||
`
|
||||
<li class="rgthree-info-menu" stub="menu"></li>
|
||||
${''
|
||||
// !civitaiLink
|
||||
// ? ""
|
||||
// : `
|
||||
// <li title="Visit on Civitai" class="-link -civitai"><a href="${civitaiLink}" target="_blank">Civitai ${link}</a></li>
|
||||
// `
|
||||
}
|
||||
</ul>
|
||||
|
||||
@@ -188,14 +191,11 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
: !info.raw?.civitai
|
||||
? infoTableRow(
|
||||
"Civitai",
|
||||
`<button data-action="fetch-civitai">Fetch info from civitai</button>`,
|
||||
`<button class="rgthree-button" data-action="fetch-civitai">Fetch info from civitai</button>`,
|
||||
)
|
||||
: ""
|
||||
}
|
||||
${infoTableRow(
|
||||
"Base Model",
|
||||
(info.baseModel || " ") + (info.baseModelFile ? `(${info.baseModelFile})` : ""),
|
||||
)}
|
||||
|
||||
${infoTableRow(
|
||||
"Name",
|
||||
info.name || info.raw?.metadata?.ss_output_name || "",
|
||||
@@ -203,11 +203,22 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
"name",
|
||||
)}
|
||||
|
||||
${infoTableRow(
|
||||
${!info.baseModelFile && !info.baseModelFile ? '' : infoTableRow(
|
||||
"Base Model",
|
||||
(info.baseModel || "") + (info.baseModelFile ? ` (${info.baseModelFile})` : ""),
|
||||
)}
|
||||
|
||||
|
||||
${!info.trainedWords?.length ? '' : infoTableRow(
|
||||
"Trained Words",
|
||||
getTrainedWordsMarkup(info.trainedWords) ?? "",
|
||||
"Trained words from the metadata and/or civitai. Click to select for copy.",
|
||||
)}
|
||||
|
||||
${!info.raw?.metadata.ss_clip_skip || info.raw?.metadata.ss_clip_skip == 'None' ? '' : infoTableRow(
|
||||
"Clip Skip",
|
||||
info.raw?.metadata.ss_clip_skip
|
||||
)}
|
||||
${infoTableRow(
|
||||
"Strength Min",
|
||||
info.strengthMin ?? "",
|
||||
@@ -277,6 +288,37 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
|
||||
const div = $el("div", { html });
|
||||
|
||||
if (rgthree.isDevMode()) {
|
||||
setAttributes(queryOne('[stub="menu"]', div)!, {
|
||||
children: [
|
||||
new MenuButton({
|
||||
icon: dotdotdot,
|
||||
options: [
|
||||
{ label: "More Actions", type: "title" },
|
||||
{
|
||||
label: "Open API JSON",
|
||||
callback: async (e: PointerEvent) => {
|
||||
if (this.modelInfo?.file) {
|
||||
window.open(`rgthree/api/loras/info?file=${encodeURIComponent(this.modelInfo.file)}`);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Clear all local info",
|
||||
callback: async (e: PointerEvent) => {
|
||||
if (this.modelInfo?.file) {
|
||||
this.modelInfo = await MODEL_INFO_SERVICE.clearLoraFetchedData(this.modelInfo.file);
|
||||
this.setContent(this.getInfoContent());
|
||||
this.setTitle(this.modelInfo?.["name"] || this.modelInfo?.["file"] || "Unknown");
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
return div;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
|
||||
@import '../common/css/buttons.scss';
|
||||
@import '../common/css/dialog.scss';
|
||||
@import '../common/css/menu.scss';
|
||||
|
||||
.rgthree-dialog.-settings {
|
||||
width: 100%;
|
||||
|
||||
@@ -990,6 +990,9 @@ class Rgthree extends EventTarget {
|
||||
}
|
||||
|
||||
isDevMode() {
|
||||
if (window.location.href.includes("#rgthree-dev=false")) {
|
||||
return false;
|
||||
}
|
||||
return GLOBAL_LOG_LEVEL >= LogLevel.DEBUG || window.location.href.includes("#rgthree-dev");
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,12 @@ export async function showLoraChooser(
|
||||
event: PointerEvent,
|
||||
callback: ContextMenuEventListener,
|
||||
parentMenu?: ContextMenu,
|
||||
loras?: string[],
|
||||
) {
|
||||
const canvas = app.canvas as TLGraphCanvas;
|
||||
const loras = ["None", ...(await rgthreeApi.getLoras())];
|
||||
if (!loras) {
|
||||
loras = ["None", ...(await rgthreeApi.getLoras())];
|
||||
}
|
||||
new LiteGraph.ContextMenu(loras, {
|
||||
event: event,
|
||||
parentMenu,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
width: 90vw;
|
||||
max-width: 960px;
|
||||
|
||||
.rgthree-info-tags {
|
||||
.rgthree-info-area {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
@@ -22,7 +22,8 @@
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
> * {
|
||||
&.rgthree-info-tag > * {
|
||||
min-height: 24px;
|
||||
border-radius: 4px;
|
||||
line-height: 1;
|
||||
color: rgba(255,255,255,0.85);
|
||||
@@ -44,13 +45,8 @@
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
&:first-child {
|
||||
margin-right: .3em;
|
||||
display: none;
|
||||
}
|
||||
&:last-child {
|
||||
margin-left: .5em;
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,20 +60,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.-civitai > * {
|
||||
color: #ddd;
|
||||
background: #1b65aa;
|
||||
transition: all 0.15s ease-in-out;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
border-color: #1971c2;
|
||||
background: #1971c2;
|
||||
}
|
||||
}
|
||||
// &.-civitai > * {
|
||||
// color: #ddd;
|
||||
// background: #1b65aa;
|
||||
// transition: all 0.15s ease-in-out;
|
||||
// &:hover {
|
||||
// color: #fff;
|
||||
// border-color: #1971c2;
|
||||
// background: #1971c2;
|
||||
// }
|
||||
// }
|
||||
&.-type > * {
|
||||
background: rgb(73, 54, 94);
|
||||
color: rgb(228, 209, 248);
|
||||
}
|
||||
|
||||
&.rgthree-info-menu {
|
||||
margin-left: auto;
|
||||
|
||||
:not(#fakeid) & .rgthree-button {
|
||||
margin: 0;
|
||||
min-height: 24px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +159,7 @@
|
||||
display: block;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
> input, > textarea{
|
||||
padding: 5px 10px;
|
||||
border: 0;
|
||||
@@ -162,6 +174,12 @@
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
:not(#fakeid) & .rgthree-button[data-action="fetch-civitai"] {
|
||||
font-size: inherit;
|
||||
padding: 6px 16px;
|
||||
margin: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
tr[data-field-name="userNote"] td > span:first-child {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
.rgthree-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: fixed;
|
||||
z-index: 999999;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.08s ease-in-out;
|
||||
|
||||
color: #dde;
|
||||
background-color: #111;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 0 10px black !important;
|
||||
|
||||
> li {
|
||||
position: relative;
|
||||
padding: 4px 6px;
|
||||
z-index: 9999;
|
||||
white-space: nowrap;
|
||||
|
||||
&[role="button"] {
|
||||
background-color: var(--comfy-menu-bg) !important;
|
||||
color: var(--input-text);
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
filter: brightness(155%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[state^="measuring"] {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
}
|
||||
&[state="open"] {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
import { generateId, wait } from "./shared_utils.js";
|
||||
import { createElement as $el, getClosestOrSelf, setAttributes} from "./utils_dom.js";
|
||||
|
||||
/**
|
||||
* A menu. Mimics the comfy menu.
|
||||
*/
|
||||
class Menu {
|
||||
|
||||
private element: HTMLMenuElement = $el('menu.rgthree-menu');
|
||||
private callbacks: Map<string, (e: PointerEvent) => Promise<boolean|void>> = new Map();
|
||||
|
||||
private handleWindowPointerDownBound = this.handleWindowPointerDown.bind(this);
|
||||
|
||||
constructor(options: MenuOption[]) {
|
||||
this.setOptions(options);
|
||||
this.element.addEventListener('pointerup', async (e) => {
|
||||
const target = getClosestOrSelf(e.target as HTMLElement, "[data-callback],menu");
|
||||
if (e.which !== 1) {
|
||||
return;
|
||||
}
|
||||
const callback = target?.dataset?.['callback'];
|
||||
if (callback) {
|
||||
const halt = await this.callbacks.get(callback)?.(e);
|
||||
if (halt !== false) {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
});
|
||||
}
|
||||
|
||||
setOptions(options: MenuOption[]) {
|
||||
for (const option of options) {
|
||||
if (option.type === 'title') {
|
||||
this.element.appendChild($el(`li`, {
|
||||
html: option.label
|
||||
}));
|
||||
} else {
|
||||
const id = generateId(8);
|
||||
this.callbacks.set(id, async (e: PointerEvent) => { return option?.callback?.(e); });
|
||||
this.element.appendChild($el(`li[role="button"][data-callback="${id}"]`, {
|
||||
html: option.label
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toElement() {
|
||||
return this.element;
|
||||
}
|
||||
|
||||
async open(e: PointerEvent) {
|
||||
const parent = (e.target as HTMLElement).closest('div,dialog,body') as HTMLElement
|
||||
parent.appendChild(this.element);
|
||||
setAttributes(this.element, {
|
||||
style: {
|
||||
left: `${e.clientX + 16}px`,
|
||||
top: `${e.clientY - 16}px`,
|
||||
}
|
||||
});
|
||||
this.element.setAttribute('state', 'measuring-open');
|
||||
await wait(16);
|
||||
const rect = this.element.getBoundingClientRect();
|
||||
if (rect.right > window.innerWidth) {
|
||||
this.element.style.left = `${e.clientX - rect.width - 16}px`;
|
||||
await wait(16);
|
||||
}
|
||||
this.element.setAttribute('state', 'open');
|
||||
setTimeout(() => {
|
||||
window.addEventListener('pointerdown', this.handleWindowPointerDownBound);
|
||||
});
|
||||
}
|
||||
|
||||
handleWindowPointerDown(e:PointerEvent) {
|
||||
if (!this.element.contains(e.target as HTMLElement)) {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
||||
async close() {
|
||||
window.removeEventListener('pointerdown', this.handleWindowPointerDownBound);
|
||||
this.element.setAttribute('state', 'measuring-closed');
|
||||
await wait(16);
|
||||
this.element.setAttribute('state', 'closed');
|
||||
this.element.remove();
|
||||
}
|
||||
|
||||
isOpen() {
|
||||
return (this.element.getAttribute('state') || '').includes('open');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type MenuOption = {
|
||||
label: string;
|
||||
type?: 'title'|'item'|'separator';
|
||||
callback?: (e: PointerEvent) => void;
|
||||
}
|
||||
|
||||
type MenuButtonOptions = {
|
||||
icon: string;
|
||||
options: MenuOption[];
|
||||
}
|
||||
|
||||
export class MenuButton {
|
||||
|
||||
private options: MenuButtonOptions;
|
||||
private menu: Menu;
|
||||
|
||||
private element: HTMLButtonElement = $el('button.rgthree-button[data-action="open-menu"]')
|
||||
|
||||
constructor(options: MenuButtonOptions) {
|
||||
this.options = options;
|
||||
this.element.innerHTML = options.icon;
|
||||
this.menu = new Menu(options.options);
|
||||
|
||||
this.element.addEventListener('pointerdown', (e) => {
|
||||
if (!this.menu.isOpen()) {
|
||||
this.menu.open(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
toElement() {
|
||||
return this.element;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,7 +19,7 @@ class ModelInfoService {
|
||||
if (!refresh) {
|
||||
info = await rgthreeApi.getLoraInfo(file, light);
|
||||
} else {
|
||||
info = await rgthreeApi.refreshLoraInfo(file);
|
||||
info = await rgthreeApi.refreshLorasInfo(file);
|
||||
}
|
||||
if (!light) {
|
||||
this.loraToInfo.set(file, info);
|
||||
@@ -31,6 +31,12 @@ class ModelInfoService {
|
||||
return this.fetchLora(file, true);
|
||||
}
|
||||
|
||||
async clearLoraFetchedData(file: string) {
|
||||
await rgthreeApi.clearLorasInfo(file);
|
||||
this.loraToInfo.delete(file);
|
||||
return null;
|
||||
}
|
||||
|
||||
async saveLoraPartial(file: string, data: Partial<RgthreeModelInfo>) {
|
||||
let info = await rgthreeApi.saveLoraInfo(file, data);
|
||||
this.loraToInfo.set(file, info);
|
||||
|
||||
@@ -59,12 +59,6 @@ class RgthreeApi {
|
||||
);
|
||||
}
|
||||
|
||||
async refreshLoraInfo(lora: string): Promise<RgthreeModelInfo | null> {
|
||||
return await this.fetchApiJsonOrNull<RgthreeModelInfo>(
|
||||
`/loras/info/refresh?file=${encodeURIComponent(lora)}`,
|
||||
);
|
||||
}
|
||||
|
||||
async saveLoraInfo(
|
||||
lora: string,
|
||||
data: Partial<RgthreeModelInfo>,
|
||||
@@ -81,9 +75,20 @@ class RgthreeApi {
|
||||
return await this.fetchApiJsonOrNull<RgthreeModelInfo[]>(`/loras/info`);
|
||||
}
|
||||
|
||||
async refreshLorasInfo(): Promise<RgthreeModelInfo[] | null> {
|
||||
return await this.fetchApiJsonOrNull<RgthreeModelInfo[]>(`/loras/info/refresh`);
|
||||
async refreshLorasInfo(file: string): Promise<RgthreeModelInfo | null>;
|
||||
async refreshLorasInfo(): Promise<RgthreeModelInfo[] | null>;
|
||||
async refreshLorasInfo(file?: string) {
|
||||
const path = `/loras/info/refresh` + (file ? `?file=${encodeURIComponent(file)}` : '');
|
||||
const infos = await this.fetchApiJsonOrNull<RgthreeModelInfo[]|RgthreeModelInfo>(path);
|
||||
return infos;
|
||||
}
|
||||
|
||||
async clearLorasInfo(file?: string): Promise<void> {
|
||||
const path = `/loras/info/clear` + (file ? `?file=${encodeURIComponent(file)}` : '');
|
||||
await this.fetchApiJsonOrNull<RgthreeModelInfo[]>(path);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const rgthreeApi = new RgthreeApi();
|
||||
|
||||
+54
-20
@@ -1,8 +1,9 @@
|
||||
import { RgthreeDialog } from "../../rgthree/common/dialog.js";
|
||||
import { createElement as $el, empty, appendChildren, getClosestOrSelf, queryOne, query, } from "../../rgthree/common/utils_dom.js";
|
||||
import { logoCivitai, link, pencilColored, diskColored } from "../../rgthree/common/media/svgs.js";
|
||||
import { createElement as $el, empty, appendChildren, getClosestOrSelf, queryOne, query, setAttributes, } from "../../rgthree/common/utils_dom.js";
|
||||
import { logoCivitai, pencilColored, diskColored, dotdotdot } from "../../rgthree/common/media/svgs.js";
|
||||
import { SERVICE as MODEL_INFO_SERVICE } from "../../rgthree/common/model_info_service.js";
|
||||
import { rgthree } from "./rgthree.js";
|
||||
import { MenuButton } from "../../rgthree/common/menu.js";
|
||||
import { generateId } from "../../rgthree/common/shared_utils.js";
|
||||
function injectCss() {
|
||||
const href = "rgthree/common/css/dialog_model_info.css";
|
||||
@@ -134,19 +135,15 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
}
|
||||
}
|
||||
getInfoContent() {
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
|
||||
const info = this.modelInfo || {};
|
||||
const civitaiLink = (_a = info.links) === null || _a === void 0 ? void 0 : _a.find((i) => i.includes("civitai.com/models"));
|
||||
const html = `
|
||||
<ul class="rgthree-info-tags">
|
||||
<li title="Type" class="-type -type-${(info.type || "").toLowerCase()}"><span>${info.type || ""}</span></li>
|
||||
<li title="Base Model" class="-basemodel -basemodel-${(info.baseModel || "").toLowerCase()}"><span>${info.baseModel || ""}</span></li>
|
||||
<li stub="menu"></li>
|
||||
${!civitaiLink
|
||||
? ""
|
||||
: `
|
||||
<li title="Visit on Civitai" class="-link -civitai"><a href="${civitaiLink}" target="_blank">${logoCivitai} Civitai ${link}</a></li>
|
||||
`}
|
||||
<ul class="rgthree-info-area">
|
||||
<li title="Type" class="rgthree-info-tag -type -type-${(info.type || "").toLowerCase()}"><span>${info.type || ""}</span></li>
|
||||
<li title="Base Model" class="rgthree-info-tag -basemodel -basemodel-${(info.baseModel || "").toLowerCase()}"><span>${info.baseModel || ""}</span></li>
|
||||
<li class="rgthree-info-menu" stub="menu"></li>
|
||||
${''}
|
||||
</ul>
|
||||
|
||||
<table class="rgthree-info-table">
|
||||
@@ -159,20 +156,25 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
: ((_e = (_d = info.raw) === null || _d === void 0 ? void 0 : _d.civitai) === null || _e === void 0 ? void 0 : _e.error)
|
||||
? infoTableRow("Civitai", (_g = (_f = info.raw) === null || _f === void 0 ? void 0 : _f.civitai) === null || _g === void 0 ? void 0 : _g.error)
|
||||
: !((_h = info.raw) === null || _h === void 0 ? void 0 : _h.civitai)
|
||||
? infoTableRow("Civitai", `<button data-action="fetch-civitai">Fetch info from civitai</button>`)
|
||||
? infoTableRow("Civitai", `<button class="rgthree-button" data-action="fetch-civitai">Fetch info from civitai</button>`)
|
||||
: ""}
|
||||
${infoTableRow("Base Model", (info.baseModel || " ") + (info.baseModelFile ? `(${info.baseModelFile})` : ""))}
|
||||
|
||||
${infoTableRow("Name", info.name || ((_k = (_j = info.raw) === null || _j === void 0 ? void 0 : _j.metadata) === null || _k === void 0 ? void 0 : _k.ss_output_name) || "", "The name for display.", "name")}
|
||||
|
||||
${infoTableRow("Trained Words", (_l = getTrainedWordsMarkup(info.trainedWords)) !== null && _l !== void 0 ? _l : "", "Trained words from the metadata and/or civitai. Click to select for copy.")}
|
||||
${infoTableRow("Strength Min", (_m = info.strengthMin) !== null && _m !== void 0 ? _m : "", "The recommended minimum strength, In the Power Lora Loader node, strength will signal when it is below this threshold.", "strengthMin")}
|
||||
${infoTableRow("Strength Max", (_o = info.strengthMax) !== null && _o !== void 0 ? _o : "", "The recommended maximum strength. In the Power Lora Loader node, strength will signal when it is above this threshold.", "strengthMax")}
|
||||
${!info.baseModelFile && !info.baseModelFile ? '' : infoTableRow("Base Model", (info.baseModel || "") + (info.baseModelFile ? ` (${info.baseModelFile})` : ""))}
|
||||
|
||||
|
||||
${!((_l = info.trainedWords) === null || _l === void 0 ? void 0 : _l.length) ? '' : infoTableRow("Trained Words", (_m = getTrainedWordsMarkup(info.trainedWords)) !== null && _m !== void 0 ? _m : "", "Trained words from the metadata and/or civitai. Click to select for copy.")}
|
||||
|
||||
${!((_o = info.raw) === null || _o === void 0 ? void 0 : _o.metadata.ss_clip_skip) || ((_p = info.raw) === null || _p === void 0 ? void 0 : _p.metadata.ss_clip_skip) == 'None' ? '' : infoTableRow("Clip Skip", (_q = info.raw) === null || _q === void 0 ? void 0 : _q.metadata.ss_clip_skip)}
|
||||
${infoTableRow("Strength Min", (_r = info.strengthMin) !== null && _r !== void 0 ? _r : "", "The recommended minimum strength, In the Power Lora Loader node, strength will signal when it is below this threshold.", "strengthMin")}
|
||||
${infoTableRow("Strength Max", (_s = info.strengthMax) !== null && _s !== void 0 ? _s : "", "The recommended maximum strength. In the Power Lora Loader node, strength will signal when it is above this threshold.", "strengthMax")}
|
||||
${""}
|
||||
${infoTableRow("Additional Notes", (_p = info.userNote) !== null && _p !== void 0 ? _p : "", "Additional notes you'd like to keep and reference in the info dialog.", "userNote")}
|
||||
${infoTableRow("Additional Notes", (_t = info.userNote) !== null && _t !== void 0 ? _t : "", "Additional notes you'd like to keep and reference in the info dialog.", "userNote")}
|
||||
|
||||
</table>
|
||||
|
||||
<ul class="rgthree-info-images">${(_r = (_q = info.images) === null || _q === void 0 ? void 0 : _q.map((img) => {
|
||||
<ul class="rgthree-info-images">${(_v = (_u = info.images) === null || _u === void 0 ? void 0 : _u.map((img) => {
|
||||
var _a;
|
||||
return `
|
||||
<li>
|
||||
@@ -198,9 +200,41 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
: ""}
|
||||
</table-->
|
||||
</li>`;
|
||||
}).join("")) !== null && _r !== void 0 ? _r : ""}</ul>
|
||||
}).join("")) !== null && _v !== void 0 ? _v : ""}</ul>
|
||||
`;
|
||||
const div = $el("div", { html });
|
||||
if (rgthree.isDevMode()) {
|
||||
setAttributes(queryOne('[stub="menu"]', div), {
|
||||
children: [
|
||||
new MenuButton({
|
||||
icon: dotdotdot,
|
||||
options: [
|
||||
{ label: "More Actions", type: "title" },
|
||||
{
|
||||
label: "Open API JSON",
|
||||
callback: async (e) => {
|
||||
var _a;
|
||||
if ((_a = this.modelInfo) === null || _a === void 0 ? void 0 : _a.file) {
|
||||
window.open(`rgthree/api/loras/info?file=${encodeURIComponent(this.modelInfo.file)}`);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Clear all local info",
|
||||
callback: async (e) => {
|
||||
var _a, _b, _c;
|
||||
if ((_a = this.modelInfo) === null || _a === void 0 ? void 0 : _a.file) {
|
||||
this.modelInfo = await MODEL_INFO_SERVICE.clearLoraFetchedData(this.modelInfo.file);
|
||||
this.setContent(this.getInfoContent());
|
||||
this.setTitle(((_b = this.modelInfo) === null || _b === void 0 ? void 0 : _b["name"]) || ((_c = this.modelInfo) === null || _c === void 0 ? void 0 : _c["file"]) || "Unknown");
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
return div;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,6 +336,44 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont
|
||||
filter: blur(5px);
|
||||
}
|
||||
|
||||
.rgthree-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: fixed;
|
||||
z-index: 999999;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.08s ease-in-out;
|
||||
color: #dde;
|
||||
background-color: #111;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 0 10px black !important;
|
||||
}
|
||||
.rgthree-menu > li {
|
||||
position: relative;
|
||||
padding: 4px 6px;
|
||||
z-index: 9999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.rgthree-menu > li[role=button] {
|
||||
background-color: var(--comfy-menu-bg) !important;
|
||||
color: var(--input-text);
|
||||
cursor: pointer;
|
||||
}
|
||||
.rgthree-menu > li[role=button]:hover {
|
||||
filter: brightness(155%);
|
||||
}
|
||||
.rgthree-menu[state^=measuring] {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
}
|
||||
.rgthree-menu[state=open] {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -675,6 +675,9 @@ class Rgthree extends EventTarget {
|
||||
return this.logger.newSession(name);
|
||||
}
|
||||
isDevMode() {
|
||||
if (window.location.href.includes("#rgthree-dev=false")) {
|
||||
return false;
|
||||
}
|
||||
return GLOBAL_LOG_LEVEL >= LogLevel.DEBUG || window.location.href.includes("#rgthree-dev");
|
||||
}
|
||||
monitorBadLinks() {
|
||||
|
||||
@@ -3,10 +3,12 @@ import { rgthreeApi } from "../../rgthree/common/rgthree_api.js";
|
||||
const PASS_THROUGH = function (item) {
|
||||
return item;
|
||||
};
|
||||
export async function showLoraChooser(event, callback, parentMenu) {
|
||||
export async function showLoraChooser(event, callback, parentMenu, loras) {
|
||||
var _a, _b;
|
||||
const canvas = app.canvas;
|
||||
const loras = ["None", ...(await rgthreeApi.getLoras())];
|
||||
if (!loras) {
|
||||
loras = ["None", ...(await rgthreeApi.getLoras())];
|
||||
}
|
||||
new LiteGraph.ContextMenu(loras, {
|
||||
event: event,
|
||||
parentMenu,
|
||||
|
||||
@@ -2,24 +2,25 @@
|
||||
width: 90vw;
|
||||
max-width: 960px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags {
|
||||
.rgthree-info-dialog .rgthree-info-area {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li {
|
||||
.rgthree-info-dialog .rgthree-info-area > li {
|
||||
display: inline-flex;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li + li {
|
||||
.rgthree-info-dialog .rgthree-info-area > li + li {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li:not(.-link) + li.-link {
|
||||
.rgthree-info-dialog .rgthree-info-area > li:not(.-link) + li.-link {
|
||||
margin-left: auto;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * {
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-tag > * {
|
||||
min-height: 24px;
|
||||
border-radius: 4px;
|
||||
line-height: 1;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
@@ -37,38 +38,35 @@
|
||||
align-items: center;
|
||||
box-shadow: inset 0px 0px 0 1px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg {
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-tag > * > svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg:first-child {
|
||||
margin-right: 0.3em;
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg:last-child {
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-tag > * > svg:last-child {
|
||||
margin-left: 0.5em;
|
||||
fill: currentColor;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > *[href] {
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-tag > *[href] {
|
||||
box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.25), inset 0px -1px 0px rgba(0, 0, 0, 0.66);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > *:empty {
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-tag > *:empty {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-civitai > * {
|
||||
color: #ddd;
|
||||
background: #1b65aa;
|
||||
transition: all 0.15s ease-in-out;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-civitai > *:hover {
|
||||
color: #fff;
|
||||
border-color: #1971c2;
|
||||
background: #1971c2;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-type > * {
|
||||
.rgthree-info-dialog .rgthree-info-area > li.-type > * {
|
||||
background: rgb(73, 54, 94);
|
||||
color: rgb(228, 209, 248);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-menu {
|
||||
margin-left: auto;
|
||||
}
|
||||
:not(#fakeid) .rgthree-info-dialog .rgthree-info-area > li.rgthree-info-menu .rgthree-button {
|
||||
margin: 0;
|
||||
min-height: 24px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-menu svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table {
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0px;
|
||||
@@ -145,6 +143,11 @@
|
||||
.rgthree-info-dialog .rgthree-info-table td > input:only-child, .rgthree-info-dialog .rgthree-info-table td > textarea:only-child {
|
||||
width: 100%;
|
||||
}
|
||||
:not(#fakeid) .rgthree-info-dialog .rgthree-info-table td .rgthree-button[data-action=fetch-civitai] {
|
||||
font-size: inherit;
|
||||
padding: 6px 16px;
|
||||
margin: 2px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr[data-field-name=userNote] td > span:first-child {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
.rgthree-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: fixed;
|
||||
z-index: 999999;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.08s ease-in-out;
|
||||
color: #dde;
|
||||
background-color: #111;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 0 10px black !important;
|
||||
}
|
||||
.rgthree-menu > li {
|
||||
position: relative;
|
||||
padding: 4px 6px;
|
||||
z-index: 9999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.rgthree-menu > li[role=button] {
|
||||
background-color: var(--comfy-menu-bg) !important;
|
||||
color: var(--input-text);
|
||||
cursor: pointer;
|
||||
}
|
||||
.rgthree-menu > li[role=button]:hover {
|
||||
filter: brightness(155%);
|
||||
}
|
||||
.rgthree-menu[state^=measuring] {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
}
|
||||
.rgthree-menu[state=open] {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import { generateId, wait } from "./shared_utils.js";
|
||||
import { createElement as $el, getClosestOrSelf, setAttributes } from "./utils_dom.js";
|
||||
class Menu {
|
||||
constructor(options) {
|
||||
this.element = $el('menu.rgthree-menu');
|
||||
this.callbacks = new Map();
|
||||
this.handleWindowPointerDownBound = this.handleWindowPointerDown.bind(this);
|
||||
this.setOptions(options);
|
||||
this.element.addEventListener('pointerup', async (e) => {
|
||||
var _a, _b;
|
||||
const target = getClosestOrSelf(e.target, "[data-callback],menu");
|
||||
if (e.which !== 1) {
|
||||
return;
|
||||
}
|
||||
const callback = (_a = target === null || target === void 0 ? void 0 : target.dataset) === null || _a === void 0 ? void 0 : _a['callback'];
|
||||
if (callback) {
|
||||
const halt = await ((_b = this.callbacks.get(callback)) === null || _b === void 0 ? void 0 : _b(e));
|
||||
if (halt !== false) {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
});
|
||||
}
|
||||
setOptions(options) {
|
||||
for (const option of options) {
|
||||
if (option.type === 'title') {
|
||||
this.element.appendChild($el(`li`, {
|
||||
html: option.label
|
||||
}));
|
||||
}
|
||||
else {
|
||||
const id = generateId(8);
|
||||
this.callbacks.set(id, async (e) => { var _a; return (_a = option === null || option === void 0 ? void 0 : option.callback) === null || _a === void 0 ? void 0 : _a.call(option, e); });
|
||||
this.element.appendChild($el(`li[role="button"][data-callback="${id}"]`, {
|
||||
html: option.label
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
toElement() {
|
||||
return this.element;
|
||||
}
|
||||
async open(e) {
|
||||
const parent = e.target.closest('div,dialog,body');
|
||||
parent.appendChild(this.element);
|
||||
setAttributes(this.element, {
|
||||
style: {
|
||||
left: `${e.clientX + 16}px`,
|
||||
top: `${e.clientY - 16}px`,
|
||||
}
|
||||
});
|
||||
this.element.setAttribute('state', 'measuring-open');
|
||||
await wait(16);
|
||||
const rect = this.element.getBoundingClientRect();
|
||||
if (rect.right > window.innerWidth) {
|
||||
this.element.style.left = `${e.clientX - rect.width - 16}px`;
|
||||
await wait(16);
|
||||
}
|
||||
this.element.setAttribute('state', 'open');
|
||||
setTimeout(() => {
|
||||
window.addEventListener('pointerdown', this.handleWindowPointerDownBound);
|
||||
});
|
||||
}
|
||||
handleWindowPointerDown(e) {
|
||||
if (!this.element.contains(e.target)) {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
async close() {
|
||||
window.removeEventListener('pointerdown', this.handleWindowPointerDownBound);
|
||||
this.element.setAttribute('state', 'measuring-closed');
|
||||
await wait(16);
|
||||
this.element.setAttribute('state', 'closed');
|
||||
this.element.remove();
|
||||
}
|
||||
isOpen() {
|
||||
return (this.element.getAttribute('state') || '').includes('open');
|
||||
}
|
||||
}
|
||||
export class MenuButton {
|
||||
constructor(options) {
|
||||
this.element = $el('button.rgthree-button[data-action="open-menu"]');
|
||||
this.options = options;
|
||||
this.element.innerHTML = options.icon;
|
||||
this.menu = new Menu(options.options);
|
||||
this.element.addEventListener('pointerdown', (e) => {
|
||||
if (!this.menu.isOpen()) {
|
||||
this.menu.open(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
toElement() {
|
||||
return this.element;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ class ModelInfoService {
|
||||
info = await rgthreeApi.getLoraInfo(file, light);
|
||||
}
|
||||
else {
|
||||
info = await rgthreeApi.refreshLoraInfo(file);
|
||||
info = await rgthreeApi.refreshLorasInfo(file);
|
||||
}
|
||||
if (!light) {
|
||||
this.loraToInfo.set(file, info);
|
||||
@@ -25,6 +25,11 @@ class ModelInfoService {
|
||||
async refreshLora(file) {
|
||||
return this.fetchLora(file, true);
|
||||
}
|
||||
async clearLoraFetchedData(file) {
|
||||
await rgthreeApi.clearLorasInfo(file);
|
||||
this.loraToInfo.delete(file);
|
||||
return null;
|
||||
}
|
||||
async saveLoraPartial(file, data) {
|
||||
let info = await rgthreeApi.saveLoraInfo(file, data);
|
||||
this.loraToInfo.set(file, info);
|
||||
|
||||
@@ -38,9 +38,6 @@ class RgthreeApi {
|
||||
async getLoraInfo(lora, light = true) {
|
||||
return await this.fetchApiJsonOrNull(`/loras/info?file=${encodeURIComponent(lora)}&light=${light ? 1 : 0}`, { cache: "no-store" });
|
||||
}
|
||||
async refreshLoraInfo(lora) {
|
||||
return await this.fetchApiJsonOrNull(`/loras/info/refresh?file=${encodeURIComponent(lora)}`);
|
||||
}
|
||||
async saveLoraInfo(lora, data) {
|
||||
const body = new FormData();
|
||||
body.append("json", JSON.stringify(data));
|
||||
@@ -49,8 +46,15 @@ class RgthreeApi {
|
||||
async getLorasInfo() {
|
||||
return await this.fetchApiJsonOrNull(`/loras/info`);
|
||||
}
|
||||
async refreshLorasInfo() {
|
||||
return await this.fetchApiJsonOrNull(`/loras/info/refresh`);
|
||||
async refreshLorasInfo(file) {
|
||||
const path = `/loras/info/refresh` + (file ? `?file=${encodeURIComponent(file)}` : '');
|
||||
const infos = await this.fetchApiJsonOrNull(path);
|
||||
return infos;
|
||||
}
|
||||
async clearLorasInfo(file) {
|
||||
const path = `/loras/info/clear` + (file ? `?file=${encodeURIComponent(file)}` : '');
|
||||
await this.fetchApiJsonOrNull(path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
export const rgthreeApi = new RgthreeApi();
|
||||
|
||||
Reference in New Issue
Block a user