v4's arrangement, which is the one that reads as an editor: a zone head holds what acts on THAT zone, so the app grows a bar of its own for what acts on the app. * The menu bar. Brand, View and Settings, and whether ComfyUI is still on the other end. Only menus with something real in them exist -- an empty File menu is a promise the app does not keep. * The prompt is written in the CONSTRUCTOR, a window. v4 called this the Composer; that name is taken here by the element kit, and two things called Composer in one repo is one thing nobody can search for. It is the longest thing a person writes and the least often read, and a permanent third of the centre column is the room the timeline needs. The host is built at startup and outlives every opening, so a window that opens twice does not throw away what was typed. * The timeline replaces it, and Generate moves into its head with what the run is doing at the far end of the same head. No bar across the bottom: one that spans the window belongs to no region. Four faults found on the way, three of them mine and one much older: * THE OVERLAY ROOT WAS A STACKING CONTEXT. It documents at length that it must never be one -- and then set `position: fixed`, which makes one on its own. So the whole z ladder was measured inside that single element: an open menu at z 500 painted UNDER a button at z 1. Every overlay in the app was one positive z-index away from being buried, and the only reason nobody had seen it is that almost nothing claims a z-index. The root is static and zero-sized now; every layer in it is fixed already. * Generate's hover ran `filter: brightness()`, which lightens the LABEL along with the fill under it -- the one thing that had to stay readable lost contrast in both themes. Only the fill moves now, and which way it moves depends on the theme: dark's accent carries near-black text so it goes lighter, light's carries white so it goes darker. Measured: no gradient stop under 4.1:1, hovered or at rest. * A fixed-height head could not shrink below the width of everything in it, and a head now holds a title, three controls and a status. That min-content became the centre column's, so a 768px window laid out 878px wide and scrolled sideways. It wraps now, as v4's does. * A CSS patch of mine silently did nothing because its anchor text had moved and I had left the assertion off that one replacement. Every patch asserts now.
54 lines
1.9 KiB
JavaScript
54 lines
1.9 KiB
JavaScript
// Type. Nothing here carries a margin: spacing belongs to the container, so a
|
|
// heading can be dropped anywhere without bringing its own gap.
|
|
|
|
import { define } from "../internals/register.js";
|
|
import { el } from "../internals/el.js";
|
|
import { setText } from "../internals/text.js";
|
|
import { uid } from "../internals/ids.js";
|
|
|
|
const handle = (node) => ({
|
|
node,
|
|
setText: (value) => setText(node, value),
|
|
destroy: () => node.remove(),
|
|
});
|
|
|
|
const TAGS = { display: "h1", xl: "h1", lg: "h2", md: "h3", sm: "h4" };
|
|
|
|
for (const size of Object.keys(TAGS)) {
|
|
define("header", size, ({ text, id } = {}) =>
|
|
handle(el(TAGS[size], { cls: `cx-h cx-h-${size}`, text, attrs: { id } })));
|
|
}
|
|
|
|
for (const size of ["lg", "md", "sm", "xs"]) {
|
|
define("text", size, ({ text } = {}) =>
|
|
handle(el("p", { cls: `cx-t cx-t-${size}`, text })));
|
|
}
|
|
|
|
// One hint, one look. v4 had ten class names for this exact thing.
|
|
define("hint", "default", ({ text, id } = {}) =>
|
|
handle(el("p", { cls: "cx-hint", text, attrs: { id } })));
|
|
|
|
define("label", "field", ({ text, for: htmlFor } = {}) =>
|
|
handle(el("label", { cls: "cx-label", text, attrs: { for: htmlFor } })));
|
|
|
|
define("label", "section", ({ text } = {}) =>
|
|
handle(el("div", { cls: "cx-eyebrow", text })));
|
|
|
|
/** Who this is. One mark and one word, in the display face, at the far left of
|
|
* the menu bar -- the only place in the app that names the app. */
|
|
define("brand", "default", ({ name = "FunPack" } = {}) =>
|
|
({ node: el("span", { cls: "cx-brand", children: [
|
|
el("span", { cls: "cx-brand-mark", attrs: { "aria-hidden": "true" } }),
|
|
el("span", { cls: "cx-brand-name", text: name }),
|
|
] }),
|
|
destroy() { this.node.remove(); } }));
|
|
|
|
define("code", "inline", ({ text } = {}) =>
|
|
handle(el("code", { cls: "cx-code", text })));
|
|
|
|
define("code", "block", ({ text, label } = {}) => {
|
|
const id = uid("code");
|
|
const pre = el("pre", { cls: "cx-code-block", text, attrs: { id, "aria-label": label } });
|
|
return handle(pre);
|
|
});
|