diff --git a/services/web-ui/public/capture.html b/services/web-ui/public/capture.html index b61892c..ab41fd2 100644 --- a/services/web-ui/public/capture.html +++ b/services/web-ui/public/capture.html @@ -44,17 +44,19 @@ } .timecode-display { - font-size: 38px; - font-weight: 400; + font-family: var(--font-mono); + font-size: 64px; + font-weight: 500; font-variant-numeric: tabular-nums; - letter-spacing: 0.06em; + letter-spacing: 0.05em; color: var(--accent); - font-family: 'SF Mono', 'Consolas', 'Menlo', monospace; + text-shadow: 0 0 18px oklch(55% 0.20 266 / 0.30); line-height: 1; } .timecode-display.inactive { color: var(--text-tertiary); + text-shadow: none; } .timecode-status { @@ -313,6 +315,7 @@
+ + + diff --git a/services/web-ui/public/js/topbar-strip.js b/services/web-ui/public/js/topbar-strip.js new file mode 100644 index 0000000..50dc9cf --- /dev/null +++ b/services/web-ui/public/js/topbar-strip.js @@ -0,0 +1,56 @@ +// Operator status strip mounted at the top of every .main pane. +(function () { + function mount() { + const main = document.querySelector('.main'); + if (!main || main.querySelector('.topbar-strip')) return; + const strip = document.createElement('div'); + strip.className = 'topbar-strip'; + strip.innerHTML = + '' + + 'Z-AMPP' + + '00:00:00' + + '' + + 'Page' + + '' + pageName() + '' + + '' + + 'API' + + '--'; + main.insertBefore(strip, main.firstChild); + tick(); setInterval(tick, 1000); + ping(); setInterval(ping, 10000); + } + function pageName() { + const p = location.pathname.replace(/\.html$/, '').replace(/^\//, ''); + if (!p || p === 'index') return 'Library'; + return p.charAt(0).toUpperCase() + p.slice(1); + } + function tick() { + const n = new Date(); + const hh = String(n.getHours()).padStart(2, '0'); + const mm = String(n.getMinutes()).padStart(2, '0'); + const ss = String(n.getSeconds()).padStart(2, '0'); + const el = document.getElementById('tsNow'); + if (el) el.textContent = hh + ':' + mm + ':' + ss; + } + async function ping() { + const dot = document.getElementById('tsDot'); + const apiEl = document.getElementById('tsApi'); + const t0 = performance.now(); + try { + const r = await fetch('/api/v1/projects', { credentials: 'include', signal: AbortSignal.timeout(4000) }); + const ms = Math.round(performance.now() - t0); + if (r.ok) { + if (dot) { dot.style.background = 'var(--signal-good)'; dot.style.boxShadow = '0 0 8px var(--signal-good)'; } + if (apiEl) apiEl.textContent = ms + ' ms'; + } else { + if (dot) { dot.style.background = 'var(--signal-warn)'; dot.style.boxShadow = '0 0 8px var(--signal-warn)'; } + if (apiEl) apiEl.textContent = 'HTTP ' + r.status; + } + } catch (e) { + if (dot) { dot.style.background = 'var(--signal-bad)'; dot.style.boxShadow = '0 0 8px var(--signal-bad)'; } + if (apiEl) apiEl.textContent = 'offline'; + } + } + if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount); + else mount(); +})(); diff --git a/services/web-ui/public/player.html b/services/web-ui/public/player.html index 04484c5..6cba698 100644 --- a/services/web-ui/public/player.html +++ b/services/web-ui/public/player.html @@ -305,6 +305,7 @@ + + +