Mobile: horizontal-scroll tables + tab fade (Commit 4/4)

- Wrap wide tables (admin, settings, reports) in .table-wrap with
  min-width on the table so they scroll horizontally on narrow screens
  instead of collapsing rows.
- Add global .table-wrap { overflow-x: auto } utility.
- Mobile: add mask-image fade on .tabs right edge to hint scrollability
  when tabs overflow; flex-shrink:0 on .tab keeps labels intact.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
ScreenTinker 2026-04-21 15:56:01 -05:00
parent b45d81cfaa
commit 06d3e93e21
4 changed files with 28 additions and 7 deletions

View file

@ -878,6 +878,12 @@ body {
line-height: 1.4;
}
/* Table wrapper: enables horizontal scroll when table min-width exceeds viewport */
.table-wrap {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
/* Mobile hamburger toggle */
.mobile-menu-btn {
display: none;
@ -924,8 +930,13 @@ body {
.remote-container { flex-direction: column; }
.remote-controls { width: 100%; flex-direction: row; flex-wrap: wrap; }
.modal { width: 95vw; max-height: 90vh; overflow-y: auto; }
.tabs { overflow-x: auto; }
.tab { white-space: nowrap; }
.tabs {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
-webkit-mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
}
.tab { white-space: nowrap; flex-shrink: 0; }
/* Dashboard stats stack to single column */
.dash-stats-row { flex-direction: column; }

View file

@ -48,7 +48,8 @@ async function loadUsers() {
const [users, plans] = await Promise.all([API('/auth/users'), fetch('/api/subscription/plans').then(r => r.json())]);
el.innerHTML = `
<table style="width:100%;border-collapse:collapse;font-size:13px">
<div class="table-wrap">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:720px">
<thead><tr style="border-bottom:1px solid var(--border)">
<th style="padding:8px;text-align:left;color:var(--text-muted)">User</th>
<th style="padding:8px;text-align:left;color:var(--text-muted)">Auth</th>
@ -82,6 +83,7 @@ async function loadUsers() {
`).join('')}
</tbody>
</table>
</div>
<p style="color:var(--text-muted);font-size:11px;margin-top:8px">${users.length} total users</p>
`;
@ -126,7 +128,8 @@ async function loadPlans() {
try {
const plans = await fetch('/api/subscription/plans').then(r => r.json());
el.innerHTML = `
<table style="width:100%;border-collapse:collapse;font-size:13px">
<div class="table-wrap">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:500px">
<thead><tr style="border-bottom:1px solid var(--border)">
<th style="padding:8px;text-align:left;color:var(--text-muted)">Plan</th>
<th style="padding:8px;text-align:right;color:var(--text-muted)">Devices</th>
@ -146,6 +149,7 @@ async function loadPlans() {
`).join('')}
</tbody>
</table>
</div>
`;
} catch (err) { el.innerHTML = `<p style="color:var(--danger)">${esc(err.message)}</p>`; }
}

View file

@ -103,7 +103,8 @@ export async function render(container) {
<!-- Top Content -->
<div class="settings-section" style="margin-bottom:20px">
<h3 style="font-size:14px;margin-bottom:12px">Top Content</h3>
<table style="width:100%;border-collapse:collapse;font-size:13px">
<div class="table-wrap">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:460px">
<thead><tr style="border-bottom:1px solid var(--border)">
<th style="padding:8px;text-align:left;color:var(--text-muted)">Content</th>
<th style="padding:8px;text-align:right;color:var(--text-muted)">Plays</th>
@ -121,12 +122,14 @@ export async function render(container) {
`).join('') || '<tr><td colspan="4" style="padding:16px;text-align:center;color:var(--text-muted)">No data</td></tr>'}
</tbody>
</table>
</div>
</div>
<!-- By Device -->
<div class="settings-section">
<h3 style="font-size:14px;margin-bottom:12px">By Device</h3>
<table style="width:100%;border-collapse:collapse;font-size:13px">
<div class="table-wrap">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:400px">
<thead><tr style="border-bottom:1px solid var(--border)">
<th style="padding:8px;text-align:left;color:var(--text-muted)">Device</th>
<th style="padding:8px;text-align:right;color:var(--text-muted)">Plays</th>
@ -142,6 +145,7 @@ export async function render(container) {
`).join('') || '<tr><td colspan="3" style="padding:16px;text-align:center;color:var(--text-muted)">No data</td></tr>'}
</tbody>
</table>
</div>
</div>
`;

View file

@ -333,7 +333,8 @@ async function loadUsers() {
const currentUser = JSON.parse(localStorage.getItem('user') || '{}');
el.innerHTML = `
<table style="width:100%;border-collapse:collapse;font-size:13px">
<div class="table-wrap">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:520px">
<thead>
<tr style="border-bottom:1px solid var(--border);text-align:left">
<th style="padding:8px 12px;color:var(--text-muted);font-weight:500">User</th>
@ -368,6 +369,7 @@ async function loadUsers() {
`).join('')}
</tbody>
</table>
</div>
<p style="color:var(--text-muted);font-size:11px;margin-top:12px">${users.length} user(s) registered</p>
`;