From 55c37a009709ae25517612406a57e5c057db2e30 Mon Sep 17 00:00:00 2001 From: iRedTea Date: Wed, 14 Oct 2026 20:03:03 +0300 Subject: [PATCH] fix: the spinner by the path takes room only while busy, opening and closing smoothly --- internal/server/web/templates/files.html | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/internal/server/web/templates/files.html b/internal/server/web/templates/files.html index 6b1fe18..fd2c5b0 100644 --- a/internal/server/web/templates/files.html +++ b/internal/server/web/templates/files.html @@ -23,16 +23,18 @@ .fm-bar .fm-pathbox .btn.sq { position:absolute; right:4px; top:4px; width:26px; height:26px; border:1px solid transparent; } .fm-bar .fm-pathbox .btn.sq:hover { border-color:var(--border); background:#151a21; } .spinner { width:16px; height:16px; border:2px solid var(--border); border-top-color:var(--accent); - border-radius:50%; animation:spin .7s linear infinite; display:inline-block; flex:none; visibility:hidden; } + border-radius:50%; animation:spin .7s linear infinite; display:inline-block; flex:none; } @keyframes spin { to { transform:rotate(360deg); } } /* Busy indicator; while files upload it also shows how far they got, and a - click on it lists them. It holds its place, hidden or not, so the path - field beside it never jumps. */ - #uppct:not(:empty) { min-width:9.5ch; } + click on it lists them. It takes room only while it shows. */ #uppct:empty { display:none; } - .fm-bar .busy { margin:0 -3px; } - .busy { flex:none; min-width:16px; justify-content:center; display:inline-flex; align-items:center; gap:6px; background:none; border:0; padding:0; + .busy { flex:none; display:none; align-items:center; gap:8px; background:none; border:0; padding:0 2px; height:34px; color:var(--muted); font-size:13px; font-variant-numeric:tabular-nums; cursor:default; } + /* Folded to nothing when idle (the negative margin takes back the bar's + gap), it opens smoothly, and only for work that lasts a moment. */ + .fm-bar .busy { display:inline-flex; box-sizing:border-box; max-width:0; padding:0; margin-left:-8px; opacity:0; + overflow:hidden; white-space:nowrap; transition:max-width .3s ease, margin-left .3s ease, opacity .25s ease; } + .fm-bar .busy.on { max-width:120px; margin-left:0; opacity:1; transition-delay:.15s; } .busy:hover { background:none; } .busy.up { cursor:pointer; color:var(--text); } .busy.up:hover { color:var(--accent); } @@ -343,8 +345,7 @@ (function () { const agentID = {{.Agent.ID}}; let busyN = 0; - // The spinner keeps its place when hidden, so the path field never jumps. - function setBusy(on) { busyN += on ? 1 : -1; if (busyN < 0) busyN = 0; document.getElementById('spin').style.visibility = busyN > 0 ? 'visible' : 'hidden'; } + function setBusy(on) { busyN += on ? 1 : -1; if (busyN < 0) busyN = 0; document.getElementById('busy').classList.toggle('on', busyN > 0); } const api = (op, body) => { setBusy(true); return fetch('/api/panel/agents/' + encodeURIComponent(agentID) + '/fs/' + op, {