ux(classifier): blue completed counts; blue labels when row fully scanned

The black-completed vs grey-flashing distinction was too subtle. Completed
numbers (the direct count, always; the +total once final) now render in
var(--primary) — theme-aware blue in both light and dark. While a subtree
is still scanning its +total stays muted grey + pulses, so blue = done,
grey = in progress. Once both numbers are blue the row's folders/files
labels turn blue too (.folder-count.done .ct-label).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZDDC 2026-06-09 11:11:51 -05:00
parent e0ba77a75b
commit 389b2e94ac
2 changed files with 31 additions and 9 deletions

View file

@ -175,17 +175,24 @@
background-color: var(--bg-hover);
}
/* Counts read "direct+total". The direct number stays solid (immediate info);
the "+total" subtree count is muted and pulses while its subtree is still
being scanned, then goes solid once final. */
/* Counts read "direct+total". Completed numbers are blue var(--primary),
which is theme-aware (medium blue in light, lighter blue in dark). The
direct number is always completed (known the moment the folder is read).
The "+total" subtree count stays muted grey + pulses while still scanning,
then turns blue once final. Once the row is fully scanned (both numbers
blue) the folders/files labels turn blue too (.folder-count.done). */
.folder-count .ct-direct,
.folder-count .ct-total {
color: var(--text-secondary, #6b7280);
color: var(--primary);
}
.folder-count .ct-total.pending {
color: var(--text-muted, #9aa0a6);
font-style: italic;
animation: scan-pulse 1.2s ease-in-out infinite;
}
.folder-count.done .ct-label {
color: var(--primary);
}
@keyframes scan-pulse {
0%, 100% { opacity: 0.55; }
50% { opacity: 1; }

View file

@ -35,12 +35,15 @@
*/
function populateCount(el, folder) {
el.textContent = '';
el.classList.remove('done');
const st = folder.scanState;
if (st === 'pending') return;
if (st === 'zip-pending') { el.textContent = '(zip — open to scan)'; return; }
if (st === 'scanning') { el.textContent = 'scanning…'; return; }
const done = st === 'done';
// When fully scanned both numbers are blue; .done turns the labels blue too.
if (done) el.classList.add('done');
const dDir = folder.subdirCount || 0, tDir = folder.runDirs || 0;
const dFile = folder.fileCount || 0, tFile = folder.runFiles || 0;
@ -48,17 +51,29 @@
frag.appendChild(document.createTextNode('('));
if (dDir > 0 || tDir > 0) {
appendPair(frag, dDir, tDir, done);
frag.appendChild(document.createTextNode(tDir === 1 ? ' folder, ' : ' folders, '));
appendLabel(frag, tDir === 1 ? ' folder, ' : ' folders, ');
}
appendPair(frag, dFile, tFile, done);
frag.appendChild(document.createTextNode(tFile === 1 ? ' file)' : ' files)'));
appendLabel(frag, tFile === 1 ? ' file)' : ' files)');
el.appendChild(frag);
}
// Append "<direct>" and, when there's a subtree (or scanning is ongoing),
// "+<total>" with the total in a span that greys + pulses until final.
// The "folders"/"files" word labels — blue only once the row is .done.
function appendLabel(frag, text) {
const s = document.createElement('span');
s.className = 'ct-label';
s.textContent = text;
frag.appendChild(s);
}
// Append "<direct>" (always a completed/blue number) and, when there's a
// subtree (or scanning is ongoing), "+<total>" with the total in a span
// that greys + pulses until final, then turns blue.
function appendPair(frag, direct, total, done) {
frag.appendChild(document.createTextNode(String(direct)));
const d = document.createElement('span');
d.className = 'ct-direct';
d.textContent = String(direct);
frag.appendChild(d);
if (!done || total > direct) {
frag.appendChild(document.createTextNode('+'));
const t = document.createElement('span');