Fix: Admin-Seite Mobile-kompatibel (Tabellen scrollbar, Filter wrap, Touch-Targets)
This commit is contained in:
parent
92620c2c52
commit
bfdf6ebfae
4 changed files with 208 additions and 81 deletions
|
|
@ -3,7 +3,7 @@
|
|||
Router, State-Management, Navigation, Initialisierung.
|
||||
============================================================ */
|
||||
|
||||
const APP_VER = '124'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VER = '126'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
|
||||
const App = (() => {
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ window.Page_admin = (() => {
|
|||
<div style="max-width:720px;margin:0 auto;padding:var(--space-4)">
|
||||
|
||||
<!-- Tabs -->
|
||||
<div class="by-tabs" style="margin-bottom:var(--space-5)" id="adm-tabs">
|
||||
<div class="by-tabs adm-tabs" id="adm-tabs">
|
||||
${TABS.map(t => `
|
||||
<button class="by-tab${t.id === _tab ? ' active' : ''}" data-tab="${t.id}">
|
||||
${UI.icon(t.icon)} ${t.label}
|
||||
|
|
@ -144,14 +144,10 @@ window.Page_admin = (() => {
|
|||
// ------------------------------------------------------------------
|
||||
async function _renderUsers(el) {
|
||||
el.innerHTML = `
|
||||
<div style="display:flex;gap:var(--space-2);margin-bottom:var(--space-4)">
|
||||
<div class="adm-filter-row">
|
||||
<input id="adm-user-q" type="search" placeholder="Name oder E-Mail…"
|
||||
style="flex:1;padding:var(--space-2) var(--space-3);border:1.5px solid var(--c-border);
|
||||
border-radius:var(--radius-md);font-size:var(--text-sm);font-family:inherit;
|
||||
background:var(--c-surface);color:var(--c-text)">
|
||||
<select id="adm-user-rolle" style="padding:var(--space-2) var(--space-3);
|
||||
border:1.5px solid var(--c-border);border-radius:var(--radius-md);
|
||||
font-size:var(--text-sm);font-family:inherit;background:var(--c-surface);color:var(--c-text)">
|
||||
class="adm-filter-input">
|
||||
<select id="adm-user-rolle" class="adm-filter-select">
|
||||
<option value="">Alle Rollen</option>
|
||||
<option value="user">user</option>
|
||||
<option value="moderator">moderator</option>
|
||||
|
|
@ -339,7 +335,7 @@ window.Page_admin = (() => {
|
|||
async function _renderForum(el) {
|
||||
el.innerHTML = `
|
||||
<!-- Unternavigation -->
|
||||
<div style="display:flex;gap:var(--space-2);margin-bottom:var(--space-4)">
|
||||
<div class="adm-subnav">
|
||||
<button class="btn btn-primary btn-sm adm-forum-nav" data-view="reports" id="adm-fn-reports">
|
||||
Offene Meldungen
|
||||
</button>
|
||||
|
|
@ -429,13 +425,10 @@ window.Page_admin = (() => {
|
|||
} else {
|
||||
// Threads
|
||||
el.innerHTML = `
|
||||
<div style="display:flex;gap:var(--space-2);margin-bottom:var(--space-3)">
|
||||
<div class="adm-filter-row">
|
||||
<input id="adm-thread-q" type="search" placeholder="Threads durchsuchen…"
|
||||
style="flex:1;padding:var(--space-2) var(--space-3);border:1.5px solid var(--c-border);
|
||||
border-radius:var(--radius-md);font-size:var(--text-sm);font-family:inherit;
|
||||
background:var(--c-surface);color:var(--c-text)">
|
||||
<label style="display:flex;align-items:center;gap:var(--space-2);
|
||||
font-size:var(--text-sm);color:var(--c-text-secondary);white-space:nowrap">
|
||||
class="adm-filter-input">
|
||||
<label class="adm-filter-label">
|
||||
<input type="checkbox" id="adm-show-deleted"> Gelöschte
|
||||
</label>
|
||||
</div>
|
||||
|
|
@ -623,39 +616,41 @@ window.Page_admin = (() => {
|
|||
return;
|
||||
}
|
||||
el.innerHTML = `
|
||||
<div class="card" style="overflow:hidden">
|
||||
<table style="width:100%;border-collapse:collapse;font-size:var(--text-sm)">
|
||||
<thead>
|
||||
<tr style="background:var(--c-surface-2);text-align:left">
|
||||
<th style="padding:var(--space-3) var(--space-4);font-weight:var(--weight-semibold);color:var(--c-text-secondary)">Job</th>
|
||||
<th style="padding:var(--space-3) var(--space-4);font-weight:var(--weight-semibold);color:var(--c-text-secondary)">Nächster Lauf</th>
|
||||
<th style="padding:var(--space-3) var(--space-4);font-weight:var(--weight-semibold);color:var(--c-text-secondary)">Trigger</th>
|
||||
<th style="padding:var(--space-3) var(--space-4);font-weight:var(--weight-semibold);color:var(--c-text-secondary)"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${jobs.map((j, i) => `
|
||||
<tr style="${i % 2 === 1 ? 'background:var(--c-surface-2)' : ''}">
|
||||
<td style="padding:var(--space-3) var(--space-4);font-weight:var(--weight-semibold);color:var(--c-text)">
|
||||
${_esc(j.name)}
|
||||
<div style="font-size:var(--text-xs);color:var(--c-text-muted);font-weight:normal">${_esc(j.id)}</div>
|
||||
</td>
|
||||
<td style="padding:var(--space-3) var(--space-4);color:var(--c-text-secondary)">
|
||||
${j.next_run_time ? _formatDateTime(j.next_run_time) : '<span style="color:var(--c-text-muted)">—</span>'}
|
||||
</td>
|
||||
<td style="padding:var(--space-3) var(--space-4);color:var(--c-text-muted);font-size:var(--text-xs);max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">
|
||||
${_esc(j.trigger)}
|
||||
</td>
|
||||
<td style="padding:var(--space-3) var(--space-4);text-align:right">
|
||||
<button class="btn btn-sm btn-ghost adm-job-trigger" data-id="${_esc(j.id)}" data-name="${_esc(j.name)}"
|
||||
title="Jetzt ausführen" style="color:var(--c-primary)">
|
||||
${UI.icon('play')}
|
||||
</button>
|
||||
</td>
|
||||
<div class="card adm-table-card">
|
||||
<div class="adm-table-scroll">
|
||||
<table class="adm-table">
|
||||
<thead>
|
||||
<tr style="background:var(--c-surface-2);text-align:left">
|
||||
<th class="adm-th">Job</th>
|
||||
<th class="adm-th">Nächster Lauf</th>
|
||||
<th class="adm-th">Trigger</th>
|
||||
<th class="adm-th"></th>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
${jobs.map((j, i) => `
|
||||
<tr style="${i % 2 === 1 ? 'background:var(--c-surface-2)' : ''}">
|
||||
<td class="adm-td" style="font-weight:var(--weight-semibold);color:var(--c-text)">
|
||||
${_esc(j.name)}
|
||||
<div class="adm-job-id">${_esc(j.id)}</div>
|
||||
</td>
|
||||
<td class="adm-td" style="color:var(--c-text-secondary);white-space:nowrap">
|
||||
${j.next_run_time ? _formatDateTime(j.next_run_time) : '<span style="color:var(--c-text-muted)">—</span>'}
|
||||
</td>
|
||||
<td class="adm-td adm-td-trigger">
|
||||
${_esc(j.trigger)}
|
||||
</td>
|
||||
<td class="adm-td" style="text-align:right">
|
||||
<button class="btn btn-sm btn-ghost adm-job-trigger adm-icon-btn" data-id="${_esc(j.id)}" data-name="${_esc(j.name)}"
|
||||
title="Jetzt ausführen" style="color:var(--c-primary)">
|
||||
${UI.icon('play')}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
el.querySelectorAll('.adm-job-trigger').forEach(btn => {
|
||||
|
|
@ -704,39 +699,38 @@ window.Page_admin = (() => {
|
|||
return;
|
||||
}
|
||||
el.innerHTML = `
|
||||
<div class="card" style="overflow:hidden">
|
||||
<table style="width:100%;border-collapse:collapse;font-size:var(--text-sm)">
|
||||
<thead>
|
||||
<tr style="background:var(--c-surface-2);text-align:left">
|
||||
<th style="padding:var(--space-3) var(--space-4);font-weight:var(--weight-semibold);color:var(--c-text-secondary)">Wann</th>
|
||||
<th style="padding:var(--space-3) var(--space-4);font-weight:var(--weight-semibold);color:var(--c-text-secondary)">Admin</th>
|
||||
<th style="padding:var(--space-3) var(--space-4);font-weight:var(--weight-semibold);color:var(--c-text-secondary)">Aktion</th>
|
||||
<th style="padding:var(--space-3) var(--space-4);font-weight:var(--weight-semibold);color:var(--c-text-secondary)">Ziel</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${rows.map((r, i) => `
|
||||
<tr style="${i % 2 === 1 ? 'background:var(--c-surface-2)' : ''}">
|
||||
<td style="padding:var(--space-2) var(--space-4);color:var(--c-text-muted);white-space:nowrap;font-size:var(--text-xs)">
|
||||
${_formatDateTime(r.created_at)}
|
||||
</td>
|
||||
<td style="padding:var(--space-2) var(--space-4);color:var(--c-text)">
|
||||
${_esc(r.admin_name || '—')}
|
||||
</td>
|
||||
<td style="padding:var(--space-2) var(--space-4)">
|
||||
<span style="font-size:var(--text-xs);padding:2px 7px;border-radius:3px;
|
||||
background:var(--c-surface-2);color:var(--c-text-secondary);font-family:monospace">
|
||||
${_esc(r.action)}
|
||||
</span>
|
||||
${r.detail ? `<div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-top:2px">${_esc(r.detail)}</div>` : ''}
|
||||
</td>
|
||||
<td style="padding:var(--space-2) var(--space-4);color:var(--c-text-secondary);font-size:var(--text-xs)">
|
||||
${_esc(r.target || '—')}
|
||||
</td>
|
||||
<div class="card adm-table-card">
|
||||
<div class="adm-table-scroll">
|
||||
<table class="adm-table">
|
||||
<thead>
|
||||
<tr style="background:var(--c-surface-2);text-align:left">
|
||||
<th class="adm-th">Wann</th>
|
||||
<th class="adm-th">Admin</th>
|
||||
<th class="adm-th">Aktion</th>
|
||||
<th class="adm-th">Ziel</th>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
${rows.map((r, i) => `
|
||||
<tr style="${i % 2 === 1 ? 'background:var(--c-surface-2)' : ''}">
|
||||
<td class="adm-td" style="color:var(--c-text-muted);white-space:nowrap;font-size:var(--text-xs)">
|
||||
${_formatDateTime(r.created_at)}
|
||||
</td>
|
||||
<td class="adm-td" style="color:var(--c-text);white-space:nowrap">
|
||||
${_esc(r.admin_name || '—')}
|
||||
</td>
|
||||
<td class="adm-td">
|
||||
<span class="adm-badge-mono">${_esc(r.action)}</span>
|
||||
${r.detail ? `<div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-top:2px;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${_esc(r.detail)}</div>` : ''}
|
||||
</td>
|
||||
<td class="adm-td" style="color:var(--c-text-secondary);font-size:var(--text-xs);white-space:nowrap">
|
||||
${_esc(r.target || '—')}
|
||||
</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue