diff --git a/admin.html b/admin.html index e5dfcec..25e158e 100644 --- a/admin.html +++ b/admin.html @@ -6,7 +6,7 @@ MischLabs Admin - +
@@ -48,11 +48,7 @@ -
- Hinweis: Betriebsdaten kommen aus dem MischLabs-Statusproxy. Kachel-Aenderungen werden aktuell lokal im Browser gespeichert oder als `services.json` exportiert; fuer globale Live-Aenderungen folgt spaeter ein Gitea-Commit-Workflow. -
- -
+
@@ -94,6 +90,6 @@
- + diff --git a/admin.js b/admin.js index aa6a1cf..1e6cb17 100644 --- a/admin.js +++ b/admin.js @@ -695,6 +695,32 @@ function startOpsAutoRefresh() { }, 60000); } +function initCollapsibleCards() { + document.querySelectorAll('.ops-card-head').forEach((head) => { + const card = head.closest('.ops-card'); + if (!card) return; + + const bodyEl = card.querySelector('.services-status-board, .ops-list'); + const id = bodyEl ? bodyEl.id : null; + const storageKey = id ? `ops-card-collapsed-${id}` : null; + + if (storageKey) { + const isCollapsed = localStorage.getItem(storageKey) === 'true'; + card.classList.toggle('is-collapsed', isCollapsed); + } + + head.addEventListener('click', (event) => { + if (event.target.closest('button')) { + return; + } + card.classList.toggle('is-collapsed'); + if (storageKey) { + localStorage.setItem(storageKey, card.classList.contains('is-collapsed')); + } + }); + }); +} + async function boot() { await handleCallback(); tokenSet = getStoredTokens(); @@ -717,6 +743,7 @@ async function boot() { logoutButton.hidden = false; adminUser.textContent = `Angemeldet als ${claims.preferred_username || claims.email}`; renderEditor(); + initCollapsibleCards(); refreshOps(); startOpsAutoRefresh(); } diff --git a/style.css b/style.css index 0792a7f..ae8e633 100644 --- a/style.css +++ b/style.css @@ -423,14 +423,16 @@ main { display: inline-flex; align-items: center; justify-content: center; - min-height: 38px; - padding: 0 13px; + min-height: 42px; + padding: 0 18px; color: var(--text); + font-size: 0.92rem; text-decoration: none; background: rgba(17, 22, 36, 0.86); border: 1px solid var(--border); border-radius: var(--radius); cursor: pointer; + transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease; } .ghost-button:hover, @@ -542,12 +544,49 @@ main { margin-bottom: 10px; color: #fff; font-weight: 700; + cursor: pointer; + user-select: none; + transition: color 0.15s ease; +} + +.ops-card-head:hover { + color: #67e8f9; +} + +.ops-card-head > div:first-child, +.ops-card-head > span:first-child { + display: inline-flex; + align-items: center; + gap: 8px; +} + +.ops-card-head > div:first-child::before, +.ops-card-head > span:first-child::before { + content: '▾'; + display: inline-block; + font-size: 0.92rem; + color: var(--dim); + transition: transform 0.22s cubic-bezier(0.175, 0.885, 0.32, 1.275); + transform: rotate(0deg); +} + +.ops-card.is-collapsed .ops-card-head > div:first-child::before, +.ops-card.is-collapsed .ops-card-head > span:first-child::before { + transform: rotate(-90deg); +} + +.ops-card.is-collapsed .ops-card-head { + margin-bottom: 0; +} + +.ops-card.is-collapsed > *:not(.ops-card-head) { + display: none !important; } .ghost-button.mini { - min-height: 30px; - padding: 0 10px; - font-size: 0.78rem; + min-height: 34px; + padding: 0 14px; + font-size: 0.82rem; } .ops-list {