Inital attempt
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
var cal = document.querySelector(".diary-cal");
|
var cal = document.querySelector(".diary-cal");
|
||||||
if (!cal) return;
|
if (!cal) return;
|
||||||
|
|
||||||
|
cal.querySelectorAll(".dropdown > button").forEach(wireDropdown);
|
||||||
|
|
||||||
var toggle = document.createElement("button");
|
var toggle = document.createElement("button");
|
||||||
toggle.type = "button";
|
toggle.type = "button";
|
||||||
toggle.className = "panel-toggle";
|
toggle.className = "panel-toggle";
|
||||||
@@ -13,20 +15,9 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
var main = document.querySelector("main");
|
var main = document.querySelector("main");
|
||||||
if (main) {
|
if (!main) return;
|
||||||
main.parentNode.insertBefore(toggle, main);
|
main.parentNode.insertBefore(toggle, main);
|
||||||
|
if (window.matchMedia("(max-width: 1100px)").matches) {
|
||||||
main.parentNode.insertBefore(cal, main);
|
main.parentNode.insertBefore(cal, main);
|
||||||
}
|
}
|
||||||
|
|
||||||
cal.querySelectorAll(".dropdown > button").forEach(wireDropdown);
|
|
||||||
|
|
||||||
var pageHeader = document.querySelector("header");
|
|
||||||
function updateTop() {
|
|
||||||
if (!pageHeader || getComputedStyle(cal).position !== "fixed") return;
|
|
||||||
var rect = pageHeader.getBoundingClientRect();
|
|
||||||
cal.style.top = Math.max(8, rect.bottom + 8) + "px";
|
|
||||||
}
|
|
||||||
window.addEventListener("scroll", updateTop, { passive: true });
|
|
||||||
window.addEventListener("resize", updateTop);
|
|
||||||
updateTop();
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
+23
-1
@@ -125,5 +125,27 @@ function deletePage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
wireDropdown(document.querySelector('[data-action="actions-drop"]'));
|
var panel = document.querySelector('.actions');
|
||||||
|
if (!panel) return;
|
||||||
|
|
||||||
|
var toggle = document.createElement('button');
|
||||||
|
toggle.type = 'button';
|
||||||
|
toggle.className = 'panel-toggle';
|
||||||
|
toggle.textContent = 'Actions';
|
||||||
|
toggle.setAttribute('aria-expanded', 'false');
|
||||||
|
toggle.addEventListener('click', function () {
|
||||||
|
var open = panel.classList.toggle('is-open');
|
||||||
|
toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||||||
|
});
|
||||||
|
|
||||||
|
var main = document.querySelector('main');
|
||||||
|
if (!main) return;
|
||||||
|
// Insert at the top of main's parent (right after the header) so the
|
||||||
|
// ACTIONS toggle sits above any toggles other panels may have added.
|
||||||
|
var header = document.querySelector('header');
|
||||||
|
var anchor = header ? header.nextSibling : main.parentNode.firstChild;
|
||||||
|
main.parentNode.insertBefore(toggle, anchor);
|
||||||
|
if (window.matchMedia('(max-width: 1100px)').matches) {
|
||||||
|
main.parentNode.insertBefore(panel, toggle.nextSibling);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
// Lift the floating action button above the footer when the footer is on
|
|
||||||
// screen, so it never overlaps the request-time line or the companion icon.
|
|
||||||
// Mirrors the TOC's header-aware top-offset behaviour in toc.js.
|
|
||||||
(function () {
|
|
||||||
var fab = document.querySelector(".fab");
|
|
||||||
var footer = document.querySelector("footer");
|
|
||||||
if (!fab || !footer) return;
|
|
||||||
|
|
||||||
function updateBottom() {
|
|
||||||
var rect = footer.getBoundingClientRect();
|
|
||||||
var overlap = Math.max(0, window.innerHeight - rect.top);
|
|
||||||
fab.style.bottom = (overlap + 16) + "px";
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("scroll", updateBottom, { passive: true });
|
|
||||||
window.addEventListener("resize", updateBottom);
|
|
||||||
updateBottom();
|
|
||||||
})();
|
|
||||||
+11
-12
@@ -35,20 +35,19 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "extras"}}
|
{{define "extras"}}
|
||||||
{{if .SidebarWidget}}{{.SidebarWidget}}{{end}}
|
<div class="right-rail">
|
||||||
{{if .CanEdit}}
|
{{if .CanEdit}}
|
||||||
<script src="/_/page/fab.js" defer></script>
|
<nav class="actions">
|
||||||
<div class="fab dropdown">
|
<div class="panel-header">ACTIONS</div>
|
||||||
<button class="btn btn-fab" data-action="actions-drop" title="Actions" aria-label="Actions">≡</button>
|
<button class="btn" onclick="newPage()" title="New page (N)">NEW</button>
|
||||||
<div class="dropdown-menu align-right open-up">
|
<a class="btn" href="?edit" title="Edit page (E)">EDIT</a>
|
||||||
<button class="btn dropdown-item" onclick="newPage()" title="New page (N)">NEW</button>
|
<button class="btn" data-companion-reveal hidden title="Reveal in file manager">REVEAL</button>
|
||||||
<a class="btn dropdown-item" href="?edit" title="Edit page (E)">EDIT</a>
|
|
||||||
<button class="btn dropdown-item" data-companion-reveal hidden title="Reveal in file manager">REVEAL</button>
|
|
||||||
{{if not .IsRoot}}
|
{{if not .IsRoot}}
|
||||||
<button class="btn dropdown-item" onclick="movePage()" title="Move page (M)">MOVE</button>
|
<button class="btn" onclick="movePage()" title="Move page (M)">MOVE</button>
|
||||||
<button class="btn dropdown-item danger" onclick="deletePage()" title="Delete page">DELETE</button>
|
<button class="btn danger" onclick="deletePage()" title="Delete page">DELETE</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</nav>
|
||||||
|
{{end}}
|
||||||
|
{{if .SidebarWidget}}{{.SidebarWidget}}{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
|
||||||
|
|||||||
+20
-28
@@ -1,4 +1,4 @@
|
|||||||
(function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
var content = document.querySelector("main");
|
var content = document.querySelector("main");
|
||||||
if (!content) return;
|
if (!content) return;
|
||||||
|
|
||||||
@@ -28,32 +28,24 @@
|
|||||||
});
|
});
|
||||||
nav.appendChild(list);
|
nav.appendChild(list);
|
||||||
|
|
||||||
var toggle = document.createElement("button");
|
var rail = document.querySelector(".right-rail");
|
||||||
toggle.type = "button";
|
if (!rail) {
|
||||||
toggle.className = "panel-toggle";
|
rail = document.createElement("div");
|
||||||
toggle.textContent = "Contents";
|
rail.className = "right-rail";
|
||||||
toggle.setAttribute("aria-expanded", "false");
|
document.body.appendChild(rail);
|
||||||
toggle.addEventListener("click", function () {
|
}
|
||||||
|
rail.appendChild(nav);
|
||||||
|
|
||||||
|
var fab = document.createElement("button");
|
||||||
|
fab.type = "button";
|
||||||
|
fab.className = "btn btn-fab fab";
|
||||||
|
fab.title = "Contents";
|
||||||
|
fab.setAttribute("aria-label", "Contents");
|
||||||
|
fab.setAttribute("aria-expanded", "false");
|
||||||
|
fab.textContent = "≡";
|
||||||
|
fab.addEventListener("click", function () {
|
||||||
var open = nav.classList.toggle("is-open");
|
var open = nav.classList.toggle("is-open");
|
||||||
toggle.setAttribute("aria-expanded", open ? "true" : "false");
|
fab.setAttribute("aria-expanded", open ? "true" : "false");
|
||||||
|
});
|
||||||
|
document.body.appendChild(fab);
|
||||||
});
|
});
|
||||||
|
|
||||||
var main = document.querySelector("main");
|
|
||||||
if (main) {
|
|
||||||
main.parentNode.insertBefore(toggle, main);
|
|
||||||
main.parentNode.insertBefore(nav, main);
|
|
||||||
} else {
|
|
||||||
document.body.appendChild(toggle);
|
|
||||||
document.body.appendChild(nav);
|
|
||||||
}
|
|
||||||
|
|
||||||
var pageHeader = document.querySelector("header");
|
|
||||||
function updateTop() {
|
|
||||||
if (!pageHeader || getComputedStyle(nav).position !== "fixed") return;
|
|
||||||
var rect = pageHeader.getBoundingClientRect();
|
|
||||||
nav.style.top = Math.max(8, rect.bottom + 8) + "px";
|
|
||||||
}
|
|
||||||
window.addEventListener("scroll", updateTop, { passive: true });
|
|
||||||
window.addEventListener("resize", updateTop);
|
|
||||||
updateTop();
|
|
||||||
})();
|
|
||||||
|
|||||||
+74
-2
@@ -348,6 +348,12 @@ main > h2 {
|
|||||||
z-index: 50;
|
z-index: 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Standalone FAB buttons (page TOC) are mobile-only.
|
||||||
|
Wrapped FABs (search actions dropdown) stay visible on desktop. */
|
||||||
|
button.fab {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-fab {
|
.btn-fab {
|
||||||
background: var(--bg-panel);
|
background: var(--bg-panel);
|
||||||
border: 1px solid var(--secondary);
|
border: 1px solid var(--secondary);
|
||||||
@@ -540,6 +546,43 @@ hr {
|
|||||||
background: var(--primary-hover);
|
background: var(--primary-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* === Right rail === */
|
||||||
|
.right-rail {
|
||||||
|
position: fixed;
|
||||||
|
top: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
width: 14rem;
|
||||||
|
max-height: calc(100vh - 2rem);
|
||||||
|
overflow-y: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Panels share visual treatment when inside the rail */
|
||||||
|
.actions,
|
||||||
|
.right-rail .toc,
|
||||||
|
.right-rail .diary-cal {
|
||||||
|
position: static;
|
||||||
|
top: auto;
|
||||||
|
left: auto;
|
||||||
|
right: auto;
|
||||||
|
width: auto;
|
||||||
|
max-height: none;
|
||||||
|
border: 1px solid var(--secondary);
|
||||||
|
background: var(--bg);
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
/* === Table of contents === */
|
/* === Table of contents === */
|
||||||
.toc {
|
.toc {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -832,6 +875,16 @@ hr {
|
|||||||
|
|
||||||
/* === Responsive === */
|
/* === Responsive === */
|
||||||
@media (max-width: 1100px) {
|
@media (max-width: 1100px) {
|
||||||
|
.right-rail {
|
||||||
|
position: static;
|
||||||
|
width: auto;
|
||||||
|
max-height: none;
|
||||||
|
overflow: visible;
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
button.fab {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
.panel-toggle {
|
.panel-toggle {
|
||||||
display: block;
|
display: block;
|
||||||
background: none;
|
background: none;
|
||||||
@@ -854,7 +907,7 @@ hr {
|
|||||||
.panel-toggle[aria-expanded="true"]::before {
|
.panel-toggle[aria-expanded="true"]::before {
|
||||||
content: "▾ ";
|
content: "▾ ";
|
||||||
}
|
}
|
||||||
.toc,
|
.actions,
|
||||||
.diary-cal {
|
.diary-cal {
|
||||||
position: static;
|
position: static;
|
||||||
display: none;
|
display: none;
|
||||||
@@ -863,10 +916,29 @@ hr {
|
|||||||
margin: 0 auto 1rem;
|
margin: 0 auto 1rem;
|
||||||
max-height: none;
|
max-height: none;
|
||||||
}
|
}
|
||||||
.toc.is-open,
|
.actions.is-open {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
.diary-cal.is-open {
|
.diary-cal.is-open {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
/* TOC on mobile is a floating overlay toggled by the FAB. */
|
||||||
|
.toc {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 5rem;
|
||||||
|
right: 1rem;
|
||||||
|
top: auto;
|
||||||
|
left: auto;
|
||||||
|
width: calc(100% - 2rem);
|
||||||
|
max-width: 20rem;
|
||||||
|
max-height: calc(100vh - 8rem);
|
||||||
|
overflow-y: auto;
|
||||||
|
display: none;
|
||||||
|
z-index: 60;
|
||||||
|
}
|
||||||
|
.toc.is-open {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
|
|||||||
Reference in New Issue
Block a user