feat(library): let the scan mark follow the reading down the column

The mark was pinned to the folder the reading was asked of, so a walk through
a whole roll said C2 while the frames under it were what was being read. It
now hangs on the folder the reading stands in — `progress.at` — and on every
row above it up to and including the roll's own row: reading D:/A/B1/C2 marks
C2, B1, A and D:, and as the walk moves the chain moves with it. A reading
that has not reached a frame yet has nowhere to stand, and stands on the
folder it was asked of, so the ring is on the column from the click.
This commit is contained in:
2026-10-08 10:35:02 +07:00
parent d5e9144d89
commit efe07e20ba
+23 -20
View File
@@ -1027,35 +1027,38 @@ function Catalogue() {
[nodes, expanded]
);
// Where a mark goes on the column: the row for the folder a reading — or a
// request waiting its turn — was asked of, and every row above it short of the
// roll's own row. A right click on April is a reading of April, and the shelf
// is not the folder; a right click on 2026/04 marks 2026 with it, so a branch
// folded shut still shows the work going on under it. The rows are found by
// the key the walk would give them — `folder/sub` — rather than by taking the
// row's own name apart, which is the same path spelled by two pieces of code
// and has to agree with the reading's own spelling, not merely nearly.
// The roll's own row is worn for a reading of the whole roll, and for one whose
// own row is not on the column at all — a branch folded away, or a folder that
// has gone from the disk. A reading the column cannot point at is a reading
// running with nothing to say so, which is worse than a mark on the roll.
// Where a mark goes on the column: the row for the folder the reading is
// standing in, and every row above it up to and including the roll's own row.
// Reading D:/A/B1/C2 shows the work on C2 and on B1, on A and on D: — the
// whole path down to where the walk is. As the walk moves on, so does the
// mark: on A the chain is D: alone, in C2 it is D:/A/B1/C2, and a fold shut
// over a branch takes the rows below it out of the column without taking the
// reading off the screen, because the rows above are still there to say it.
// A reading that has not reached a frame yet stands nowhere, and stands on
// the folder it was asked of — from the click, not from the first frame, so a
// command is never a command the reader cannot tell from one that never ran.
// The rows are found by the key the walk would give them — `folder/sub` —
// rather than by taking the row's own name apart, which is the same path
// spelled by two pieces of code and has to agree with the reading's own
// spelling, not merely nearly.
interface Mark {
root: string;
own: string;
onOwn: boolean;
}
const markOf = (folderName: string, rel: string): Mark => {
const markOf = (folderName: string, rel: string, at: string): Mark => {
const root = normPath(folderName);
const own = rel ? `${root}/${normPath(rel)}` : root;
return { root, own, onOwn: rel === '' || rows.some((n) => n.key === own) };
const here = normPath(at || rel);
return { root, own: here ? `${root}/${here}` : root };
};
const liveMark = live ? markOf(live.folder, live.progress.from) : null;
const askedMarks = scanQueue().map((j) => markOf(j.folder, j.rel));
const liveMark = live ? markOf(live.folder, live.progress.from, live.progress.at) : null;
// A request waiting its turn is not being read and has no folder to stand in,
// so it marks the folder it was asked of.
const askedMarks = scanQueue().map((j) => markOf(j.folder, j.rel, ''));
const wearsMark = (n: Node, m: Mark): boolean => {
// Another roll's rows are neither the reading's nor the request's news.
if (n.key !== m.root && !n.key.startsWith(`${m.root}/`)) return false;
if (!m.onOwn) return n.key === m.root;
return m.own === m.root ? n.key === m.root : n.key !== m.root && (m.own === n.key || m.own.startsWith(`${n.key}/`));
// The asked row itself, and every row the asked row sits under.
return n.key === m.own || m.own.startsWith(`${n.key}/`);
};
// A remembered subfolder that no longer holds a frame falls back to the folder