diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-14 11:17:42 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-14 11:17:42 +0200 |
| commit | 2fb66c5baecdd8b49be904f6244f66ba04f68061 (patch) | |
| tree | 3b80940e1819a811f6ec2c04831e3616a74a8eae /packages/meshbay-hub/src/meshbay_hub/static/style.css | |
| parent | a294c1d338ba4c20d66873d593d1c101e69c5a40 (diff) | |
| download | meshbay-2fb66c5baecdd8b49be904f6244f66ba04f68061.tar.gz | |
feat(ui): an indexing dock above the music bar, on every page
Adding a large directory left the operator nothing to look at once they left
the Settings panel that started it, and nothing at all when it was added from
another machine. A band now sits above the music bar on every page: one row
per group with indexing under way, naming the root being walked, percent,
bytes and files, and the roots waiting their turn; "indexing finished" for a
few seconds at the end. A click opens the group's Settings, and × hides the
row until that group is idle.
Two sources feed it. On the node's own machine the desktop client polls the
loopback `GET /api/index-status` for every group, whatever the route. An
operator's group page forwards MNP `index_progress` pushes, resolving the
root from the roots table it opened; an ordinary member keeps the sidebar dot
only, and a page clears its row when it lets go of the group. Where both
describe a group, loopback wins.
Reconcile passes and watchdog bursts show only past 1 GB or 5 s, so a single
dropped file does not flash a bar. The logic lives in index-dock-model.js,
which has no imports and is tested under node. The dock publishes
`--index-dock-h` and the sidebar stops above it and the music bar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6jPTeocXA1BePekdsgPya
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/style.css')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/style.css | 99 |
1 files changed, 97 insertions, 2 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/style.css b/packages/meshbay-hub/src/meshbay_hub/static/style.css index 871ca0a..a2ef80e 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/style.css +++ b/packages/meshbay-hub/src/meshbay_hub/static/style.css @@ -73,6 +73,8 @@ --toolbar-h: 0px; /* Published by the music bar while it is on screen (sticky.js). */ --music-bar-h: 0px; + /* Published by the indexing dock, which sits on top of the music bar. */ + --index-dock-h: 0px; } /* ── Reset ────────────────────────────────────────────────────────────────── */ @@ -400,7 +402,7 @@ a:hover { text-decoration: underline; } display: flex; flex-direction: column; width: 240px; - height: calc(100vh - var(--nav-h) - var(--music-bar-h)); + height: calc(100vh - var(--nav-h) - var(--music-bar-h) - var(--index-dock-h)); background: var(--sidebar-bg); border-right: 1px solid var(--border); padding: 16px 0 0; @@ -2512,7 +2514,7 @@ a.transfer-name { position: fixed; left: -240px; top: 52px; - height: calc(100vh - 52px - var(--music-bar-h)); + height: calc(100vh - 52px - var(--music-bar-h) - var(--index-dock-h)); z-index: 50; transition: left 0.2s; box-shadow: none; @@ -4287,6 +4289,99 @@ h2 .gn-owner, h3 .gn-owner { font-size: 0.55em; } border-radius: 10px; } +/* ── Indexing dock (index-dock.js) ──────────────────────────────────────── + Sticky for the music bar's reason. It is rendered right before that bar, so + `bottom: var(--music-bar-h)` stacks it on top when both are pinned, and it + publishes its own height as `--index-dock-h` for the sidebar to stop above + the two of them. */ +.index-dock { + position: sticky; + bottom: var(--music-bar-h); + z-index: 50; + display: flex; + flex-direction: column; + gap: 6px; + margin-top: 16px; +} +.index-dock-row { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + background: var(--bg-raised); + border: 1px solid var(--border); + border-radius: 10px; +} +.index-dock-main { + flex: 1 1 auto; + min-width: 0; + display: block; + padding: 0; + border: 0; + background: none; + color: inherit; + font: inherit; + text-align: left; + cursor: pointer; +} +.index-dock-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 12px; + font-size: 0.85em; +} +.index-dock-title { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.index-dock-meta { + color: var(--text-dim); + white-space: nowrap; + font-variant-numeric: tabular-nums; +} +.index-dock-bar { display: block; margin: 6px 0 0; } +.index-dock-bar .index-progress-fill { display: block; } +.index-dock-done .index-progress-fill { background: var(--success); } +/* Walking the tree, or waiting for another root: no percentage to show yet, + and a bar parked at 0 % reads as stuck. */ +.index-dock-indeterminate { animation: index-dock-sweep 1.4s ease-in-out infinite; } +@keyframes index-dock-sweep { + from { transform: translateX(-100%); } + to { transform: translateX(340%); } +} +.index-dock-next { + display: block; + margin-top: 4px; + font-size: 0.78em; + color: var(--text-dim); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.index-dock-hide { + flex-shrink: 0; + display: inline-flex; + padding: 4px; + border: 0; + border-radius: 6px; + background: none; + color: var(--text-dim); + cursor: pointer; +} +.index-dock-hide:hover { background: var(--bg-surface); } +.index-dock-hide .icon { width: 16px; height: 16px; } +@media (max-width: 640px) { + .index-dock-head { flex-direction: column; gap: 2px; } + .index-dock-title, + .index-dock-meta { white-space: normal; } +} +@media (prefers-reduced-motion: reduce) { + .index-dock-indeterminate { animation: none; } +} + .music-player-info { display: flex; align-items: center; |