feat(ui): Sampler quick-access popover over the timeline (same settings as Engine ▸ Sampling)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
2df329d458
commit
229f361702
@@ -1,5 +0,0 @@
|
||||
// Stand-ins that sit BEFORE a real feature in the same row (see index.js).
|
||||
import { composer as c } from "../../composer/composer.js";
|
||||
|
||||
export default [{ id: "placeholder:sampler", mount: "timeline.status",
|
||||
setup: ({ host }) => host.append(c.button.sm({ label: "⏱ Sampler", tone: "neutral", disabled: true }).node) }];
|
||||
@@ -0,0 +1,39 @@
|
||||
// "⏱ Sampler": steps, scheduler and sampler one click away, in a thin window over the timeline. Same settings as Engine ▸ Sampling,
|
||||
// same values tree, so the two cannot disagree. Absent when no installed module has a sampling setting.
|
||||
import { composer as c } from "../../composer/composer.js";
|
||||
import { settingRow, whenSatisfied } from "../settings/field.js";
|
||||
|
||||
export default {
|
||||
id: "sampler",
|
||||
mount: "timeline.status",
|
||||
needs: ["pipeline"],
|
||||
setup({ host, app }) {
|
||||
const ps = app.pipeline;
|
||||
let pop = null;
|
||||
const sampling = () => ps.activeModules().filter((m) => (m.category || "") === "sampling" && Object.keys(m.settings || {}).length);
|
||||
const button = c.button.sm({ label: "⏱ Sampler", tone: "neutral", title: "Steps, scheduler and sampler: one click, no modal.", onClick: () => (pop ? pop.close() : open()) });
|
||||
button.node.hidden = true;
|
||||
host.append(button.node);
|
||||
|
||||
const body = c.region.stack({ gap: "md" });
|
||||
const draw = () => {
|
||||
if (ps.loading()) return body.set([c.hint.default({ text: "Loading…" })]);
|
||||
if (ps.loadError()) return body.set([c.banner.warn({ text: `Could not load: ${ps.loadError()}` })]);
|
||||
const mods = sampling(), values = ps.currentValues();
|
||||
const change = async (id, name, value) => { await ps.setModuleValue(id, name, value); draw(); };
|
||||
body.set(mods.flatMap((m) => [mods.length > 1 ? c.label.section({ text: m.title || m.id }) : null,
|
||||
...Object.entries(m.settings).filter(([, spec]) => whenSatisfied(values, m.id, spec.when)).map(([name, spec]) => settingRow(m.id, name, spec, values, change))]).filter(Boolean));
|
||||
};
|
||||
const typing = () => body.node.contains(document.activeElement) && /^(input|textarea)$/i.test(document.activeElement.tagName);
|
||||
const off = ps.subscribe(() => { if (pop && !typing()) draw(); });
|
||||
const show = () => { button.node.hidden = !sampling().length; if (button.node.hidden && pop) pop.close(); };
|
||||
ps.ensureLoaded().then(show);
|
||||
const offShow = ps.subscribe(show);
|
||||
|
||||
function open() {
|
||||
draw();
|
||||
pop = c.popover.anchored({ anchor: button, body, side: "top", align: "end", onClose: () => { pop = null; } });
|
||||
}
|
||||
return () => { off(); offShow(); if (pop) pop.close(); button.node.remove(); };
|
||||
},
|
||||
};
|
||||
+1
-1
@@ -4,7 +4,7 @@ export default [
|
||||
"./features/log/index.js",
|
||||
"./features/projects/index.js",
|
||||
"./features/media/index.js",
|
||||
"./features/placeholders/early.js",
|
||||
"./features/sampler/index.js",
|
||||
"./features/dock/index.js",
|
||||
"./features/keys/index.js",
|
||||
"./features/timeline/index.js",
|
||||
|
||||
Reference in New Issue
Block a user