feat: media bin marks references as solid R1/R2 tags (◐ for the resolution source) in every view; Clear references (N) button
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
dcc6cba02f
commit
1ee963d5d3
@@ -31,6 +31,8 @@
|
||||
}
|
||||
.cx-cell-badge { left: var(--sp-1); }
|
||||
.cx-cell-duration { right: var(--sp-1); font-variant-numeric: tabular-nums; }
|
||||
.cx-cell-flags { position: absolute; top: 2px; right: 2px; display: flex; gap: 2px; pointer-events: none; }
|
||||
.cx-cell-flag { font-size: 10px; font-weight: 700; line-height: 1; padding: 2px 4px; border-radius: var(--r-1); background: var(--accent); color: var(--void); }
|
||||
.cx-cell-name {
|
||||
font-size: clamp(10px, calc(var(--cell, 96px) * .115), 13px);
|
||||
line-height: var(--lh-snug); padding: 0 var(--sp-3) var(--sp-3);
|
||||
|
||||
@@ -34,6 +34,8 @@ function thumbOf(item, cls = "cx-cell-thumb", marks = true) {
|
||||
}
|
||||
if (marks && item.badge) thumb.append(el("span", { cls: "cx-cell-badge", text: item.badge }));
|
||||
if (marks && item.duration) thumb.append(el("span", { cls: "cx-cell-duration", text: item.duration }));
|
||||
// `flags` [{text, title}]: what this item IS to the work (a reference, say): small and solid, in every view, readable at a glance.
|
||||
if ((item.flags || []).length) thumb.append(el("span", { cls: "cx-cell-flags", children: item.flags.map((f) => el("span", { cls: "cx-cell-flag", text: f.text, attrs: { title: f.title || f.text } })) }));
|
||||
return thumb;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,13 +36,15 @@ test("the selected scene's references are marked on their tiles, and the menu ta
|
||||
hub.setup({ host, app: { project, api, mediaPeek: {}, say: () => {}, on: () => () => {} } });
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
const named = (n) => [...host.querySelectorAll(".cx-cell")].find((x) => x.textContent.includes(n));
|
||||
assert.match(named("dog.png").textContent, /ref 1/);
|
||||
assert.match(named("cat.png").textContent, /ref 2/);
|
||||
assert.doesNotMatch(named("owl.png").textContent, /ref/);
|
||||
const flag = (n) => [...named(n).querySelectorAll(".cx-cell-flag")].map((x) => x.textContent).join();
|
||||
assert.deepEqual([flag("dog.png"), flag("cat.png"), flag("owl.png")], ["R1", "R2", ""]);
|
||||
const clear = [...host.querySelectorAll("button")].find((b) => b.textContent.startsWith("Clear references"));
|
||||
assert.ok(clear && !clear.hidden && /\(2\)/.test(clear.textContent), "one click takes them all off");
|
||||
document.querySelectorAll(".cx-popover").forEach((n) => n.remove());
|
||||
named("dog.png").dispatchEvent(new window.MouseEvent("contextmenu", { bubbles: true, cancelable: true }));
|
||||
const stop = [...document.querySelectorAll(".cx-menu-item")].find((b) => b.textContent.includes("Stop using as a reference"));
|
||||
assert.ok(stop && !stop.disabled, "not greyed: it can be taken off");
|
||||
stop.click();
|
||||
assert.deepEqual(set, [["s1", "references", ["m1"]]]);
|
||||
clear.click();
|
||||
assert.deepEqual(set, [["s1", "references", ["m1"]], ["s1", "references", []]]);
|
||||
});
|
||||
|
||||
@@ -90,7 +90,8 @@ export default {
|
||||
await gone(ids);
|
||||
} });
|
||||
bulk.node.hidden = true;
|
||||
host.append(c.toolbar.default({ items: [c.text.sm({ text: "Media" })], trailing: [selectBtn, bulk] }).node, drop.node, note.node, seg("Show", FILTERS, "filter").node, sort.node,
|
||||
const clearRefs = c.button.sm({ label: "Clear references", tone: "ghost", title: "Stop using every reference picture in the selected scene", onClick: () => p.selected && p.setScene(p.selected.id, "references", []) });
|
||||
host.append(c.toolbar.default({ items: [c.text.sm({ text: "Media" })], trailing: [clearRefs, selectBtn, bulk] }).node, drop.node, note.node, seg("Show", FILTERS, "filter").node, sort.node,
|
||||
seg("View", VIEWS, "view").node, seg("Tile size", DENSITY, "cols").node, shelf.node);
|
||||
|
||||
let drawn = "";
|
||||
@@ -108,13 +109,16 @@ export default {
|
||||
shelf.set([g]);
|
||||
if (g.setCols) g.setCols(Number(show.cols));
|
||||
// what the selected scene uses is marked on its tile, so a reference can be told from the rest
|
||||
const role = (m) => [sc && sc.source_image === m.id ? "source" : null, refs.includes(m.id) ? `ref ${refs.indexOf(m.id) + 1}` : null].filter(Boolean);
|
||||
g.setItems(shown.map((m) => ({ id: m.id, label: m.name, thumb: m.kind === "audio" ? undefined : `${base(m.id)}/thumb`, badge: [...role(m), m.kind].join(" · ") })));
|
||||
const flags = (m) => [sc && sc.source_image === m.id ? { text: "◐", title: "The selected scene's resolution source" } : null,
|
||||
refs.includes(m.id) ? { text: `R${refs.indexOf(m.id) + 1}`, title: `Reference ${refs.indexOf(m.id) + 1} of ${refs.length} for the selected scene` } : null].filter(Boolean);
|
||||
g.setItems(shown.map((m) => ({ id: m.id, label: m.name, thumb: m.kind === "audio" ? undefined : `${base(m.id)}/thumb`, badge: m.kind, flags: flags(m) })));
|
||||
g.setValue(selecting ? [...chosen] : sc ? [sc.source_image, ...refs].filter(Boolean) : []);
|
||||
selectBtn.setLabel(selecting ? "Done" : "Select");
|
||||
bulk.node.hidden = !selecting;
|
||||
bulk.setLabel(`Delete (${chosen.size})`);
|
||||
bulk.setDisabled(!chosen.size);
|
||||
clearRefs.node.hidden = !refs.length;
|
||||
clearRefs.setLabel(`Clear references (${refs.length})`);
|
||||
}
|
||||
async function refresh() {
|
||||
try { items = (await api.media()).media || []; learn(items); app.say("bin"); } catch (err) { tell(err.message); }
|
||||
|
||||
Reference in New Issue
Block a user