From 810b6f6159488b08bd7c9a27adcb469788d0f59a Mon Sep 17 00:00:00 2001 From: s0lray Date: Thu, 26 Mar 2026 20:02:00 -0400 Subject: [PATCH] Center header title and fit tree to browser viewport on desktop (THE-120) - Remove
from header flex container that broke title centering - Apply viewport-fit zoom logic on all screen sizes, not just mobile - Set SVG height to calc(100vh - 120px) so tree fills available space - Add overflow:hidden to body to prevent scrolling past viewport - Remove unnecessary top:20px offset from header Co-Authored-By: Paperclip --- public/css/arf.css | 12 ++++------ public/index.html | 1 - public/js/arf.js | 58 ++++++++++++++++++++++------------------------ 3 files changed, 33 insertions(+), 38 deletions(-) diff --git a/public/css/arf.css b/public/css/arf.css index 3e4e894..2c52415 100644 --- a/public/css/arf.css +++ b/public/css/arf.css @@ -70,6 +70,8 @@ body { color: var(--color-text-primary); font-size: var(--font-size-base); font-family: var(--font-family); + margin: 0; + overflow: hidden; } noscript p { @@ -94,7 +96,8 @@ noscript p { svg { display: block; width: 100%; - height: auto; + /* Fill remaining viewport height below header + search bar */ + height: calc(100vh - 120px); cursor: grab; } @@ -109,7 +112,6 @@ svg:active { position: relative; font-size: var(--font-size-xl); font-weight: bold; - top: 20px; text-align: center; color: var(--color-header); padding: var(--space-2) var(--space-4); @@ -393,10 +395,6 @@ a { padding: var(--space-2) var(--space-3); } - #header hr { - display: none; - } - #header-actions { right: var(--space-3); } @@ -417,7 +415,7 @@ a { /* Maximize SVG tree viewport */ svg { - min-height: 60vh; + height: calc(100vh - 80px); } /* Floating notes button (mobile only) */ diff --git a/public/index.html b/public/index.html index 4abff3c..9fc8790 100644 --- a/public/index.html +++ b/public/index.html @@ -31,7 +31,6 @@ -
diff --git a/public/js/arf.js b/public/js/arf.js index 7bbe86a..5919e9e 100644 --- a/public/js/arf.js +++ b/public/js/arf.js @@ -84,38 +84,36 @@ d3.json("arf.json").then(function(json) { root.children.forEach(collapse); - // On mobile, stretch the viewBox to match the actual rendered aspect ratio - // so the zoom-to-fill calculation uses the real visible area, not the - // fixed 1280x800 letterboxed region. - if (window.innerWidth <= 768) { - var rect = svgEl.node().getBoundingClientRect(); - if (rect.width && rect.height) { - svgH = Math.round(svgW * (rect.height / rect.width)); - svgEl.attr("viewBox", "0 0 " + svgW + " " + svgH); - } - - // Run tree layout to get final node positions, then compute zoom from data. - tree(root); - root.descendants().forEach(function(d) { d.y = d.depth * 180; }); - var visibleNodes = root.descendants(); - var minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity; - visibleNodes.forEach(function(d) { - if (d.x < minX) minX = d.x; - if (d.x > maxX) maxX = d.x; - if (d.y < minY) minY = d.y; - if (d.y > maxY) maxY = d.y; - }); - var pad = 40; - var bw = (maxY - minY) || 1; - var bh = (maxX - minX) || 1; - var k = Math.min((svgW - pad * 2) / bw, (svgH - pad * 2) / bh, 3); - var cx = (minY + maxY) / 2; - var cy = (minX + maxX) / 2; - var tx = svgW / 2 - margin[3] - cx * k; - var ty = svgH / 2 - margin[0] - cy * k; - svgEl.call(zoom.transform, d3.zoomIdentity.translate(tx, ty).scale(k)); + // Stretch the viewBox to match the actual rendered aspect ratio so the + // zoom-to-fill calculation uses the real visible area, not the fixed + // 1280x800 letterboxed region. + var rect = svgEl.node().getBoundingClientRect(); + if (rect.width && rect.height) { + svgH = Math.round(svgW * (rect.height / rect.width)); + svgEl.attr("viewBox", "0 0 " + svgW + " " + svgH); } + // Run tree layout to get final node positions, then compute zoom from data. + tree(root); + root.descendants().forEach(function(d) { d.y = d.depth * 180; }); + var visibleNodes = root.descendants(); + var minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity; + visibleNodes.forEach(function(d) { + if (d.x < minX) minX = d.x; + if (d.x > maxX) maxX = d.x; + if (d.y < minY) minY = d.y; + if (d.y > maxY) maxY = d.y; + }); + var pad = 40; + var bw = (maxY - minY) || 1; + var bh = (maxX - minX) || 1; + var k = Math.min((svgW - pad * 2) / bw, (svgH - pad * 2) / bh, 3); + var cx = (minY + maxY) / 2; + var cy = (minX + maxX) / 2; + var tx = svgW / 2 - margin[3] - cx * k; + var ty = svgH / 2 - margin[0] - cy * k; + svgEl.call(zoom.transform, d3.zoomIdentity.translate(tx, ty).scale(k)); + update(root); initSearch(); });