ScuttleBot

ui: add scroll indicators to mobile nav Show fade-gradient arrows at the edges of the nav tab bar on mobile to indicate scrollable content. Indicators appear/hide based on scroll position — left arrow when scrolled right, right arrow when more tabs are off-screen.

lmata 2026-04-03 19:12 trunk
Commit c0251636b0ee88b5bc37b08232275acb2fc8d7ff4fc9d1471376333705347449
1 file changed +25 -2
--- internal/api/ui/index.html
+++ internal/api/ui/index.html
@@ -199,15 +199,21 @@
199199
@media (max-width: 600px) {
200200
/* header: shorter, compact brand, scrollable nav */
201201
header { padding:0 8px; height:44px; }
202202
.brand { padding-right:8px; margin-right:0; border-right:none; }
203203
.brand span { display:none; }
204
- nav { overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none; }
204
+ nav { overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none; position:relative; }
205205
nav::-webkit-scrollbar { display:none; }
206206
.nav-tab { padding:0 10px; font-size:12px; }
207207
.header-right { display:none; }
208208
209
+ /* scroll indicators */
210
+ .nav-scroll-left, .nav-scroll-right { display:none; position:absolute; top:0; bottom:0; width:28px; pointer-events:none; z-index:2; align-items:center; justify-content:center; font-size:11px; color:#58a6ff; }
211
+ .nav-scroll-left { left:0; background:linear-gradient(90deg,#161b22 40%,transparent); }
212
+ .nav-scroll-right { right:0; background:linear-gradient(270deg,#161b22 40%,transparent); }
213
+ .nav-scroll-left.visible, .nav-scroll-right.visible { display:flex; }
214
+
209215
/* content: reduce padding, stack grids */
210216
.pane-inner { padding:12px; gap:12px; }
211217
.stat-grid { grid-template-columns:1fr !important; }
212218
.card-body { padding:12px !important; }
213219
@@ -296,18 +302,20 @@
296302
<header>
297303
<div class="brand">
298304
<h1>⬡ scuttlebot</h1>
299305
<span>agent coordination backplane</span>
300306
</div>
301
- <nav>
307
+ <nav id="main-nav">
308
+ <span class="nav-scroll-left" id="nav-scroll-left">‹</span>
302309
<div class="nav-tab active" id="tab-status" onclick="switchTab('status')">◈ status</div>
303310
<div class="nav-tab" id="tab-users" onclick="switchTab('users')">◉ users</div>
304311
<div class="nav-tab" id="tab-agents" onclick="switchTab('agents')">◎ agents</div>
305312
<div class="nav-tab" id="tab-channels" onclick="switchTab('channels')">◎ channels</div>
306313
<div class="nav-tab" id="tab-chat" onclick="switchTab('chat')">◌ chat</div>
307314
<div class="nav-tab" id="tab-ai" onclick="switchTab('ai')">✦ ai</div>
308315
<div class="nav-tab" id="tab-settings" onclick="switchTab('settings')">⚙ settings</div>
316
+ <span class="nav-scroll-right visible" id="nav-scroll-right">›</span>
309317
</nav>
310318
<div class="header-right">
311319
<span id="header-user-display" style="font-size:12px;color:#8b949e"></span>
312320
<button class="sm" onclick="logout()">sign out</button>
313321
</div>
@@ -2946,12 +2954,27 @@
29462954
email: document.getElementById('tls-email').value.trim() || undefined,
29472955
allow_insecure: document.getElementById('tls-allow-insecure').checked,
29482956
}
29492957
}, 'tls-config-save-result');
29502958
}
2959
+
2960
+// --- nav scroll indicators ---
2961
+(function() {
2962
+ const nav = document.getElementById('main-nav');
2963
+ const left = document.getElementById('nav-scroll-left');
2964
+ const right = document.getElementById('nav-scroll-right');
2965
+ if (!nav || !left || !right) return;
2966
+ function update() {
2967
+ left.classList.toggle('visible', nav.scrollLeft > 4);
2968
+ right.classList.toggle('visible', nav.scrollLeft + nav.clientWidth < nav.scrollWidth - 4);
2969
+ }
2970
+ nav.addEventListener('scroll', update, { passive: true });
2971
+ window.addEventListener('resize', update);
2972
+ update();
2973
+})();
29512974
29522975
// --- init ---
29532976
function loadAll() { loadStatus(); loadAgents(); loadSettings(); startMetricsPoll(); }
29542977
initAuth();
29552978
</script>
29562979
</body>
29572980
</html>
29582981
--- internal/api/ui/index.html
+++ internal/api/ui/index.html
@@ -199,15 +199,21 @@
199 @media (max-width: 600px) {
200 /* header: shorter, compact brand, scrollable nav */
201 header { padding:0 8px; height:44px; }
202 .brand { padding-right:8px; margin-right:0; border-right:none; }
203 .brand span { display:none; }
204 nav { overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none; }
205 nav::-webkit-scrollbar { display:none; }
206 .nav-tab { padding:0 10px; font-size:12px; }
207 .header-right { display:none; }
208
 
 
 
 
 
 
209 /* content: reduce padding, stack grids */
210 .pane-inner { padding:12px; gap:12px; }
211 .stat-grid { grid-template-columns:1fr !important; }
212 .card-body { padding:12px !important; }
213
@@ -296,18 +302,20 @@
296 <header>
297 <div class="brand">
298 <h1>⬡ scuttlebot</h1>
299 <span>agent coordination backplane</span>
300 </div>
301 <nav>
 
302 <div class="nav-tab active" id="tab-status" onclick="switchTab('status')">◈ status</div>
303 <div class="nav-tab" id="tab-users" onclick="switchTab('users')">◉ users</div>
304 <div class="nav-tab" id="tab-agents" onclick="switchTab('agents')">◎ agents</div>
305 <div class="nav-tab" id="tab-channels" onclick="switchTab('channels')">◎ channels</div>
306 <div class="nav-tab" id="tab-chat" onclick="switchTab('chat')">◌ chat</div>
307 <div class="nav-tab" id="tab-ai" onclick="switchTab('ai')">✦ ai</div>
308 <div class="nav-tab" id="tab-settings" onclick="switchTab('settings')">⚙ settings</div>
 
309 </nav>
310 <div class="header-right">
311 <span id="header-user-display" style="font-size:12px;color:#8b949e"></span>
312 <button class="sm" onclick="logout()">sign out</button>
313 </div>
@@ -2946,12 +2954,27 @@
2946 email: document.getElementById('tls-email').value.trim() || undefined,
2947 allow_insecure: document.getElementById('tls-allow-insecure').checked,
2948 }
2949 }, 'tls-config-save-result');
2950 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2951
2952 // --- init ---
2953 function loadAll() { loadStatus(); loadAgents(); loadSettings(); startMetricsPoll(); }
2954 initAuth();
2955 </script>
2956 </body>
2957 </html>
2958
--- internal/api/ui/index.html
+++ internal/api/ui/index.html
@@ -199,15 +199,21 @@
199 @media (max-width: 600px) {
200 /* header: shorter, compact brand, scrollable nav */
201 header { padding:0 8px; height:44px; }
202 .brand { padding-right:8px; margin-right:0; border-right:none; }
203 .brand span { display:none; }
204 nav { overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none; position:relative; }
205 nav::-webkit-scrollbar { display:none; }
206 .nav-tab { padding:0 10px; font-size:12px; }
207 .header-right { display:none; }
208
209 /* scroll indicators */
210 .nav-scroll-left, .nav-scroll-right { display:none; position:absolute; top:0; bottom:0; width:28px; pointer-events:none; z-index:2; align-items:center; justify-content:center; font-size:11px; color:#58a6ff; }
211 .nav-scroll-left { left:0; background:linear-gradient(90deg,#161b22 40%,transparent); }
212 .nav-scroll-right { right:0; background:linear-gradient(270deg,#161b22 40%,transparent); }
213 .nav-scroll-left.visible, .nav-scroll-right.visible { display:flex; }
214
215 /* content: reduce padding, stack grids */
216 .pane-inner { padding:12px; gap:12px; }
217 .stat-grid { grid-template-columns:1fr !important; }
218 .card-body { padding:12px !important; }
219
@@ -296,18 +302,20 @@
302 <header>
303 <div class="brand">
304 <h1>⬡ scuttlebot</h1>
305 <span>agent coordination backplane</span>
306 </div>
307 <nav id="main-nav">
308 <span class="nav-scroll-left" id="nav-scroll-left">‹</span>
309 <div class="nav-tab active" id="tab-status" onclick="switchTab('status')">◈ status</div>
310 <div class="nav-tab" id="tab-users" onclick="switchTab('users')">◉ users</div>
311 <div class="nav-tab" id="tab-agents" onclick="switchTab('agents')">◎ agents</div>
312 <div class="nav-tab" id="tab-channels" onclick="switchTab('channels')">◎ channels</div>
313 <div class="nav-tab" id="tab-chat" onclick="switchTab('chat')">◌ chat</div>
314 <div class="nav-tab" id="tab-ai" onclick="switchTab('ai')">✦ ai</div>
315 <div class="nav-tab" id="tab-settings" onclick="switchTab('settings')">⚙ settings</div>
316 <span class="nav-scroll-right visible" id="nav-scroll-right">›</span>
317 </nav>
318 <div class="header-right">
319 <span id="header-user-display" style="font-size:12px;color:#8b949e"></span>
320 <button class="sm" onclick="logout()">sign out</button>
321 </div>
@@ -2946,12 +2954,27 @@
2954 email: document.getElementById('tls-email').value.trim() || undefined,
2955 allow_insecure: document.getElementById('tls-allow-insecure').checked,
2956 }
2957 }, 'tls-config-save-result');
2958 }
2959
2960 // --- nav scroll indicators ---
2961 (function() {
2962 const nav = document.getElementById('main-nav');
2963 const left = document.getElementById('nav-scroll-left');
2964 const right = document.getElementById('nav-scroll-right');
2965 if (!nav || !left || !right) return;
2966 function update() {
2967 left.classList.toggle('visible', nav.scrollLeft > 4);
2968 right.classList.toggle('visible', nav.scrollLeft + nav.clientWidth < nav.scrollWidth - 4);
2969 }
2970 nav.addEventListener('scroll', update, { passive: true });
2971 window.addEventListener('resize', update);
2972 update();
2973 })();
2974
2975 // --- init ---
2976 function loadAll() { loadStatus(); loadAgents(); loadSettings(); startMetricsPoll(); }
2977 initAuth();
2978 </script>
2979 </body>
2980 </html>
2981

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button