Make info panels collapsible with remembered state

Each main section with a data-panel key can now be folded by clicking its
heading (rotating chevron, keyboard-accessible via role/tabindex/aria-expanded
and Enter/Space). Collapsed keys are persisted in localStorage and restored on
load, so the layout stays how you left it across reloads.

State is device-global like the theme (a single non-namespaced key, not
per-user data), and only collapsed panels are stored — so any panel added
later defaults to open.
This commit is contained in:
Alexander Heldt
2026-07-10 16:57:48 +00:00
parent f4ce7dcb54
commit 561b98b64f
3 changed files with 70 additions and 7 deletions
+42
View File
@@ -1769,6 +1769,48 @@
if (ev) openEditDialog(ev);
});
// ---------- collapsible panels ----------
// Each main section carrying a data-panel key can be folded by clicking its
// heading; collapsed keys are remembered across reloads. State is device-global
// (like the theme), so a single non-namespaced key is fine — it's not per-user
// data. Only collapsed panels are stored, so newly added panels default open.
const PANELS_KEY = "puppy-tracker:panels:v1";
function loadPanelState() {
try {
const s = JSON.parse(localStorage.getItem(PANELS_KEY));
return s && typeof s === "object" ? s : {};
} catch { return {}; }
}
function savePanelState(state) {
try { localStorage.setItem(PANELS_KEY, JSON.stringify(state)); } catch { /* ignore */ }
}
function initPanels() {
const state = loadPanelState();
document.querySelectorAll("main section[data-panel]").forEach(section => {
const key = section.dataset.panel;
const h2 = section.querySelector(":scope > h2");
if (!h2) return;
section.classList.add("collapsible");
const collapsed = !!state[key];
section.classList.toggle("collapsed", collapsed);
h2.setAttribute("role", "button");
h2.setAttribute("tabindex", "0");
h2.setAttribute("aria-expanded", String(!collapsed));
const toggle = () => {
const nowCollapsed = section.classList.toggle("collapsed");
h2.setAttribute("aria-expanded", String(!nowCollapsed));
const s = loadPanelState();
if (nowCollapsed) s[key] = true; else delete s[key];
savePanelState(s);
};
h2.addEventListener("click", toggle);
h2.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") { e.preventDefault(); toggle(); }
});
});
}
initPanels();
// ---------- wiring ----------
document.querySelectorAll("button.action").forEach(btn => {
btn.addEventListener("click", () => {