From 4e5e88cf0b05e7ddfc9b2d93df33653e710ff8af Mon Sep 17 00:00:00 2001 From: s0lray Date: Thu, 26 Mar 2026 19:54:31 -0400 Subject: [PATCH] Add Notes and theme toggle buttons to desktop header (THE-120) Move theme toggle from legend to header as "Light Mode"/"Dark Mode" button visible on both desktop and mobile. Add "Notes" button in header (desktop only; mobile keeps floating pill). Legend and notes content now load into a 400px slide-in side panel on desktop, matching the full-screen mobile overlay. Escape key closes notes panel. Co-Authored-By: Paperclip --- public/css/arf.css | 247 +++++++++++++++++++++++---------------------- public/index.html | 12 +-- public/js/arf.js | 21 ++-- 3 files changed, 144 insertions(+), 136 deletions(-) diff --git a/public/css/arf.css b/public/css/arf.css index b0f6f03..3e4e894 100644 --- a/public/css/arf.css +++ b/public/css/arf.css @@ -103,20 +103,51 @@ svg:active { } #header { + display: flex; + align-items: center; + justify-content: center; + 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); +} + +#header-actions { + position: absolute; + right: var(--space-4); + top: 50%; + transform: translateY(-50%); + display: flex; + gap: var(--space-2); + align-items: center; +} + +#header-actions button { + background: none; + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + color: var(--color-text-secondary); + font-size: var(--font-size-sm); + font-family: var(--font-family); + padding: var(--space-1) var(--space-2); + cursor: pointer; + white-space: nowrap; +} + +#header-actions button:hover { + color: var(--color-text-primary); + border-color: var(--color-text-secondary); } .legend { - position: absolute; - top: 0px; - right: 0; - width: 330px; - font-size: var(--font-size-sm); - color: var(--color-legend); + display: none; +} + +#notes-content { + display: none; } .legend a { @@ -260,24 +291,97 @@ a { text-align: center; } -/* Mobile theme toggle (hidden on desktop) */ -#mobile-theme-toggle { - display: none; -} - -/* Mobile notes button (hidden on desktop) */ +/* Mobile floating notes button (hidden on desktop; header button used instead) */ #mobile-notes-btn { display: none; } -/* Notes overlay (hidden on desktop) */ +/* Notes overlay */ #notes-overlay { display: none; + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 299; } -/* Notes panel (hidden on desktop) */ +#notes-overlay.visible { + display: block; +} + +/* Notes panel (desktop: side panel) */ #notes-panel { - display: none; + display: flex; + flex-direction: column; + position: fixed; + top: 0; + right: 0; + width: 400px; + max-width: 100vw; + height: 100vh; + background: var(--color-surface); + z-index: 300; + transform: translateX(100%); + transition: transform 250ms ease; + will-change: transform; + box-shadow: var(--shadow-md); +} + +#notes-panel.open { + transform: translateX(0); +} + +#notes-panel-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--space-4); + border-bottom: 1px solid var(--color-border); + flex-shrink: 0; +} + +#notes-panel-title { + font-size: var(--font-size-lg); + font-weight: bold; + color: var(--color-text-primary); +} + +#notes-panel-close { + background: none; + border: none; + color: var(--color-text-secondary); + font-size: 20px; + line-height: 1; + cursor: pointer; + padding: 2px var(--space-1); + border-radius: var(--radius-sm); +} + +#notes-panel-close:hover { + color: var(--color-text-primary); + background: var(--color-bg); +} + +#notes-panel-body { + flex: 1; + padding: var(--space-4); + overflow-y: auto; + font-size: var(--font-size-base); + color: var(--color-text-primary); + line-height: 1.6; +} + +#notes-panel-body a { + color: var(--color-node-stroke); +} + +#notes-panel-body h3 { + margin-top: var(--space-4); + margin-bottom: var(--space-2); +} + +#notes-panel-body h3:first-child { + margin-top: 0; } /* === Mobile responsive === */ @@ -286,7 +390,6 @@ a { font-size: var(--font-size-lg); top: 0; position: relative; - text-align: center; padding: var(--space-2) var(--space-3); } @@ -294,26 +397,13 @@ a { display: none; } - #mobile-theme-toggle { - display: inline-block; - position: absolute; + #header-actions { right: var(--space-3); - top: 50%; - transform: translateY(-50%); - background: none; - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - color: var(--color-text-secondary); - font-size: var(--font-size-sm); - font-family: var(--font-family); - padding: var(--space-1) var(--space-2); - cursor: pointer; - white-space: nowrap; } - #mobile-theme-toggle:hover { - color: var(--color-text-primary); - border-color: var(--color-text-secondary); + /* Hide desktop notes button on mobile (floating button used instead) */ + #header-notes-btn { + display: none; } #search-container { @@ -325,21 +415,12 @@ a { font-size: 13px; } - /* Hide legend and notes content on mobile */ - .legend { - display: none; - } - - #notes-content { - display: none; - } - /* Maximize SVG tree viewport */ svg { min-height: 60vh; } - /* Floating notes button */ + /* Floating notes button (mobile only) */ #mobile-notes-btn { display: block; position: fixed; @@ -363,85 +444,9 @@ a { background: var(--color-bg); } - /* Notes overlay */ - #notes-overlay { - display: none; - position: fixed; - inset: 0; - background: rgba(0, 0, 0, 0.5); - z-index: 299; - } - - #notes-overlay.visible { - display: block; - } - - /* Notes panel */ + /* Full-width notes panel on mobile */ #notes-panel { - display: flex; - flex-direction: column; - position: fixed; - top: 0; - right: 0; width: 100vw; - height: 100vh; - background: var(--color-surface); - z-index: 300; - transform: translateX(100%); - transition: transform 250ms ease; - will-change: transform; - } - - #notes-panel.open { - transform: translateX(0); - } - - #notes-panel-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: var(--space-4); - border-bottom: 1px solid var(--color-border); - flex-shrink: 0; - } - - #notes-panel-title { - font-size: var(--font-size-lg); - font-weight: bold; - color: var(--color-text-primary); - } - - #notes-panel-close { - background: none; - border: none; - color: var(--color-text-secondary); - font-size: 20px; - line-height: 1; - cursor: pointer; - padding: 2px var(--space-1); - border-radius: var(--radius-sm); - } - - #notes-panel-close:hover { - color: var(--color-text-primary); - background: var(--color-bg); - } - - #notes-panel-body { - flex: 1; - padding: var(--space-4); - overflow-y: auto; - font-size: var(--font-size-base); - color: var(--color-text-primary); - line-height: 1.6; - } - - #notes-panel-body h3 { - margin-top: var(--space-4); - margin-bottom: var(--space-2); - } - - #notes-panel-body h3:first-child { - margin-top: 0; + box-shadow: none; } } diff --git a/public/index.html b/public/index.html index a968bdd..4abff3c 100644 --- a/public/index.html +++ b/public/index.html @@ -27,7 +27,10 @@
@@ -104,14 +107,11 @@ R - Requires registration
M - Indicates a URL that contains the search term and the URL itself must be edited manually

