Files
olivv-cs-ComfyUI-FunPack/easy_gen/frontend/project_menu.js
T
digital-garbage 9791cb8ccd Add FunPack Easy Gen (simplified single-scene UI) and a /funpack Hub
Easy Gen is a new Fooocus-style frontend at /funpack/easy — big preview,
one prompt box, Upload, Generate, and an Advanced settings panel — built
entirely on the Movie Editor's existing project format and API (no new
backend endpoints), so projects stay interchangeable between the two UIs.

The Hub at /funpack links to both UIs and surfaces version/branch/commit
plus an Update/Restart action reusing the Editor's git_update.py flow.

Startup now prints full host:port URLs for all three (Hub, Editor, Easy
Gen) via a new config.comfy_display_url() helper.

Also: settings_window.js's About section now labels itself via
window.FunPackAppName instead of hardcoding "Cutting Room", and Easy
Gen's boot-error banner accumulates distinct errors instead of
overwriting, so a cascading failure (e.g. dom.js not loading) surfaces
its root cause instead of just the last script in load order.
2026-07-23 16:37:26 +03:00

105 lines
3.5 KiB
JavaScript

// "FunPack Easy Gen" project picker — same /funpack/movie/api/projects* calls
// as the Editor's welcome.js / menubar.js "Open recent" menu, reimplemented as
// a small standalone modal (welcome.js/menubar.js are wired into the full
// Editor chrome and not reusable in isolation).
(function () {
const { el, clear } = window.dom;
const API = window.MovieEditorAPI;
const S = window.Store;
let overlay = null;
const loadFileInput = (function () {
const inp = document.createElement("input");
inp.type = "file";
inp.accept = ".json,.funpack_project.json,application/json";
inp.style.display = "none";
inp.onchange = async () => {
const file = inp.files?.[0];
inp.value = "";
if (!file) return;
try {
const data = JSON.parse(await file.text());
const p = await API.importProject(data);
S.set({ project: p });
close();
} catch (e) {
alert("Could not load project file: " + (e.message || e));
}
};
document.body.appendChild(inp);
return inp;
})();
function close() {
if (overlay) { overlay.remove(); overlay = null; }
}
async function open({ dismissable } = {}) {
close();
overlay = el("div", "modal-overlay");
if (!dismissable) overlay.style.pointerEvents = "auto";
const box = el("div", "modal modal-wide");
const head = el("div", "modal-head");
head.append(el("div", "modal-title", "FunPack Easy Gen"));
if (dismissable) {
const x = el("button", "btn ghost tiny", "✕");
x.onclick = close;
head.append(el("div", "modal-head-right"), x);
}
box.append(head);
const content = el("div", "modal-content");
box.append(content);
const actions = el("div", "welcome-actions");
const mkBtn = (label, cls, hint, fn) => {
const b = el("button", "welcome-btn" + (cls ? " " + cls : ""));
b.type = "button";
b.append(el("span", "welcome-btn-label", label));
if (hint) b.append(el("span", "welcome-btn-hint", hint));
b.onclick = fn;
return b;
};
actions.append(
mkBtn("New Generation", "primary", "Start with a blank prompt", async () => {
await S.createProject("Untitled");
close();
}),
mkBtn("Load Project File…", "", "Import a .funpack_project.json", () => loadFileInput.click()),
);
content.append(actions);
content.append(el("div", "sw-rows-label", "Recent"));
const recentWrap = el("div", "sw-rows");
content.append(recentWrap);
try {
const list = await S.listProjects();
clear(recentWrap);
if (!list.length) {
recentWrap.append(el("div", "sw-hint", "No projects yet."));
}
list.slice(0, 12).forEach((p) => {
const row = el("div", "sw-row");
const main = el("div", "sw-row-main");
main.append(el("div", "sw-row-title", p.name));
main.append(el("div", "sw-row-hint", `${p.scene_count ?? 1} scene(s)`));
row.append(main);
const openBtn = el("button", "btn ghost tiny", "Open");
openBtn.type = "button";
openBtn.onclick = async () => { await S.loadProject(p.id); close(); };
row.append(openBtn);
recentWrap.append(row);
});
} catch (e) {
clear(recentWrap);
recentWrap.append(el("div", "sw-hint", "Could not load project list: " + (e.message || e)));
}
overlay.append(box);
if (dismissable) overlay.addEventListener("click", (e) => { if (e.target === overlay) close(); });
document.body.append(overlay);
}
window.ProjectMenu = { open, close };
})();