Skip to content

Commit

Permalink
feat: ✨ image feed
Browse files Browse the repository at this point in the history
forked from @pythongosssss with a few changes:
- a light box
- a way to load history images (i.e current session images)
  • Loading branch information
melMass committed Jul 6, 2023
1 parent 7585624 commit 99eb5ae
Show file tree
Hide file tree
Showing 2 changed files with 313 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
__pycache__
*.py[cod]
*.onnx
*.onnx
node_modules/
311 changes: 311 additions & 0 deletions web/imageFeed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
import { api } from "/scripts/api.js";
import { app } from "/scripts/app.js";

// forked from pysssss's imageFeed.js

const styles = {
lighbox: {
position: "fixed",
top: 0,
left: 0,
width: "100vw",
height: "100vh",
background: "rgba(0,0,0,0.5)",
display: "none",
justifyContent: "center",
alignItems: "center",
zIndex: 999,
},
lightboxBtn: (extra) => ({
position: "absolute",
top: "50%",
background: "none",
border: "none",
color: "#fff",
zIndex: 9999999,
fontSize: "30px",
cursor: "pointer",
pointerEvents: "bounding-box",
...extra,
})
,
img_list: {

minHeight: "30px",
maxHeight: "300px",
width: "100vw",
position: "absolute",
bottom: 0,
zIndex: 9999999,
background: "#333",
overflow: "auto",
}
}

let currentImageIndex = 0;
const imageUrls = [];

let image_menu = null

