Files
olivv-cs-ComfyUI-FunPack/app/legacy/layout.js
T
digital-garbageandClaude Sonnet 5 29ac44ffcd feat: v4 UI port Phase A start -- module categories, legacy frontend served live
Two pieces of the "port v4's exact UI onto v5's backend" plan:

- core/contract.py: new optional ModuleSpec.category field (closed set:
  continuity, guidance, conditioning, sampling, post, system), validated in
  core/schema.py, threaded through core/registry.py's FIELDS and
  to_manifest(). Presentation grouping, independent of STAGE (execution
  order) -- a module can be stage="sampling" and category="guidance" at
  once. Only the 4 existing modules that actually render a settings panel
  (alg, sharpen, appearance, full_control) got a category assigned; the
  other 12 have none to categorize (no SETTINGS block) and stay
  uncategorised, which is valid.

- v4's frontend (movie_editor/frontend/*, ~29k lines, 61 files) copied
  verbatim into app/legacy/. core/routes.py's "/" route now serves
  legacy/index.html instead of the composer entry point; a <base> tag in
  that file resolves its own relative script/link tags against
  /funpack/app/legacy/ regardless of what URL it's served at, so every
  file moved as a unit with zero per-file path edits. Verified live: all
  61 assets load 200 OK, the real v4 onboarding screen renders pixel-for-
  pixel (it's the actual DOM/CSS, not a reimplementation), and several v4
  API calls (/api/media, /api/projects, /api/git/status) already succeed
  against v5's real backend by coincidence of shared route naming -- the
  rest 404/405 as expected, since api.js's ~90 functions haven't been
  rewired to v5's actual routes yet (next piece of this plan).

The old composer entry point (app/index.html, app/composer/**) stays in
the tree, unreferenced, until a later cleanup pass once nothing imports it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 23:58:51 +03:00

84 lines
2.6 KiB
JavaScript

// Column visibility: Assets / Preview / Properties toggles (chips in the timeline header).
// Canonical layout is all three side-by-side; collapsing a column gives its space to the rest.
(function () {
const KEY = "funpack_dock_panels";
const PANELS = [
{ id: "media", label: "Assets" },
{ id: "preview", label: "Preview" },
{ id: "settings", label: "Properties" },
];
const mainRow = document.getElementById("main-row");
const tabsEl = document.getElementById("dock-tabs");
if (!mainRow || !tabsEl) return;
function load() {
try {
const raw = localStorage.getItem(KEY);
if (raw) {
const p = JSON.parse(raw);
return {
media: p.media !== false,
preview: p.preview !== false,
settings: p.settings !== false,
};
}
} catch (_) {}
return { media: true, preview: true, settings: true };
}
let state = load();
function save() {
localStorage.setItem(KEY, JSON.stringify(state));
}
const panelEls = {
media: document.getElementById("media-zone"),
preview: document.getElementById("preview-zone"),
settings: document.getElementById("inspector-zone"),
};
function setVis(el, show) {
if (!el) return;
if (show) el.removeAttribute("hidden"); else el.setAttribute("hidden", "");
}
function apply() {
// CSS reads these data attrs to size columns and hide the dividing splitters.
mainRow.dataset.media = state.media ? "1" : "0";
mainRow.dataset.preview = state.preview ? "1" : "0";
mainRow.dataset.settings = state.settings ? "1" : "0";
setVis(panelEls.media, state.media);
setVis(panelEls.preview, state.preview);
setVis(panelEls.settings, state.settings);
tabsEl.querySelectorAll(".dock-tab").forEach((btn) => {
const id = btn.dataset.panel;
const on = !!state[id];
btn.classList.toggle("on", on);
btn.setAttribute("aria-pressed", on ? "true" : "false");
});
}
function toggle(id) {
const on = Object.values(state).filter(Boolean).length;
if (state[id] && on <= 1) return; // keep at least one panel visible
state[id] = !state[id];
save();
apply();
}
PANELS.forEach(({ id, label }) => {
const btn = document.createElement("button");
btn.type = "button";
btn.className = "dock-tab";
btn.dataset.panel = id;
btn.textContent = label;
btn.title = `Show or hide ${label}`;
btn.onclick = () => toggle(id);
tabsEl.append(btn);
});
apply();
window.DockLayout = { get: () => ({ ...state }), set: (patch) => { state = { ...state, ...patch }; save(); apply(); } };
})();