From a67bedc6f26507bf698560ff450aa460aa1f6080 Mon Sep 17 00:00:00 2001
From: th
Date: Sat, 11 Apr 2026 23:40:26 +0200
Subject: [PATCH] relay: burger menu for mobile, admin reachable, badge matches
header buttons
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The relay's nav row used to flatten on mobile by hiding admin / user
identity / compose buttons outright, leaving only "account" + "logout".
Admin was completely unreachable from a phone. Replaces that with a
proper burger menu and exposes every nav target.
* layout.php: new with a ph-list icon between
the spacer and #nav-buttons. Inline `style="display:flex"` removed
from #nav-buttons — display is now CSS-driven, so the burger
popover and the desktop row don't fight each other.
* app.js showView(): the mobile-block on `name === 'admin'` is gone.
Burger button visibility is now mirrored against the same
setup/login/change-password gating that hides #nav-buttons. Picking
any view also clears `.menu-open` so the popover collapses behind
the freshly-shown view.
* app.js toggleNavMenu(): exposed on window for the inline onclick.
Document-level click outside closes the menu.
* style.css: default `#nav-buttons:not(.hidden)` becomes flex (same
semantics as the old inline). #nav-burger is `display:none` on
desktop, `inline-flex` on mobile. Mobile media query drops the old
display:none rules for #nav-admin / #view-admin / #nav-compose,
keeps #nav-user hidden (redundant with the menu), and adds a
`.menu-open` rule that turns #nav-buttons into a popover anchored
to the header (position:absolute, right:12px, surface bg, border,
shadow, z-index 50). Buttons inside the popover go full-width
left-aligned. header { position:relative } so the absolute
positioning has an anchor.
* style.css: also #view-admin .section gets a simple display:block
override on mobile so the desktop grid-area layout doesn't break
the page when admin is opened from a phone.
header .user .badge sizing (carried over from the previous turn): the
admin badge in the relay header now matches the .nav-btn box-model
exactly (5px 10px padding, 9px font, 1px border, 3px radius, line-
height:1, pixel font), so it sits flush with the nav buttons instead
of being a tiny pill in the middle of the row.
chore: bump version to 0.9.8
Co-Authored-By: Claude Opus 4.6 (1M context)
---
config.php | 2 +-
relay/ui/app.js | 26 +++++++++++++++++----
relay/ui/layout.php | 3 ++-
relay/ui/style.css | 57 +++++++++++++++++++++++++++++++++++++++++----
4 files changed, 76 insertions(+), 12 deletions(-)
diff --git a/config.php b/config.php
index 33042c8..23304c5 100644
--- a/config.php
+++ b/config.php
@@ -1,7 +1,7 @@
{
$('view-' + v)?.classList.add('hidden');
});
@@ -40,13 +36,17 @@ function showView(name) {
if (['compose', 'account', 'admin'].includes(name)) {
$('nav-buttons').classList.remove('hidden');
- $('nav-buttons').style.display = 'flex';
$('nav-compose').classList.toggle('active', name === 'compose');
$('nav-account').classList.toggle('active', name === 'account');
$('nav-admin').classList.toggle('active', name === 'admin');
+ $('nav-burger')?.classList.remove('hidden');
+ // Picking a view also collapses the mobile menu so it doesn't
+ // hover over the freshly-shown view.
+ $('nav-buttons').classList.remove('menu-open');
} else {
// Setup, login, and forced change-password hide all nav
$('nav-buttons').classList.add('hidden');
+ $('nav-burger')?.classList.add('hidden');
}
if (name === 'compose') {
@@ -63,6 +63,22 @@ function showView(name) {
}
}
+/** Burger toggle for the mobile nav. The button is hidden on desktop
+ * via CSS, on mobile it expands #nav-buttons as a dropdown panel
+ * positioned under the header. */
+function toggleNavMenu() {
+ $('nav-buttons')?.classList.toggle('menu-open');
+}
+window.toggleNavMenu = toggleNavMenu;
+// Tap outside the menu closes it
+document.addEventListener('click', (e) => {
+ const nav = $('nav-buttons');
+ const burger = $('nav-burger');
+ if (!nav?.classList.contains('menu-open')) return;
+ if (nav.contains(e.target) || burger?.contains(e.target)) return;
+ nav.classList.remove('menu-open');
+});
+
async function doChangePassword() {
const current = $('cp-current').value;
const newPw = $('cp-new').value;
diff --git a/relay/ui/layout.php b/relay/ui/layout.php
index ab3997d..d273261 100644
--- a/relay/ui/layout.php
+++ b/relay/ui/layout.php
@@ -17,7 +17,8 @@ if (!defined('RELAY_BOOTSTRAPPED')) { http_response_code(404); exit; }
hyprcrd relay
-