From efe07e20bad7a048c0eadab132dd620d86ba9a51 Mon Sep 17 00:00:00 2001 From: 3dtours Date: Thu, 8 Oct 2026 10:35:02 +0700 Subject: [PATCH] feat(library): let the scan mark follow the reading down the column MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- docker/frontend/src/Library.tsx | 43 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/docker/frontend/src/Library.tsx b/docker/frontend/src/Library.tsx index b5eb062..05f01dd 100644 --- a/docker/frontend/src/Library.tsx +++ b/docker/frontend/src/Library.tsx @@ -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