diff --git a/public/admin/admin.css b/public/admin/admin.css index ebd7b54..2e14ff9 100644 --- a/public/admin/admin.css +++ b/public/admin/admin.css @@ -295,13 +295,16 @@ details.field-group > summary.field-group-title:hover { color: var(--text); } } .field.switch-field .switch-label { font-size: 13px; } -/* status on the left, Apply on the right */ +/* the card's one action row: status on the left, Configure / Apply on the right */ .module-actions { display: flex; align-items: center; gap: 10px; - margin-top: 4px; + margin-top: 10px; } +.module-name.is-toggle { cursor: pointer; } +.module-name.is-toggle:hover, +.module-name.is-toggle:focus-visible { color: var(--accent); outline: none; } .module-actions .admin-status { flex: 1; margin-top: 0; } .module-actions .btn { margin-left: auto; } diff --git a/public/admin/admin.js b/public/admin/admin.js index da62c31..0b8806a 100644 --- a/public/admin/admin.js +++ b/public/admin/admin.js @@ -585,15 +585,37 @@ function buildModuleCard(mod) { const actions = document.createElement('div'); actions.className = 'module-actions'; const save = document.createElement('button'); - save.className = 'btn primary'; - save.textContent = 'Apply'; const status = document.createElement('span'); status.className = 'admin-status'; actions.append(status, save); - form.appendChild(actions); + // A card is a status line until someone wants to change something: the + // form starts folded, and the row at the bottom holds one button that + // does both jobs — "Configure" opens the form and becomes "Apply", which + // saves without closing it. The name is the other way in and out. card.appendChild(form); + card.appendChild(actions); + const openKey = 'proddash:admin:open:' + mod.id; + const setOpen = (open) => { + form.hidden = !open; + status.hidden = !open; + save.textContent = open ? 'Apply' : 'Configure'; + save.className = open ? 'btn primary' : 'btn'; + try { sessionStorage.setItem(openKey, open ? '1' : '0'); } catch { /* fine */ } + }; + let wasOpen = false; + try { wasOpen = sessionStorage.getItem(openKey) === '1'; } catch { /* fine */ } + setOpen(wasOpen); + name.classList.add('is-toggle'); + name.title = 'Show or hide this module\'s settings'; + name.tabIndex = 0; + name.setAttribute('role', 'button'); + name.addEventListener('click', () => setOpen(form.hidden)); + name.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setOpen(form.hidden); } + }); save.addEventListener('click', async () => { + if (form.hidden) return setOpen(true); const config = {}; for (const [key, read] of readers) config[key] = read(); save.disabled = true;