console: add always-visible back-to-top button + collapsible dashboard panels (per-section, persisted)
This commit is contained in:
@@ -254,7 +254,6 @@ button.button, input[type="submit"].button { font-family: inherit; }
|
||||
|
||||
/* loading pulse for polling */
|
||||
.tool-grid.htmx-request .tool-card { opacity: .6; transition: opacity .2s; }
|
||||
|
||||
/* -------------------------------------------------- Tool embed */
|
||||
.tool-bar {
|
||||
position: sticky; top: 52px; z-index: 15;
|
||||
@@ -345,3 +344,44 @@ button.button, input[type="submit"].button { font-family: inherit; }
|
||||
[data-theme="dark"] .form-error { background: #3a2424; color: #ffb4ab; border-color: #7a4e4c; }
|
||||
[data-theme="dark"] .tool-icon { color: #1c1e22; }
|
||||
[data-theme="dark"] .category-pill { background: var(--surface-2); }
|
||||
|
||||
/* ---------- Back to top ---------- */
|
||||
.back-to-top {
|
||||
position: fixed;
|
||||
right: 24px;
|
||||
bottom: 24px;
|
||||
z-index: 100;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: var(--rounded-full);
|
||||
border: 1px solid var(--hairline);
|
||||
background: var(--surface-2);
|
||||
color: var(--ink);
|
||||
font-size: 20px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 14px rgba(0,0,0,.15);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
opacity: .85;
|
||||
transition: opacity .2s, transform .15s;
|
||||
}
|
||||
.back-to-top:hover { opacity: 1; transform: translateY(-2px); }
|
||||
[data-theme="dark"] .back-to-top { background: var(--surface-2); box-shadow: 0 4px 14px rgba(0,0,0,.5); }
|
||||
|
||||
/* ---------- Collapsible dashboard panels ---------- */
|
||||
.section-toggle {
|
||||
background: none;
|
||||
border: 1px solid var(--hairline);
|
||||
color: var(--ink);
|
||||
border-radius: var(--rounded-full);
|
||||
width: 26px; height: 26px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
opacity: .7;
|
||||
transition: transform .2s, opacity .2s;
|
||||
}
|
||||
.section-toggle:hover { opacity: 1; }
|
||||
.section.collapsed .section-toggle { transform: rotate(-90deg); }
|
||||
.section.collapsed .tool-grid { display: none; }
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
<main>
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
<button type="button" id="backToTop" class="back-to-top" aria-label="Back to top" title="Back to top">↑</button>
|
||||
<script>
|
||||
(function () {
|
||||
var root = document.documentElement;
|
||||
@@ -53,5 +54,15 @@
|
||||
sync();
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
(function () {
|
||||
var btn = document.getElementById('backToTop');
|
||||
if (!btn) return;
|
||||
btn.addEventListener('click', function () {
|
||||
(window.scrollTo || function(){ document.documentElement.scrollTop = 0; document.body.scrollTop = 0; })
|
||||
.call(window, { top: 0, behavior: 'smooth' });
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -11,6 +11,8 @@
|
||||
{% for section in sections %}
|
||||
<section class="section" data-dash-section>
|
||||
<div class="section-head">
|
||||
<button type="button" class="section-toggle" data-section-toggle
|
||||
title="Collapse / expand this panel" aria-label="Collapse expand panel" aria-expanded="true">▾</button>
|
||||
<span class="category-pill">
|
||||
<span class="pill-dot" style="background:{{ section.color }}"></span>
|
||||
{{ section.label }}
|
||||
@@ -67,5 +69,26 @@
|
||||
var inp = document.querySelector("[data-filter-input]");
|
||||
if (inp) inp.value = window.__dashFilter;
|
||||
apply();
|
||||
|
||||
// --- Collapsible panels (persist per-section in localStorage) ---
|
||||
function paneKey(label) { return "fhlPane_" + (label || "").trim().toLowerCase().replace(/\s+/g, "_"); }
|
||||
function syncToggle(sec) {
|
||||
var b = sec.querySelector("[data-section-toggle]");
|
||||
if (b) b.setAttribute("aria-expanded", sec.classList.contains("collapsed") ? "false" : "true");
|
||||
}
|
||||
document.querySelectorAll("[data-dash-section]").forEach(function (sec) {
|
||||
var head = sec.querySelector(".section-head");
|
||||
var label = head ? head.textContent.trim() : "";
|
||||
var wasCollapsed = false;
|
||||
try { wasCollapsed = localStorage.getItem(paneKey(label)) === "1"; } catch (_) {}
|
||||
if (wasCollapsed) sec.classList.add("collapsed");
|
||||
syncToggle(sec);
|
||||
var b = sec.querySelector("[data-section-toggle]");
|
||||
if (b) b.addEventListener("click", function () {
|
||||
sec.classList.toggle("collapsed");
|
||||
try { localStorage.setItem(paneKey(label), sec.classList.contains("collapsed") ? "1" : "0"); } catch (_) {}
|
||||
syncToggle(sec);
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
Reference in New Issue
Block a user