Compare commits

..

3 Commits

Author SHA1 Message Date
luxick fe3522b93b Update Layout 2026-05-17 11:04:52 +02:00
luxick d3e896d74e Fix rendering of new rail 2026-05-17 10:36:23 +02:00
luxick 3e765aa54f Inital attempt 2026-05-15 11:26:07 +02:00
11 changed files with 190 additions and 125 deletions
+3 -3
View File
@@ -60,7 +60,7 @@
menu.appendChild(label);
var link = document.createElement('a');
link.className = 'btn dropdown-item';
link.className = 'btn btn-block';
link.href = COMPANION_BASE + '/config';
link.target = '_blank';
link.rel = 'noopener';
@@ -78,13 +78,13 @@
menu.appendChild(msg);
var win = document.createElement('a');
win.className = 'btn dropdown-item';
win.className = 'btn btn-block';
win.href = '/companion/download/windows';
win.textContent = 'Download — Windows';
menu.appendChild(win);
var lin = document.createElement('a');
lin.className = 'btn dropdown-item';
lin.className = 'btn btn-block';
lin.href = '/companion/download/linux';
lin.textContent = 'Download — Linux';
menu.appendChild(lin);
+2 -2
View File
@@ -5,14 +5,14 @@
<div class="dropdown diary-cal-drop">
<button type="button" class="btn btn-small" data-action="cal-month-drop" aria-expanded="false" title="Monat wählen"></button>
<div class="dropdown-menu scrollable">
{{range .AllMonths}}<a class="btn dropdown-item{{if .IsCurrent}} cal-current{{end}}" href="{{.URL}}">{{.Name}}</a>{{end}}
{{range .AllMonths}}<a class="btn btn-block{{if .IsCurrent}} cal-current{{end}}" href="{{.URL}}">{{.Name}}</a>{{end}}
</div>
</div>
<a href="{{.YearURL}}" class="diary-cal-heading">{{.DisplayYear}}</a>
<div class="dropdown diary-cal-drop">
<button type="button" class="btn btn-small" data-action="cal-year-drop" aria-expanded="false" title="Jahr wählen"></button>
<div class="dropdown-menu align-right scrollable">
{{range .Years}}<a class="btn dropdown-item{{if .IsCurrent}} cal-current{{end}}" href="{{.URL}}">{{.Num}}</a>{{end}}
{{range .Years}}<a class="btn btn-block{{if .IsCurrent}} cal-current{{end}}" href="{{.URL}}">{{.Num}}</a>{{end}}
</div>
</div>
</div>
+5 -14
View File
@@ -2,6 +2,8 @@
var cal = document.querySelector(".diary-cal");
if (!cal) return;
cal.querySelectorAll(".dropdown > button").forEach(wireDropdown);
var toggle = document.createElement("button");
toggle.type = "button";
toggle.className = "panel-toggle";
@@ -13,20 +15,9 @@
});
var main = document.querySelector("main");
if (main) {
main.parentNode.insertBefore(toggle, main);
if (!main) return;
main.parentNode.insertBefore(toggle, main);
if (window.matchMedia("(max-width: 1100px)").matches) {
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();
})();
+19 -19
View File
@@ -15,9 +15,9 @@
<span class="dropdown">
<button type="button" class="btn btn-tool dropdown-toggle" title="Heading (1/2/3)">H▾</button>
<div class="dropdown-menu">
<button type="button" class="btn btn-tool dropdown-item" data-action="h1" data-key="1" title="Heading 1 (1)">Heading 1</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="h2" data-key="2" title="Heading 2 (2)">Heading 2</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="h3" data-key="3" title="Heading 3 (3)">Heading 3</button>
<button type="button" class="btn btn-tool btn-block" data-action="h1" data-key="1" title="Heading 1 (1)">Heading 1</button>
<button type="button" class="btn btn-tool btn-block" data-action="h2" data-key="2" title="Heading 2 (2)">Heading 2</button>
<button type="button" class="btn btn-tool btn-block" data-action="h3" data-key="3" title="Heading 3 (3)">Heading 3</button>
</div>
</span>
<span class="toolbar-sep"></span>
@@ -26,16 +26,16 @@
<span class="dropdown">
<button type="button" class="btn btn-tool dropdown-toggle" title="Link (L/P)">L▾</button>
<div class="dropdown-menu">
<button type="button" class="btn btn-tool dropdown-item" data-action="link" data-key="L" title="Link (L)">Link</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="wikilink" data-key="P" title="Wiki link (P)">Wiki link</button>
<button type="button" class="btn btn-tool btn-block" data-action="link" data-key="L" title="Link (L)">Link</button>
<button type="button" class="btn btn-tool btn-block" data-action="wikilink" data-key="P" title="Wiki link (P)">Wiki link</button>
</div>
</span>
<span class="dropdown">
<button type="button" class="btn btn-tool dropdown-toggle" title="List (U/O/X)">≡▾</button>
<div class="dropdown-menu">
<button type="button" class="btn btn-tool dropdown-item" data-action="ul" data-key="U" title="Unordered list (U)">Unordered list</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="ol" data-key="O" title="Ordered list (O)">Ordered list</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="task" data-key="X" title="Task list (X)">Task list</button>
<button type="button" class="btn btn-tool btn-block" data-action="ul" data-key="U" title="Unordered list (U)">Unordered list</button>
<button type="button" class="btn btn-tool btn-block" data-action="ol" data-key="O" title="Ordered list (O)">Ordered list</button>
<button type="button" class="btn btn-tool btn-block" data-action="task" data-key="X" title="Task list (X)">Task list</button>
</div>
</span>
<button type="button" class="btn btn-tool" data-action="quote" data-key="Q" title="Blockquote (Q)">&gt;</button>
@@ -44,27 +44,27 @@
<span class="dropdown">
<button type="button" class="btn btn-tool dropdown-toggle" title="Table (T)">T▾</button>
<div class="dropdown-menu">
<button type="button" class="btn btn-tool dropdown-item" data-action="fmttable" data-key="T" title="Format table (T)">Format table</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="tblalignleft" title="Align left">Align left</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="tblaligncenter" title="Align center">Align center</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="tblalignright" title="Align right">Align right</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="tblinsertcol" title="Insert column">Insert column</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="tbldeletecol" title="Delete column">Delete column</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="tblinsertrow" title="Insert row">Insert row</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="tbldeleterow" title="Delete row">Delete row</button>
<button type="button" class="btn btn-tool btn-block" data-action="fmttable" data-key="T" title="Format table (T)">Format table</button>
<button type="button" class="btn btn-tool btn-block" data-action="tblalignleft" title="Align left">Align left</button>
<button type="button" class="btn btn-tool btn-block" data-action="tblaligncenter" title="Align center">Align center</button>
<button type="button" class="btn btn-tool btn-block" data-action="tblalignright" title="Align right">Align right</button>
<button type="button" class="btn btn-tool btn-block" data-action="tblinsertcol" title="Insert column">Insert column</button>
<button type="button" class="btn btn-tool btn-block" data-action="tbldeletecol" title="Delete column">Delete column</button>
<button type="button" class="btn btn-tool btn-block" data-action="tblinsertrow" title="Insert row">Insert row</button>
<button type="button" class="btn btn-tool btn-block" data-action="tbldeleterow" title="Delete row">Delete row</button>
</div>
</span>
<span class="dropdown">
<button type="button" class="btn btn-tool dropdown-toggle" title="Insert date (D/W)">D▾</button>
<div class="dropdown-menu">
<button type="button" class="btn btn-tool dropdown-item" data-action="dateiso" data-key="D" title="YYYY-MM-DD (D)">YYYY-MM-DD</button>
<button type="button" class="btn btn-tool dropdown-item" data-action="datelong" data-key="W" title="DE Long (W)">DE Long</button>
<button type="button" class="btn btn-tool btn-block" data-action="dateiso" data-key="D" title="YYYY-MM-DD (D)">YYYY-MM-DD</button>
<button type="button" class="btn btn-tool btn-block" data-action="datelong" data-key="W" title="DE Long (W)">DE Long</button>
</div>
</span>
<span class="dropdown">
<button type="button" class="btn btn-tool dropdown-toggle" title="Special (V)">★▾</button>
<div class="dropdown-menu">
<button type="button" class="btn btn-tool dropdown-item" data-action="movie" data-key="V" title="Import movie (V)">Import movie</button>
<button type="button" class="btn btn-tool btn-block" data-action="movie" data-key="V" title="Import movie (V)">Import movie</button>
</div>
</span>
<span class="toolbar-sep"></span>
+6 -3
View File
@@ -29,9 +29,12 @@
{{end}}
{{block "headerActions" .}}{{end}}
</header>
<main>
{{block "content" .}}{{end}}
</main>
<div class="page-wrap">
<main>
{{block "content" .}}{{end}}
</main>
<aside class="sidebar">{{block "sidebar" .}}{{end}}</aside>
</div>
<footer>
<span class="muted">Request: {{.RenderMS}} ms</span>
{{block "footerExtras" .}}{{end}}
+23 -1
View File
@@ -125,5 +125,27 @@ function deletePage() {
}
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);
}
});
-18
View File
@@ -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();
})();
+10 -18
View File
@@ -34,21 +34,13 @@
{{end}}
{{end}}
{{define "extras"}}
{{if .SidebarWidget}}{{.SidebarWidget}}{{end}}
{{if .CanEdit}}
<script src="/_/page/fab.js" defer></script>
<div class="fab dropdown">
<button class="btn btn-fab" data-action="actions-drop" title="Actions" aria-label="Actions"></button>
<div class="dropdown-menu align-right open-up">
<button class="btn dropdown-item" onclick="newPage()" title="New page (N)">NEW</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}}
<button class="btn dropdown-item" onclick="movePage()" title="Move page (M)">MOVE</button>
<button class="btn dropdown-item danger" onclick="deletePage()" title="Delete page">DELETE</button>
{{end}}
</div>
</div>
{{end}}
{{end}}
{{define "sidebar"}}{{if .CanEdit}}<nav class="actions">
<div class="panel-header">ACTIONS</div>
<button class="btn btn-block" onclick="newPage()" title="New page (N)">NEW PAGE</button>
<a class="btn btn-block" href="?edit" title="Edit page (E)">EDIT PAGE</a>
<button class="btn btn-block" data-companion-reveal hidden title="Reveal in file manager">REVEAL ON CLIENT</button>
{{if not .IsRoot}}
<button class="btn btn-block" onclick="movePage()" title="Move page (M)">MOVE PAGE</button>
<button class="btn btn-block danger" onclick="deletePage()" title="Delete page">DELETE PAGE</button>
{{end}}
</nav>{{end}}{{if .SidebarWidget}}{{.SidebarWidget}}{{end}}{{end}}
+21 -28
View File
@@ -1,4 +1,4 @@
(function () {
document.addEventListener("DOMContentLoaded", function () {
var content = document.querySelector("main");
if (!content) return;
@@ -28,32 +28,25 @@
});
nav.appendChild(list);
var toggle = document.createElement("button");
toggle.type = "button";
toggle.className = "panel-toggle";
toggle.textContent = "Contents";
toggle.setAttribute("aria-expanded", "false");
toggle.addEventListener("click", function () {
var rail = document.querySelector("aside.sidebar");
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");
toggle.setAttribute("aria-expanded", open ? "true" : "false");
fab.setAttribute("aria-expanded", open ? "true" : "false");
});
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();
})();
nav.addEventListener("click", function (e) {
if (e.target.tagName === "A") {
nav.classList.remove("is-open");
fab.setAttribute("aria-expanded", "false");
}
});
document.body.appendChild(fab);
});
+1 -1
View File
@@ -29,7 +29,7 @@
<div class="fab dropdown">
<button class="btn btn-fab" data-action="actions-drop" title="Actions" aria-label="Actions"></button>
<div class="dropdown-menu align-right open-up">
<button class="btn dropdown-item" onclick="rebuildIndex()" title="Rebuild search index">REBUILD INDEX</button>
<button class="btn btn-block" onclick="rebuildIndex()" title="Rebuild search index">REBUILD INDEX</button>
</div>
</div>
{{end}}
+100 -18
View File
@@ -145,13 +145,28 @@ header {
color: var(--danger-hover);
}
/* === Page wrap ===
Note: sticky positioning on .sidebar depends on no ancestor having
overflow: auto/hidden. If you add scroll containment above this, sticky
will silently break. */
.page-wrap {
display: grid;
grid-template-columns: minmax(0, 1fr) 14rem;
gap: 1.5rem;
max-width: 1280px;
margin: 0 auto;
padding: 0 1rem;
width: 100%;
flex: 1;
align-items: start;
}
/* === Main === */
main {
max-width: 860px;
margin: 0 auto;
padding: 1.5rem 1rem;
width: 100%;
flex: 1;
min-width: 0;
}
/* === Markdown content === */
@@ -348,6 +363,12 @@ main > h2 {
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 {
background: var(--bg-panel);
border: 1px solid var(--secondary);
@@ -368,7 +389,7 @@ main > h2 {
color: var(--primary-hover);
}
.dropdown-item {
.btn-block {
display: flex;
justify-content: space-between;
align-items: baseline;
@@ -386,7 +407,7 @@ main > h2 {
flex-direction: column;
}
body.editor-wide main {
body.editor-wide .page-wrap {
max-width: none;
}
@@ -540,6 +561,45 @@ hr {
background: var(--primary-hover);
}
/* === Sidebar === */
.sidebar {
position: sticky;
top: 1rem;
align-self: start;
max-height: calc(100vh - 2rem);
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 1rem;
margin-top: 1.5rem;
}
aside.sidebar:empty {
display: none;
}
/* Panels share visual treatment when inside the sidebar */
.actions,
.sidebar .toc,
.sidebar .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;
gap: 0.15rem;
}
/* === Table of contents === */
.toc {
position: fixed;
@@ -753,17 +813,6 @@ hr {
}
/* === Diary Calendar === */
.diary-cal {
position: fixed;
top: 1rem;
left: 1rem;
width: 13rem;
border: 1px solid var(--secondary);
background: var(--bg);
padding: 0.5rem 0.75rem;
font-size: 0.85rem;
}
.diary-cal-nav {
display: flex;
align-items: center;
@@ -826,12 +875,24 @@ hr {
color: var(--primary-hover);
}
.dropdown-item.cal-current {
.btn-block.cal-current {
color: var(--primary-hover);
}
/* === Responsive === */
@media (max-width: 1100px) {
.page-wrap {
grid-template-columns: 1fr;
}
.sidebar {
display: contents;
position: static;
max-height: none;
overflow: visible;
}
button.fab {
display: inline-flex;
}
.panel-toggle {
display: block;
background: none;
@@ -854,7 +915,7 @@ hr {
.panel-toggle[aria-expanded="true"]::before {
content: "▾ ";
}
.toc,
.actions,
.diary-cal {
position: static;
display: none;
@@ -863,10 +924,31 @@ hr {
margin: 0 auto 1rem;
max-height: none;
}
.toc.is-open,
.actions.is-open {
display: flex;
}
.diary-cal.is-open {
display: block;
}
/* TOC on mobile is a floating overlay toggled by the FAB. */
.sidebar .toc,
.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;
}
.sidebar .toc.is-open,
.toc.is-open {
display: block;
}
}
@media (max-width: 600px) {