-
diff --git a/public/js/arf.js b/public/js/arf.js index 3dce43b..7bbe86a 100644 --- a/public/js/arf.js +++ b/public/js/arf.js @@ -654,9 +654,16 @@ function closePanel() { if (root) update(root); } -// Keyboard: Escape closes panel +// Keyboard: Escape closes panels document.addEventListener("keydown", function(e) { - if (e.key === "Escape") closePanel(); + if (e.key === "Escape") { + var notesPanel = document.getElementById("notes-panel"); + if (notesPanel && notesPanel.classList.contains("open")) { + toggleNotesPanel(); + } else { + closePanel(); + } + } }); // Wire close button once DOM is ready @@ -808,19 +815,15 @@ function goDark() { var body = document.body; var isLight = body.classList.toggle("light-mode"); localStorage.setItem("theme", isLight ? "light" : "dark"); - var btn = document.getElementById("theme-toggle"); + var btn = document.getElementById("header-theme-toggle"); if (btn) { - btn.textContent = isLight ? "Switch to dark mode" : "Switch to light mode"; - } - var mBtn = document.getElementById("mobile-theme-toggle"); - if (mBtn) { - mBtn.textContent = isLight ? "Dark Mode" : "Light Mode"; + btn.textContent = isLight ? "Dark Mode" : "Light Mode"; } // Re-render to pick up new CSS variable values for D3 inline styles. update(root); } -// Mobile notes panel toggle +// Notes panel toggle function toggleNotesPanel() { var panel = document.getElementById("notes-panel"); var overlay = document.getElementById("notes-overlay");