aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/style.css
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-14 11:17:42 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-14 11:17:42 +0200
commit2fb66c5baecdd8b49be904f6244f66ba04f68061 (patch)
tree3b80940e1819a811f6ec2c04831e3616a74a8eae /packages/meshbay-hub/src/meshbay_hub/static/style.css
parenta294c1d338ba4c20d66873d593d1c101e69c5a40 (diff)
downloadmeshbay-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.css99
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;