feat(design): broadcast ops console redesign sweep
Confirmed shape brief: ops-console direction, balanced density, blue committed accent, readability emphasized. Design system: surface scale to 5 steps tinted toward hue 266; text contrast lifted (secondary 62->72%, tertiary 44->52, added text-disabled); borders gained faint variant; status tokens renamed semantically (signal-good/warn/bad/idle); typography upgraded (Inter 400/500/600, JetBrains Mono for numerics, new 2xl/3xl/tc scale steps). New components: tc-display timecode classes with blue glow; tally-word with good/warn/bad/rec variants; signal-strip flutter bar with modifiers; chip dense monospaced pill; manifest table styles. Topbar status strip: new js/topbar-strip.js auto-injects a 28px strip on every page with wall clock, page name, live API latency, and system-pulse dot. Per-page: recorders gain live signal-strip above fps line; capture timecode bumped 38->64px with blue glow; ingest drop zone slimmed 200->88px side-by-side layout so manifest gets the real estate.
This commit is contained in:
parent
bab24e156a
commit
e441176961
8 changed files with 190 additions and 41 deletions
|
|
@ -44,17 +44,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.timecode-display {
|
.timecode-display {
|
||||||
font-size: 38px;
|
font-family: var(--font-mono);
|
||||||
font-weight: 400;
|
font-size: 64px;
|
||||||
|
font-weight: 500;
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
letter-spacing: 0.06em;
|
letter-spacing: 0.05em;
|
||||||
color: var(--accent);
|
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;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timecode-display.inactive {
|
.timecode-display.inactive {
|
||||||
color: var(--text-tertiary);
|
color: var(--text-tertiary);
|
||||||
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timecode-status {
|
.timecode-status {
|
||||||
|
|
@ -313,6 +315,7 @@
|
||||||
<div class="toast-container" id="toastContainer" aria-live="polite"></div>
|
<div class="toast-container" id="toastContainer" aria-live="polite"></div>
|
||||||
|
|
||||||
<script src="js/api.js?v=5"></script>
|
<script src="js/api.js?v=5"></script>
|
||||||
|
<script src="js/topbar-strip.js?v=1"></script>
|
||||||
<script>
|
<script>
|
||||||
const cState = {
|
const cState = {
|
||||||
devices: [],
|
devices: [],
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,23 @@
|
||||||
/* ================================================================
|
/* ================================================================
|
||||||
WILD DRAGON MAM — Design System
|
Z-AMPP — Design System
|
||||||
Broadcast control register. Amber accent. Deep slate.
|
Broadcast operations console. Signature blue. Deep slate.
|
||||||
|
Operator-grade type, tabular numerics, signal-first hierarchy.
|
||||||
================================================================ */
|
================================================================ */
|
||||||
|
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap');
|
||||||
|
|
||||||
/* ================================================================
|
/* ================================================================
|
||||||
TOKENS
|
TOKENS
|
||||||
================================================================ */
|
================================================================ */
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
/* Background scale */
|
/* Surfaces (5-step depth, tinted toward brand hue 266) */
|
||||||
--bg-base: oklch(11% 0.010 250);
|
--bg-deep: oklch(8% 0.011 266);
|
||||||
--bg-panel: oklch(15.5% 0.012 250);
|
--bg-base: oklch(11% 0.010 266);
|
||||||
--bg-surface: oklch(20% 0.014 250);
|
--bg-panel: oklch(15% 0.013 266);
|
||||||
--bg-raised: oklch(25% 0.015 250);
|
--bg-surface: oklch(19% 0.014 266);
|
||||||
--bg-hover: oklch(29% 0.015 250);
|
--bg-raised: oklch(24% 0.015 266);
|
||||||
|
--bg-hover: oklch(28% 0.015 266);
|
||||||
|
|
||||||
/* Accent — amber tally light */
|
/* Accent — amber tally light */
|
||||||
--accent: oklch(45% 0.20 266);
|
--accent: oklch(45% 0.20 266);
|
||||||
|
|
@ -23,26 +25,41 @@
|
||||||
--accent-subtle: oklch(55% 0.20 266 / 0.12);
|
--accent-subtle: oklch(55% 0.20 266 / 0.12);
|
||||||
--accent-border: oklch(55% 0.20 266 / 0.36);
|
--accent-border: oklch(55% 0.20 266 / 0.36);
|
||||||
|
|
||||||
/* Text */
|
/* Text — lifted secondary for readability (was 62%) */
|
||||||
--text-primary: oklch(93% 0.008 250);
|
--text-primary: oklch(94% 0.008 266);
|
||||||
--text-secondary: oklch(62% 0.012 250);
|
--text-secondary: oklch(72% 0.014 266);
|
||||||
--text-tertiary: oklch(44% 0.010 250);
|
--text-tertiary: oklch(52% 0.012 266);
|
||||||
|
--text-disabled: oklch(38% 0.010 266);
|
||||||
|
|
||||||
/* Borders */
|
/* Borders — added faint variant */
|
||||||
--border: oklch(27% 0.014 250);
|
--border-faint: oklch(22% 0.013 266);
|
||||||
--border-strong: oklch(36% 0.016 250);
|
--border: oklch(28% 0.015 266);
|
||||||
|
--border-strong: oklch(38% 0.018 266);
|
||||||
|
|
||||||
/* Status colours */
|
/* Status — raw color slots */
|
||||||
--status-green: oklch(68% 0.18 148);
|
--status-green: oklch(70% 0.18 148);
|
||||||
--status-red: oklch(62% 0.22 25);
|
--status-red: oklch(64% 0.22 25);
|
||||||
--status-blue: oklch(65% 0.16 245);
|
--status-blue: oklch(67% 0.16 245);
|
||||||
--status-amber: var(--accent);
|
--status-yellow: oklch(80% 0.16 90);
|
||||||
--status-gray: oklch(44% 0.010 250);
|
--status-gray: oklch(58% 0.012 266);
|
||||||
|
|
||||||
--status-green-bg: oklch(68% 0.18 148 / 0.10);
|
--status-green-bg: oklch(70% 0.18 148 / 0.12);
|
||||||
--status-red-bg: oklch(62% 0.22 25 / 0.10);
|
--status-red-bg: oklch(64% 0.22 25 / 0.12);
|
||||||
--status-blue-bg: oklch(65% 0.16 245 / 0.10);
|
--status-blue-bg: oklch(67% 0.16 245 / 0.12);
|
||||||
--status-amber-bg: oklch(55% 0.20 266 / 0.12);
|
--status-yellow-bg: oklch(80% 0.16 90 / 0.12);
|
||||||
|
|
||||||
|
/* Semantic signal tokens — use these in operational UI */
|
||||||
|
--signal-good: var(--status-green);
|
||||||
|
--signal-warn: var(--status-yellow);
|
||||||
|
--signal-bad: var(--status-red);
|
||||||
|
--signal-idle: var(--status-gray);
|
||||||
|
--signal-good-bg: var(--status-green-bg);
|
||||||
|
--signal-warn-bg: var(--status-yellow-bg);
|
||||||
|
--signal-bad-bg: var(--status-red-bg);
|
||||||
|
|
||||||
|
/* Legacy aliases (deprecated, kept for stragglers) */
|
||||||
|
--status-amber: var(--accent);
|
||||||
|
--status-amber-bg: var(--accent-subtle);
|
||||||
|
|
||||||
/* Spacing — 4pt base */
|
/* Spacing — 4pt base */
|
||||||
--sp-1: 4px;
|
--sp-1: 4px;
|
||||||
|
|
@ -55,14 +72,18 @@
|
||||||
--sp-12: 48px;
|
--sp-12: 48px;
|
||||||
--sp-16: 64px;
|
--sp-16: 64px;
|
||||||
|
|
||||||
/* Typography */
|
/* Typography — Inter for prose, JetBrains Mono for tabular numerics */
|
||||||
--font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
|
--font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
|
||||||
|
--font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
|
||||||
--text-xs: 11px;
|
--text-xs: 11px;
|
||||||
--text-sm: 13px;
|
--text-sm: 13px;
|
||||||
--text-base: 14px;
|
--text-base: 14px;
|
||||||
--text-md: 16px;
|
--text-md: 16px;
|
||||||
--text-lg: 18px;
|
--text-lg: 18px;
|
||||||
--text-xl: 22px;
|
--text-xl: 22px;
|
||||||
|
--text-2xl: 28px;
|
||||||
|
--text-3xl: 40px;
|
||||||
|
--text-tc: 64px; /* tally-grade timecode */
|
||||||
|
|
||||||
/* Radius */
|
/* Radius */
|
||||||
--r-sm: 4px;
|
--r-sm: 4px;
|
||||||
|
|
@ -162,6 +183,16 @@ svg { display: block; flex-shrink: 0; }
|
||||||
color: oklch(11% 0.010 250);
|
color: oklch(11% 0.010 250);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-logo {
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: var(--r-sm);
|
||||||
|
background: #fff;
|
||||||
|
padding: 2px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-brand-name {
|
.sidebar-brand-name {
|
||||||
font-size: var(--text-sm);
|
font-size: var(--text-sm);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
@ -800,3 +831,52 @@ textarea:focus { border-color: var(--accent-border); box-shadow: 0 0 0 3px var(-
|
||||||
.ampp-loading--inline .ampp-loading-label{font-size:11px}
|
.ampp-loading--inline .ampp-loading-label{font-size:11px}
|
||||||
@keyframes amppPulse{0%,100%{transform:scale(.96);opacity:.78}50%{transform:scale(1);opacity:1}}
|
@keyframes amppPulse{0%,100%{transform:scale(.96);opacity:.78}50%{transform:scale(1);opacity:1}}
|
||||||
@keyframes amppDot{0%,100%{transform:scale(.7);opacity:.35}50%{transform:scale(1.15);opacity:1}}
|
@keyframes amppDot{0%,100%{transform:scale(.7);opacity:.35}50%{transform:scale(1.15);opacity:1}}
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
OPS-CONSOLE ADDITIONS
|
||||||
|
Tally lights, timecode, signal meters, chips.
|
||||||
|
================================================================ */
|
||||||
|
|
||||||
|
/* Timecode — monospaced, tabular-nums, soft glow on focused values */
|
||||||
|
.tc { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: 0.02em; }
|
||||||
|
.tc-display { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-tc); font-weight: 500; letter-spacing: 0.03em; color: var(--accent); text-shadow: 0 0 18px oklch(55% 0.20 266 / 0.35); }
|
||||||
|
.tc-lg { font-size: var(--text-2xl); font-weight: 500; color: var(--text-primary); }
|
||||||
|
.tc-md { font-size: var(--text-md); color: var(--text-secondary); }
|
||||||
|
|
||||||
|
/* Tally word — the big status word on the recorder card */
|
||||||
|
.tally-word { font-size: var(--text-md); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; font-variant-numeric: tabular-nums; }
|
||||||
|
.tally-word--good { color: var(--signal-good); text-shadow: 0 0 14px oklch(70% 0.18 148 / 0.35); }
|
||||||
|
.tally-word--warn { color: var(--signal-warn); text-shadow: 0 0 14px oklch(80% 0.16 90 / 0.30); }
|
||||||
|
.tally-word--bad { color: var(--signal-bad); text-shadow: 0 0 14px oklch(64% 0.22 25 / 0.35); }
|
||||||
|
.tally-word--idle { color: var(--text-tertiary); }
|
||||||
|
.tally-word--rec { color: var(--accent); text-shadow: 0 0 14px oklch(55% 0.20 266 / 0.35); }
|
||||||
|
|
||||||
|
/* Signal strip — horizontal bar fluttering at the source frame rate */
|
||||||
|
.signal-strip { position: relative; height: 4px; border-radius: 2px; background: var(--bg-surface); overflow: hidden; }
|
||||||
|
.signal-strip-fill { position: absolute; inset: 0; width: 100%; background: var(--signal-good); transform-origin: left; animation: signalFlicker 1.1s ease-in-out infinite; }
|
||||||
|
.signal-strip--warn .signal-strip-fill { background: var(--signal-warn); animation-duration: 1.4s; }
|
||||||
|
.signal-strip--bad .signal-strip-fill { background: var(--signal-bad); animation: none; opacity: 0.5; }
|
||||||
|
.signal-strip--idle .signal-strip-fill { background: var(--signal-idle); animation: none; opacity: 0.4; }
|
||||||
|
@keyframes signalFlicker { 0%,100% { transform: scaleX(0.86) } 50% { transform: scaleX(1) } }
|
||||||
|
|
||||||
|
/* Operator chip — leading dot + monospaced label, denser than .badge */
|
||||||
|
.chip { display: inline-flex; align-items: center; gap: 6px; padding: 2px 8px; height: 20px; border-radius: 3px; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; background: var(--bg-surface); color: var(--text-secondary); border: 1px solid var(--border); white-space: nowrap; }
|
||||||
|
.chip-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
|
||||||
|
.chip--good { color: var(--signal-good); border-color: oklch(70% 0.18 148 / 0.35); }
|
||||||
|
.chip--warn { color: var(--signal-warn); border-color: oklch(80% 0.16 90 / 0.35); }
|
||||||
|
.chip--bad { color: var(--signal-bad); border-color: oklch(64% 0.22 25 / 0.35); }
|
||||||
|
.chip--rec { color: var(--accent); border-color: var(--accent-border); }
|
||||||
|
.chip--mono { font-family: var(--font-mono); }
|
||||||
|
|
||||||
|
/* Topbar status strip — thin live-clock + system pulse on every page */
|
||||||
|
.topbar-strip { display: flex; align-items: center; gap: 16px; padding: 0 20px; height: 28px; background: var(--bg-deep); border-bottom: 1px solid var(--border-faint); font-family: var(--font-mono); font-size: 11px; color: var(--text-tertiary); flex-shrink: 0; }
|
||||||
|
.topbar-strip .ts-now { color: var(--text-primary); font-variant-numeric: tabular-nums; letter-spacing: 0.04em; }
|
||||||
|
.topbar-strip .ts-sep { width: 1px; height: 12px; background: var(--border); }
|
||||||
|
.topbar-strip .ts-label { letter-spacing: 0.08em; text-transform: uppercase; }
|
||||||
|
.topbar-strip .ts-value { color: var(--text-secondary); font-variant-numeric: tabular-nums; }
|
||||||
|
.topbar-strip .ts-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--signal-good); box-shadow: 0 0 8px var(--signal-good); }
|
||||||
|
|
||||||
|
/* Section header */
|
||||||
|
.section-rule { display: flex; align-items: baseline; gap: 12px; margin-bottom: var(--sp-4); }
|
||||||
|
.section-rule h2 { font-size: var(--text-md); font-weight: 500; letter-spacing: -0.01em; color: var(--text-primary); }
|
||||||
|
.section-rule-tag { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-tertiary); padding: 1px 6px; border: 1px solid var(--border-faint); border-radius: 2px; }
|
||||||
|
|
|
||||||
|
|
@ -472,6 +472,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="js/api.js?v=5"></script>
|
<script src="js/api.js?v=5"></script>
|
||||||
|
<script src="js/topbar-strip.js?v=1"></script>
|
||||||
<script src="js/preview.js?v=1"></script>
|
<script src="js/preview.js?v=1"></script>
|
||||||
<script src="js/selection.js?v=1"></script>
|
<script src="js/selection.js?v=1"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
|
|
@ -835,5 +835,6 @@ function showError(msg) { toast(msg, 'error'); }
|
||||||
──────────────────────────────────────────────────────── */
|
──────────────────────────────────────────────────────── */
|
||||||
loadJobs();
|
loadJobs();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="js/topbar-strip.js?v=1"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
56
services/web-ui/public/js/topbar-strip.js
Normal file
56
services/web-ui/public/js/topbar-strip.js
Normal file
|
|
@ -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 =
|
||||||
|
'<span class="ts-dot" id="tsDot" title="System pulse"></span>' +
|
||||||
|
'<span class="ts-label">Z-AMPP</span>' +
|
||||||
|
'<span class="ts-now" id="tsNow">00:00:00</span>' +
|
||||||
|
'<span class="ts-sep"></span>' +
|
||||||
|
'<span class="ts-label">Page</span>' +
|
||||||
|
'<span class="ts-value" id="tsPage">' + pageName() + '</span>' +
|
||||||
|
'<span class="ts-sep"></span>' +
|
||||||
|
'<span class="ts-label">API</span>' +
|
||||||
|
'<span class="ts-value" id="tsApi">--</span>';
|
||||||
|
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();
|
||||||
|
})();
|
||||||
|
|
@ -305,6 +305,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=5"></script>
|
<script src="/js/api.js?v=5"></script>
|
||||||
|
<script src="/js/topbar-strip.js?v=1"></script>
|
||||||
<script>
|
<script>
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// STATE MANAGEMENT
|
// STATE MANAGEMENT
|
||||||
|
|
|
||||||
|
|
@ -359,6 +359,7 @@
|
||||||
<div class="toast-container" id="toastContainer" aria-live="polite"></div>
|
<div class="toast-container" id="toastContainer" aria-live="polite"></div>
|
||||||
|
|
||||||
<script src="js/api.js?v=5"></script>
|
<script src="js/api.js?v=5"></script>
|
||||||
|
<script src="js/topbar-strip.js?v=1"></script>
|
||||||
<script>
|
<script>
|
||||||
const pState = { recorders: [], timers: {}, sourceType: 'srt', mode: 'caller', projects: [], signals: {} };
|
const pState = { recorders: [], timers: {}, sourceType: 'srt', mode: 'caller', projects: [], signals: {} };
|
||||||
|
|
||||||
|
|
@ -474,7 +475,7 @@
|
||||||
</span>
|
</span>
|
||||||
${isRecording ? `<span class="recorder-timer" id="timer-${rec.id}">00:00:00</span>` : ''}
|
${isRecording ? `<span class="recorder-timer" id="timer-${rec.id}">00:00:00</span>` : ''}
|
||||||
</div>
|
</div>
|
||||||
${isRecording ? `<div class="recorder-status-row" style="font-size:var(--text-xs);"><span id="signal-${rec.id}" style="color:var(--text-tertiary)">Connecting…</span></div>` : ''}
|
${isRecording ? `<div class="signal-strip" id="signalStrip-${rec.id}"><div class="signal-strip-fill"></div></div><div class="recorder-status-row" style="font-size:var(--text-xs);"><span id="signal-${rec.id}" style="color:var(--text-tertiary);font-family:var(--font-mono);letter-spacing:0.02em">Connecting…</span></div>` : ''}
|
||||||
|
|
||||||
<div class="recorder-source">
|
<div class="recorder-source">
|
||||||
<svg viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" width="12" height="12"><path d="M2 4h10M2 8h7M2 12h5"/></svg>
|
<svg viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" width="12" height="12"><path d="M2 4h10M2 8h7M2 12h5"/></svg>
|
||||||
|
|
@ -548,6 +549,12 @@
|
||||||
mainTxt.style.color = mainCol;
|
mainTxt.style.color = mainCol;
|
||||||
mainDot.style.background = mainCol;
|
mainDot.style.background = mainCol;
|
||||||
}
|
}
|
||||||
|
const strip = document.getElementById('signalStrip-' + rid);
|
||||||
|
if (strip) {
|
||||||
|
strip.classList.remove('signal-strip--warn', 'signal-strip--bad', 'signal-strip--idle');
|
||||||
|
if (sig === 'connecting') strip.classList.add('signal-strip--warn');
|
||||||
|
else if (sig === 'lost' || sig === 'error') strip.classList.add('signal-strip--bad');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDur(s) {
|
function formatDur(s) {
|
||||||
|
|
|
||||||
|
|
@ -27,19 +27,18 @@
|
||||||
|
|
||||||
/* Drop zone */
|
/* Drop zone */
|
||||||
.drop-zone {
|
.drop-zone {
|
||||||
border: 1px dashed var(--border-strong);
|
border: 1px dashed var(--border);
|
||||||
border-radius: var(--r-lg);
|
border-radius: var(--r-md);
|
||||||
background: var(--bg-surface);
|
background: var(--bg-deep);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: var(--sp-12) var(--sp-8);
|
padding: var(--sp-5) var(--sp-6);
|
||||||
gap: var(--sp-4);
|
gap: var(--sp-3);
|
||||||
text-align: center;
|
text-align: left;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color var(--t-fast), background var(--t-fast);
|
transition: border-color var(--t-fast), background var(--t-fast);
|
||||||
min-height: 200px;
|
min-height: 88px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,7 +58,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.drop-zone-icon { color: var(--text-tertiary); }
|
.drop-zone-icon { color: var(--text-tertiary); }
|
||||||
.drop-zone-icon svg { width: 36px; height: 36px; }
|
.drop-zone-icon svg { width: 22px; height: 22px; }
|
||||||
|
|
||||||
.drop-zone-primary {
|
.drop-zone-primary {
|
||||||
font-size: var(--text-md);
|
font-size: var(--text-md);
|
||||||
|
|
@ -250,6 +249,7 @@
|
||||||
<div class="toast-container" id="toastContainer" aria-live="polite"></div>
|
<div class="toast-container" id="toastContainer" aria-live="polite"></div>
|
||||||
|
|
||||||
<script src="js/api.js?v=5"></script>
|
<script src="js/api.js?v=5"></script>
|
||||||
|
<script src="js/topbar-strip.js?v=1"></script>
|
||||||
<script>
|
<script>
|
||||||
const CHUNK = 10 * 1024 * 1024; // 10 MB chunks
|
const CHUNK = 10 * 1024 * 1024; // 10 MB chunks
|
||||||
const state = { projects: [], bins: [], queue: [], uploading: false };
|
const state = { projects: [], bins: [], queue: [], uploading: false };
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue