From 2cbb03894b1553d80351a878b90f7dc6ba78396e Mon Sep 17 00:00:00 2001 From: Johan Sandoval Date: Tue, 6 Oct 2026 16:29:23 +0000 Subject: [PATCH] Card layout for tables on phones and tablets; fit terminal bar Sideways-scrolling tables only showed a few of the 11 columns at a time on a phone or iPad. Below 1100px (where the nav already collapses) each row now renders as a card: the device as the title and every other column as a labelled line, one card per row on phones and two or more on tablets. - web/mobile.js copies column names onto cells (data-label) for the cards and re-applies them as the dashboard re-renders; no-op on wide screens - Column filters fold behind a "Show filters" button with an active count - Custom View keeps its sort/filter header as a strip of chips - Terminal: Follow and the "your actions (simulated)" legend move into the terminal window's title bar; tabs read "Server" / "Worker" on phones, so LIVE, the legend and Follow are all visible on small screens --- web/demo/demo.css | 14 +++--- web/demo/demo.js | 19 +++++-- web/index.html | 1 + web/mobile.css | 124 +++++++++++++++++++++++++++++++++++++++++----- web/mobile.js | 93 ++++++++++++++++++++++++++++++++++ 5 files changed, 227 insertions(+), 24 deletions(-) create mode 100644 web/mobile.js diff --git a/web/demo/demo.css b/web/demo/demo.css index d3f8191..9b73e1a 100644 --- a/web/demo/demo.css +++ b/web/demo/demo.css @@ -42,9 +42,12 @@ body.usmt-term-open { padding-bottom: calc(var(--usmt-term-h, 340px) + 72px); } .usmt-term-window { height: var(--usmt-term-h); display: flex; flex-direction: column; background: #012456; } .usmt-term.collapsed .usmt-term-window { display: none; } .usmt-term-titlebar { - height: 26px; flex: 0 0 26px; display: flex; align-items: center; padding: 0 12px; + height: 32px; flex: 0 0 32px; display: flex; align-items: center; gap: 10px; padding: 0 8px 0 12px; background: #0c0c0c; color: #cccccc; font-size: 0.78em; border-bottom: 1px solid #1b1b1b; } +.usmt-term-wtitle { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.usmt-term-titlebar .usmt-term-legend { font-size: 1em; } +.usmt-term-titlebar .usmt-term-follow { font-size: 1em; padding: 3px 10px; } .usmt-term-screens { flex: 1; min-height: 0; position: relative; } .usmt-term-body { display: none; position: absolute; inset: 0; overflow: auto; padding: 8px 12px 14px 18px; @@ -103,12 +106,11 @@ body.usmt-term-open { padding-bottom: calc(var(--usmt-term-h, 340px) + 72px); } .usmt-demo-actions .usmt-demo-reset { color: #e74c3c; border-color: #e74c3c; margin-right: auto; } @media (max-width: 700px) { - .usmt-term-legend, .usmt-term-follow { display: none; } - .usmt-term-bar { gap: 4px; padding: 0 6px; } + .t-long { display: none; } /* "Server" / "Worker", shorter titles */ + .usmt-term-bar { gap: 4px; padding: 0 8px; } .usmt-term-toggle { padding: 4px 6px; } - .usmt-term-tabs { flex: 1 1 auto; overflow: hidden; } - .usmt-term-tab { padding: 4px 6px; font-size: 0.72em; } - .usmt-term-live { font-size: 0; gap: 0; } /* just the pulsing dot */ + .usmt-term-tabs { flex: 0 1 auto; min-width: 0; } + .usmt-term-tab { padding: 4px 10px; font-size: 0.8em; } .usmt-term { --usmt-term-h: 45vh; } .usmt-term-body { font-size: 11.5px; padding: 6px 8px 10px 14px; } .usmt-term-titlebar { font-size: 0.7em; } diff --git a/web/demo/demo.js b/web/demo/demo.js index 3e6a5b0..10ac60b 100644 --- a/web/demo/demo.js +++ b/web/demo/demo.js @@ -89,11 +89,13 @@
LIVE - ${this.demo ? 'your actions (simulated)' : ''} -
-
+
+ + ${this.demo ? 'your actions (simulated)' : ''} + +
`; document.body.appendChild(dock); @@ -103,7 +105,11 @@ const screens = dock.querySelector('.usmt-term-screens'); TERMINALS.forEach(t => { const b = document.createElement('button'); - b.type = 'button'; b.className = 'usmt-term-tab'; b.dataset.id = t.id; b.textContent = t.title; + b.type = 'button'; b.className = 'usmt-term-tab'; b.dataset.id = t.id; b.title = t.title; + // "USMT-Server.ps1" on wide screens, just "Server" on phones + const m = t.title.match(/^(USMT-)(.+)(\.ps1)$/); + if (m) b.innerHTML = `${m[1]}${m[2]}${m[3]}`; + else b.textContent = t.title; b.onclick = () => { this.select(t.id); if (!this.open) this.toggle(true); }; tabs.appendChild(b); const body = document.createElement('div'); @@ -143,7 +149,10 @@ this.el.querySelectorAll('.usmt-term-tab').forEach(b => b.classList.toggle('active', b.dataset.id === id)); this.el.querySelectorAll('.usmt-term-body').forEach(b => b.classList.toggle('active', b.dataset.id === id)); const t = TERMINALS.find(x => x.id === id); - this.el.querySelector('.usmt-term-wtitle').textContent = (this.demo ? 'Administrator: PowerShell (demo container) - ' : 'Administrator: PowerShell - ') + t.title; + const wtitle = this.el.querySelector('.usmt-term-wtitle'); + wtitle.innerHTML = ''; + wtitle.firstChild.textContent = this.demo ? 'Administrator: PowerShell (demo container) - ' : 'Administrator: PowerShell - '; + wtitle.lastChild.textContent = t.title; this.el.querySelector(`.usmt-term-tab[data-id="${id}"]`).classList.remove('unread'); try { localStorage.setItem('usmt_term_tab', id); } catch (e) {} this.poll(id); diff --git a/web/index.html b/web/index.html index 021ac60..41742e7 100755 --- a/web/index.html +++ b/web/index.html @@ -352,6 +352,7 @@ } + diff --git a/web/mobile.css b/web/mobile.css index 2a8862b..b5b2193 100644 --- a/web/mobile.css +++ b/web/mobile.css @@ -1,9 +1,117 @@ /* - * Small-screen layout for the dashboard (phones, small tablets, split windows). + * Small-screen layout for the dashboard (phones, tablets, narrow windows). * Loaded after the page's own