app.registerExtension({
name: "mtb.ImageFeed",
setup: async () => {
// - HTML & CSS
//- lightbox
const lightboxContainer = document.createElement("div");
Object.assign(lightboxContainer.style, styles.lighbox);

const lightboxImage = document.createElement("img");
Object.assign(lightboxImage.style, {
maxHeight: "100%",
maxWidth: "100%",
borderRadius: "5px",
});

// previous and next buttons
const lightboxPrevBtn = document.createElement("button");
const lightboxNextBtn = document.createElement("button");

lightboxPrevBtn.textContent = "❮";
lightboxNextBtn.textContent = "❯";

Object.assign(lightboxPrevBtn.style, styles.lightboxBtn({ left: "0%" }));
Object.assign(lightboxNextBtn.style, styles.lightboxBtn({ right: "0%" }));

// close button
const lightboxCloseBtn = document.createElement("button");
Object.assign(lightboxCloseBtn.style, styles.lightboxBtn({ right: "0", top: "0" }));
lightboxCloseBtn.textContent = "❌";

const lightboxButtons = document.createElement("div");
Object.assign(lightboxButtons.style, {
position: "absolute",
top: "0%",
right: "0%",
// transform: "translate(50%, -50%)",
height: "100%",
width: "100%",
background: "none",
border: "none",
color: "#fff",
fontSize: "30px",
cursor: "pointer",
pointerEvents: "none",
});

lightboxButtons.append(lightboxPrevBtn, lightboxNextBtn, lightboxCloseBtn);
lightboxContainer.append(lightboxButtons, lightboxImage);

//- image list
const imageListContainer = document.createElement("div");
Object.assign(imageListContainer.style, styles.img_list);


const createImgListBtn = (text, style) => {
const btn = document.createElement("button");
btn.type = "button";
btn.textContent = text;
Object.assign(btn.style, {
...style,
border: "none",
color: "#fff",
background: "none",
height: "20px",
cursor: "pointer",
position: "absolute",
top: "5px",
fontSize: "12px",
lineHeight: "12px",
});
imageListContainer.append(btn);
return btn;
}
const showBtn = document.createElement("button");
const closeBtn = createImgListBtn("❌", {
width: "20px",
textIndent: "-4px",
right: "5px",
});
const loadButton = createImgListBtn("Load Session History", {
right: "90px",
});
const clearButton = createImgListBtn("Clear", {
right: "30px",
});


//- tools popup button
showBtn.classList.add("comfy-settings-btn");
Object.assign(showBtn.style, {
right: "16px",
cursor: "pointer",
display: "none",
});

//- append to DOM
document.body.append(imageListContainer);


showBtn.textContent = "🖼️";
showBtn.onclick = () => {
imageListContainer.style.display = "block";
showBtn.style.display = "none";
};
document.querySelector(".comfy-settings-btn").after(showBtn);
document.querySelector(".comfy-settings-btn").after(lightboxContainer);



// for (const { output } of history) {
// if (output?.images) {
// for (const src of output.images) {
// const img = document.createElement("img");
// const but = document.createElement("button");

//- callbacks
closeBtn.onclick = () => {
imageListContainer.style.display = "none";
showBtn.style.display = "unset";
};

clearButton.onclick = () => {
imageListContainer.replaceChildren(closeBtn, clearButton, loadButton);
}

lightboxNextBtn.onclick = () => {
currentImageIndex = (currentImageIndex + 1) % imageUrls.length;
const imageUrl = imageUrls[currentImageIndex];
lightboxImage.src = imageUrl;
};

// Modify the lightboxPrevBtn onclick callback
lightboxPrevBtn.onclick = () => {
currentImageIndex = (currentImageIndex - 1 + imageUrls.length) % imageUrls.length;
const imageUrl = imageUrls[currentImageIndex];
lightboxImage.src = imageUrl;
};


lightboxCloseBtn.onclick = () => {
lightboxContainer.style.display = "none";
};
lightboxImage.onclick = lightboxNextBtn.onclick;
/**
* This is the function that creates the image buttons for the image list
* They are wrapped in a button so that they can be clicked and open
* the image in the lightbox.
* @param {*} src
*/
const createImageBtn = (src) => {
console.log(`making image ${src.filename}`);
const img = document.createElement("img");
const but = document.createElement("button");

Object.assign(but.style, {
height: "120px",
width: "120px",
});
Object.assign(img.style, {
width: "100%",
height: "100%",
objectFit: "scale-down",
});

img.src = `/view?filename=${encodeURIComponent(src.filename)}&type=${src.type}&subfolder=${encodeURIComponent(
src.subfolder
)}`;

imageUrls.push(img.src);

console.log(img.src)

but.onclick = () => {
lightboxContainer.style.display = "flex";
// add the same image to the lightbox
lightboxImage.src = img.src;
// lighboxContainer.replaceChildren(lightboxButtons, img);

};

// add right click menu
but.addEventListener("contextmenu", (e) => {
e.preventDefault();

if (image_menu) {
image_menu.remove();
}

image_menu = document.createElement("div");
Object.assign(image_menu.style, {
position: "absolute",
top: `${e.clientY}px`,
left: `${e.clientX}px`,
background: "#333",
color: "#fff",
padding: "5px",
borderRadius: "5px",
zIndex: 999,
});
const load_img = document.createElement("button");
load_img.textContent = "Load";
load_img.onclick = () => {
app.handleFile(img.src)

}

image_menu.appendChild(load_img)
document.body.appendChild(image_menu)
})

but.append(img)
imageListContainer.prepend(but)
};


loadButton.onclick = async () => {
const all_history = await api.getHistory();
for (const history of all_history.History) {
if (history.outputs) {
for (const key of Object.keys(history.outputs)) {
console.log(key)
for (const im of history.outputs[key].images) {
console.log(im)
createImageBtn(im)
}
}
// for (const src of outputs.outputs.images) {
// console.log(src)
// makeImage(`${src.subfolder}/${src.filename}`)
// }
}
}
}

///////-------

// const all_history = await api.getHistory()
// for (const history of all_history.History) {
// if (history.outputs) {
// for (const key of Object.keys(history.outputs)) {
// for (const im of history.outputs[key].images) {
// makeImage(im)
// }
// }
// // for (const src of outputs.outputs.images) {
// // console.log(src)
// // makeImage(`${src.subfolder}/${src.filename}`)
// // }
// }
// }

//- Hook into the API
api.addEventListener("executed", ({ detail }) => {
if (detail?.output?.images) {
for (const src of detail.output.images) {
console.log(`Adding ${src} to image feed`)
createImageBtn(src)
}
}
})
}
})

0 comments on commit 99eb5ae

Please sign in to comment.