added add button
This commit is contained in:
@@ -17,6 +17,7 @@ Currently it is still missing some features it should have.
|
|||||||
- Search `/`subdirectories of model directories based on your file structure (for example, `/styles/clothing`).
|
- Search `/`subdirectories of model directories based on your file structure (for example, `/styles/clothing`).
|
||||||
- Include models listed in ComfyUI's `extra_model_paths.yaml`.
|
- Include models listed in ComfyUI's `extra_model_paths.yaml`.
|
||||||
- Button to copy a model to the ComfyUI clipboard. (Embedding cannot be copied to the system clipboard with an http connection.)
|
- Button to copy a model to the ComfyUI clipboard. (Embedding cannot be copied to the system clipboard with an http connection.)
|
||||||
|
- Button to add model to ComfyUI graph. (For small screens/low resolution.)
|
||||||
- Right, left and bottom toggleable sidebar modes.
|
- Right, left and bottom toggleable sidebar modes.
|
||||||
- Drag model to graph to add or existing node to set model.
|
- Drag model to graph to add or existing node to set model.
|
||||||
- Drag embedding to textarea to append.
|
- Drag embedding to textarea to append.
|
||||||
@@ -51,10 +52,11 @@ Currently it is still missing some features it should have.
|
|||||||
- ☐ Exclude hidden folders with a `.` prefix.
|
- ☐ Exclude hidden folders with a `.` prefix.
|
||||||
- ☐ Include a optional string to always add to searches.
|
- ☐ Include a optional string to always add to searches.
|
||||||
- ☐ Enable optional checksum to detect if a model is already downloaded.
|
- ☐ Enable optional checksum to detect if a model is already downloaded.
|
||||||
- ☐ Change copy icon to an add icon `✚`.
|
- ☐ Enable/Disable add and copy buttons.
|
||||||
- ☐ Allow user to drag width of sidebar or height of bottom bar and remember it.
|
- ☐ Allow user to drag width of sidebar or height of bottom bar and remember it.
|
||||||
- ☐ Hide/Show model extension.
|
- ☐ Hide/Show model extension.
|
||||||
- ☐ Optionally remove embedding extension.
|
- ☐ Optionally remove embedding extension.
|
||||||
|
- ☐ Strict model drag on node widget textbox.
|
||||||
|
|
||||||
### Model info window/panel (server load/send on demand)
|
### Model info window/panel (server load/send on demand)
|
||||||
|
|
||||||
@@ -68,3 +70,7 @@ Currently it is still missing some features it should have.
|
|||||||
- ☐ Show preview images for videos.
|
- ☐ Show preview images for videos.
|
||||||
- ☐ If ffmpeg or cv2 available, extract the first frame of the video and use as image preview.
|
- ☐ If ffmpeg or cv2 available, extract the first frame of the video and use as image preview.
|
||||||
- ☐ Play preview video?
|
- ☐ Play preview video?
|
||||||
|
|
||||||
|
### Accessibility
|
||||||
|
|
||||||
|
- ☐ Proper naming and labeling.
|
||||||
|
|||||||
@@ -55,10 +55,8 @@
|
|||||||
|
|
||||||
.comfy-grid .item {
|
.comfy-grid .item {
|
||||||
position: relative;
|
position: relative;
|
||||||
aspect-ratio: 2/3;
|
width: 230px;
|
||||||
max-width: 230px;
|
height: 345px;
|
||||||
/*width: 230px;*/
|
|
||||||
/*height: 345px;*/
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -70,7 +68,7 @@
|
|||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-grid .item div {
|
.comfy-grid .model-label {
|
||||||
background-color: #000a;
|
background-color: #000a;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 2.2rem;
|
height: 2.2rem;
|
||||||
@@ -80,7 +78,7 @@
|
|||||||
line-height: 2.2rem;
|
line-height: 2.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-grid .item div > p {
|
.comfy-grid .model-label > p {
|
||||||
width: calc(100% - 2rem);
|
width: calc(100% - 2rem);
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -89,17 +87,18 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-grid .item div {
|
.comfy-grid .model-label {
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-grid .item div ::-webkit-scrollbar {
|
.comfy-grid .model-label ::-webkit-scrollbar {
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-grid .item .model-preview-overlay {
|
.comfy-grid .item .model-preview-overlay {
|
||||||
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -107,23 +106,29 @@
|
|||||||
background-color: rgba(0, 0, 0, 0);
|
background-color: rgba(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-grid .copy-model-button {
|
.comfy-grid .model-preview-top-right {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
top: 8px;
|
top: 8px;
|
||||||
right: 8px;
|
right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comfy-grid .model-button {
|
||||||
opacity: 0.65;
|
opacity: 0.65;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-grid .copy-model-button:hover {
|
.comfy-grid .model-button:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.icon-button.copy-model-button.copy-alert-success {
|
.comfy-grid .model-button.copy-alert-success {
|
||||||
color: green;
|
color: green;
|
||||||
border-color: green;
|
border-color: green;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.icon-button.copy-model-button.copy-alert-fail {
|
.comfy-grid .model-button.copy-alert-fail {
|
||||||
color: darkred;
|
color: darkred;
|
||||||
border-color: darkred;
|
border-color: darkred;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -274,15 +274,61 @@ class ModelGrid {
|
|||||||
}, true);
|
}, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static #addModel(event, modelType, path) {
|
static #addModel(event, modelType, path) {
|
||||||
|
if (modelType !== "embeddings") {
|
||||||
|
const nodeType = modelNodeType(modelType);
|
||||||
|
const widgetIndex = modelWidgetIndex(nodeType);
|
||||||
|
let node = LiteGraph.createNode(nodeType, null, []);
|
||||||
|
if (node) {
|
||||||
|
node.widgets[widgetIndex].value = path;
|
||||||
|
const selectedNodes = app.canvas.selected_nodes;
|
||||||
|
let isSelectedNode = false;
|
||||||
|
for (var i in selectedNodes) {
|
||||||
|
const selectedNode = selectedNodes[i];
|
||||||
|
// TODO: settings.model_add_offset
|
||||||
|
node.pos[0] = selectedNode.pos[0] + 25;
|
||||||
|
node.pos[1] = selectedNode.pos[1] + 25;
|
||||||
|
isSelectedNode = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!isSelectedNode) {
|
||||||
|
const graphMouse = app.canvas.graph_mouse;
|
||||||
|
node.pos[0] = graphMouse[0];
|
||||||
|
node.pos[1] = graphMouse[1];
|
||||||
|
}
|
||||||
|
app.graph.add(node, {doProcessChange: true});
|
||||||
|
app.canvas.selectNode(node);
|
||||||
|
}
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
else if (modelType === "embeddings") {
|
||||||
|
const text = pathToEmbeddingString(path);
|
||||||
|
const selectedNodes = app.canvas.selected_nodes;
|
||||||
|
for (var i in selectedNodes) {
|
||||||
|
const selectedNode = selectedNodes[i];
|
||||||
|
const nodeType = modelNodeType(modelType);
|
||||||
|
const widgetIndex = modelWidgetIndex(nodeType);
|
||||||
|
const target = selectedNode.widgets[widgetIndex].element;
|
||||||
|
if (target.type === "textarea") {
|
||||||
|
const currentText = target.value;
|
||||||
|
const sep = currentText.length === 0 || currentText.slice(-1).match(/\s/) ? "" : " ";
|
||||||
|
target.value = currentText + sep + text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static #dragAddModel(event, modelType, path) {
|
||||||
const target = document.elementFromPoint(event.x, event.y);
|
const target = document.elementFromPoint(event.x, event.y);
|
||||||
if (modelType !== "embeddings" && target.id === "graph-canvas") {
|
if (modelType !== "embeddings" && target.id === "graph-canvas") {
|
||||||
const nodeType = modelNodeType(modelType);
|
const nodeType = modelNodeType(modelType);
|
||||||
const widgetIndex = modelWidgetIndex(nodeType);
|
const widgetIndex = modelWidgetIndex(nodeType);
|
||||||
const pos = app.canvas.convertEventToCanvasOffset(event);
|
const pos = app.canvas.convertEventToCanvasOffset(event);
|
||||||
const nodeAtPos = app.graph.getNodeOnPos(pos[0], pos[1], app.canvas.visible_nodes);
|
const nodeAtPos = app.graph.getNodeOnPos(pos[0], pos[1], app.canvas.visible_nodes);
|
||||||
//if (nodeAtPos && nodeAtPos.type === nodeType && app.canvas.processNodeWidgets(nodeAtPos, pos, event) !== nodeAtPos.widgets[widgetIndex]) {
|
//if (nodeAtPos && nodeAtPos.type === nodeType && app.canvas.processNodeWidgets(nodeAtPos, pos, event) !== nodeAtPos.widgets[widgetIndex]) { // TODO: settings.strict_model_drag
|
||||||
if (nodeAtPos && nodeAtPos.type === nodeType) {
|
if (nodeAtPos && nodeAtPos.type === nodeType) {
|
||||||
let node = nodeAtPos;
|
let node = nodeAtPos;
|
||||||
node.widgets[widgetIndex].value = path;
|
node.widgets[widgetIndex].value = path;
|
||||||
@@ -319,7 +365,7 @@ class ModelGrid {
|
|||||||
successful = true;
|
successful = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.warn("Cannot copy embedding to the system clipboard; Try dragging the element instead.");
|
console.warn("Cannot copy the embedding to the system clipboard; Try dragging it instead.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (nodeType) {
|
else if (nodeType) {
|
||||||
@@ -345,11 +391,14 @@ class ModelGrid {
|
|||||||
|
|
||||||
static generateInnerHtml(models, modelType) {
|
static generateInnerHtml(models, modelType) {
|
||||||
if (models.length > 0) {
|
if (models.length > 0) {
|
||||||
|
// TODO: settings.show_model_add_button
|
||||||
|
// TODO: settings.show_model_copy_button
|
||||||
return models.map((item) => {
|
return models.map((item) => {
|
||||||
const uri = item.post ?? "no-post";
|
const uri = item.post ?? "no-post";
|
||||||
const imgUrl = `/model-manager/image-preview?uri=${uri}`;
|
const imgUrl = `/model-manager/image-preview?uri=${uri}`;
|
||||||
const addModel = (e) => ModelGrid.#addModel(e, modelType, item.path);
|
const dragAdd = (e) => ModelGrid.#dragAddModel(e, modelType, item.path);
|
||||||
const copy = (e) => ModelGrid.#copyModelToClipboard(e, modelType, item.path);
|
const clickCopy = (e) => ModelGrid.#copyModelToClipboard(e, modelType, item.path);
|
||||||
|
const clickAdd = (e) => ModelGrid.#addModel(e, modelType, item.path);
|
||||||
return $el("div.item", {}, [
|
return $el("div.item", {}, [
|
||||||
$el("img.model-preview", {
|
$el("img.model-preview", {
|
||||||
src: imgUrl,
|
src: imgUrl,
|
||||||
@@ -357,17 +406,28 @@ class ModelGrid {
|
|||||||
}),
|
}),
|
||||||
$el("div.model-preview-overlay", {
|
$el("div.model-preview-overlay", {
|
||||||
src: imgUrl,
|
src: imgUrl,
|
||||||
ondragend: (e) => addModel(e),
|
ondragend: (e) => dragAdd(e),
|
||||||
draggable: true,
|
draggable: true,
|
||||||
}),
|
}),
|
||||||
$el("button.icon-button.copy-model-button", {
|
$el("div.model-preview-top-right", {
|
||||||
type: "button",
|
|
||||||
textContent: "⧉︎",
|
|
||||||
onclick: (e) => copy(e),
|
|
||||||
draggable: false,
|
draggable: false,
|
||||||
}),
|
},
|
||||||
|
[
|
||||||
|
$el("button.icon-button.model-button", {
|
||||||
|
type: "button",
|
||||||
|
textContent: "⧉︎",
|
||||||
|
onclick: (e) => clickCopy(e),
|
||||||
|
draggable: false,
|
||||||
|
}),
|
||||||
|
$el("button.icon-button.model-button", {
|
||||||
|
type: "button",
|
||||||
|
textContent: "✚",
|
||||||
|
onclick: (e) => clickAdd(e),
|
||||||
|
draggable: false,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
$el("div.model-label", {
|
$el("div.model-label", {
|
||||||
ondragend: (e) => addModel(e),
|
ondragend: (e) => dragAdd(e),
|
||||||
draggable: true,
|
draggable: true,
|
||||||
}, [
|
}, [
|
||||||
$el("p", [item.name])
|
$el("p", [item.name])
|
||||||
|
|||||||
Reference in New Issue
Block a user