From afa42718cbf82b8b56f5962c7bd1318282acbea6 Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 31 Oct 2026 23:07:33 +0100 Subject: dashboard: allow right column to hide --- src/api/dashboard/dashboard.html | 45 +++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/api/dashboard/dashboard.html b/src/api/dashboard/dashboard.html index ec36abf..6effc59 100644 --- a/src/api/dashboard/dashboard.html +++ b/src/api/dashboard/dashboard.html @@ -64,6 +64,10 @@ section.collapsed { align-self: start; } section.collapsed h2 { margin: 0; } section.collapsed h2 .toggle { display: none; } + /* The right column dragged off to the side: the map takes the width. */ + @media (min-width: 901px) { + main.right-hidden > section:not(#map) { display: none; } + } section h2 .what .id { color: var(--muted); font-weight: normal; word-break: break-all; } /* The space between boxes, where they are resized. */ main.resize-columns, main.resize-columns * { cursor: col-resize; } @@ -1193,9 +1197,13 @@ document.getElementById("document").replaceChildren( // A box is busy while text in it is selected: drawing it anew would lose the selection, // so it waits (`held`) until it's gone. +// Collapsed, or not shown at all (the right column dragged off): drawn when opened +// (`release`). +function hidden(box) { + return box.classList.contains("collapsed") || box.getClientRects().length === 0; +} function busy(box) { - // Collapsed: drawn when opened (`release`). - if (box.classList.contains("collapsed")) return true; + if (hidden(box)) return true; const selection = window.getSelection(); if (!selection || selection.isCollapsed || !selection.rangeCount) return false; return box.contains(selection.getRangeAt(0).commonAncestorContainer); @@ -1531,7 +1539,7 @@ function logTraffic(way, peer, total, kinds) { (way === "sent" ? "→ " : "← ") + name(peer) + ": " + total + " (" + parts + ")"]; consoleLines.push(line); if (consoleLines.length > CONSOLE_LINES) consoleLines.shift(); - if (document.getElementById("console-box").classList.contains("collapsed")) return; + if (hidden(document.getElementById("console-box"))) return; const log = document.getElementById("console"); const scroll = document.getElementById("console-scroll"); const following = scroll.scrollTop + scroll.clientHeight >= scroll.scrollHeight - 4; @@ -1683,16 +1691,25 @@ window.addEventListener("resize", () => { layoutAgain(); render(); }); // --- Sizes: the space between boxes dragged to resize them, double-clicked to reset; // kept in this browser --- const main = document.querySelector("main"); -// The map's share of the width; the peers' height in px; the console's share of what -// the peers leave, and the figures' share of the rest. Null: as laid out by default. +// The map's share of the width (1: the right column dragged off to the side, hidden); +// the peers' height in px; the console's share of what the peers leave, and the +// figures' share of the rest. Null: as laid out by default. let sizes = { columns: null, peers: null, split: null, console: null }; try { sizes = { ...sizes, ...JSON.parse(localStorage.getItem("continuum-sizes") || "{}") }; } catch (_) {} function applySizes() { const style = main.style; + const wasHidden = main.classList.contains("right-hidden"); + main.classList.toggle("right-hidden", sizes.columns === 1); if (sizes.columns === null) style.removeProperty("--columns"); + else if (sizes.columns === 1) style.setProperty("--columns", "minmax(0, 1fr) 0"); else style.setProperty("--columns", "minmax(0, " + sizes.columns + "fr) minmax(0, " + (1 - sizes.columns) + "fr)"); + // Back: what waited is drawn. + if (wasHidden && sizes.columns !== 1) { + if (!hidden(document.getElementById("console-box"))) showConsole(); + release(); + } // A collapsed box's row as tall as its title. const shut = id => document.getElementById(id).classList.contains("collapsed"); const split = sizes.split === null ? .5 : sizes.split; @@ -1708,9 +1725,12 @@ function applySizes() { const box = id => document.getElementById(id).getBoundingClientRect(); // Which space between boxes `event` is over, if any: "columns", "peers" (below the // peers), "split" (between figures and document) or "console" (above the console). -// Only side by side. +// Only side by side; with the right column hidden, right of the map: "columns". function gapAt(event) { if (event.target !== main) return null; + if (sizes.columns === 1 && main.classList.contains("right-hidden")) { + return event.clientX >= box("map").right ? "columns" : null; + } const map = box("map"), peers = box("peers-box"), figures = box("figures-box"), documentBox = box("document-box"), consoleBox = box("console-box"); if (map.right >= peers.left) return null; @@ -1723,11 +1743,16 @@ function gapAt(event) { } function resizeTo(gap, event) { const clamp = (value, low, high) => Math.min(high, Math.max(low, value)); - const half = (box("peers-box").left - box("map").right) / 2; + // The space between boxes (`main`'s gap), half of it each side. + const half = parseFloat(getComputedStyle(main).columnGap) / 2; if (gap === "columns") { - const map = box("map"), peers = box("peers-box"); - sizes.columns = clamp((event.clientX - half - map.left) / (peers.right - map.left - 2 * half), - .2, .8); + // Across the whole width: the right column's right edge is `main`'s, inside. + const map = box("map"); + const right = main.getBoundingClientRect().right - + parseFloat(getComputedStyle(main).paddingRight); + const share = (event.clientX - half - map.left) / (right - map.left - 2 * half); + // Dragged to the side: hidden. + sizes.columns = share > .9 ? 1 : clamp(share, .2, .8); } else if (gap === "peers") { const peers = box("peers-box"), consoleBox = box("console-box"); sizes.peers = Math.round(clamp(event.clientY - half - peers.top, 60, -- cgit v1.3.1