- Marker: "make a repaint mask" becomes How to change it (leave it to the AI, only the marked areas, the whole picture anew); the AI reads the choice first as the user's, the timeline row says it, the repaint brush picks "only the marked areas". - Task list: folded, it stays laid out out of sight and slides in at once from its button or the page's left edge; redraws make anew only the rows that changed (sync_rows.js). A picked task shows at once from the copy read before or read ahead on hover (ai_task_cache.js), then what changed; activity entries follow instead of holding it up. Stage pictures load as thumbnails first, the file itself only when shown larger. - Header: "Own tab" is "AI edits a copy ▾", a two-way menu with what each means (kept open across redraws), and "Show the copy". - Materials: the Source list lights the hovered row and ticks the one shown (a later rule had hidden both), tooltips only for cut names, arrows and Enter (ui_ai_facet_menu.js). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
25 lines
957 B
JavaScript
25 lines
957 B
JavaScript
/**
|
|
* Drawing a list again without drawing it all (the AI workbench's timeline and task list): each row
|
|
* has a key that changes when what it shows changes, and only rows with a new key are made.
|
|
*/
|
|
|
|
/**
|
|
* Puts `rows` ({key, make()}) into `parent` in this order: a child already there with the same
|
|
* key is kept as it is (moved only when the rows before it changed), the others are made, and the
|
|
* children no row asks for go.
|
|
*/
|
|
export function syncRows(parent, rows) {
|
|
const kept = new Map([...parent.children].map(child => [child.dataset.rowKey, child]));
|
|
rows.forEach((row, at) => {
|
|
let node = kept.get(row.key);
|
|
if (node) {
|
|
kept.delete(row.key);
|
|
} else {
|
|
node = row.make();
|
|
node.dataset.rowKey = row.key;
|
|
}
|
|
if (parent.children[at] !== node) parent.insertBefore(node, parent.children[at] || null);
|
|
});
|
|
for (const node of kept.values()) node.remove();
|
|
}
|