mobile: proper nav menu with backdrop + full-width targets (0.70.0)

- the mobile hamburger menu was a cramped narrow corner dropdown with no
  backdrop and no tap-to-close
- now a full-width panel (left+right anchored), comfortable full-width touch
  targets, a dimming tap-to-close backdrop, rounded card + shadow, fade-in
- verified live (390px): backdrop present, menu ~374px wide, tap-to-close works
This commit is contained in:
artheru 2026-06-10 09:32:50 +08:00
parent 344a3f7bb2
commit 6d54d89a0b
4 changed files with 11 additions and 7 deletions

View File

@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#0e0a14" /> <meta name="theme-color" content="#0e0a14" />
<meta name="description" content="amerc is the agent mercenary tavern — hire, run, publish, and remotely deliver AI agents across software boundaries. No infrastructure, just skills." /> <meta name="description" content="amerc is the agent mercenary tavern — hire, run, publish, and remotely deliver AI agents across software boundaries. No infrastructure, just skills." />
<meta name="version" content="0.69.0-preload" /> <meta name="version" content="0.70.0-mobilemenu" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" /> <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="icon" href="/app-192.png" type="image/png" sizes="192x192" /> <link rel="icon" href="/app-192.png" type="image/png" sizes="192x192" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" /> <link rel="apple-touch-icon" href="/apple-touch-icon.png" />

View File

@ -1,6 +1,6 @@
{ {
"name": "amerc-site", "name": "amerc-site",
"version": "0.69.0-preload", "version": "0.70.0-mobilemenu",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {

View File

@ -7,7 +7,7 @@ import Account from './Account.jsx';
import TavernGame from './TavernGame.jsx'; import TavernGame from './TavernGame.jsx';
import { api } from './api.js'; import { api } from './api.js';
const RELEASE = '0.69.0-preload'; const RELEASE = '0.70.0-mobilemenu';
const NAV = [ const NAV = [
{ id: 'home', label: 'Tavern' }, { id: 'home', label: 'Tavern' },
@ -66,7 +66,7 @@ function PixelTopbar({ route, setRoute, auth }) {
<button className="px-ver" onClick={() => go('changelog')} type="button" title="What's new — changelog">v{RELEASE}</button> <button className="px-ver" onClick={() => go('changelog')} type="button" title="What's new — changelog">v{RELEASE}</button>
<nav className="px-nav" aria-label="Primary">{nav}</nav> <nav className="px-nav" aria-label="Primary">{nav}</nav>
<button className="px-menu" onClick={() => setOpen((v) => !v)} type="button" aria-label="Toggle menu">{open ? <X size={20} /> : <Menu size={20} />}</button> <button className="px-menu" onClick={() => setOpen((v) => !v)} type="button" aria-label="Toggle menu">{open ? <X size={20} /> : <Menu size={20} />}</button>
{open && <div className="px-mobile">{nav}</div>} {open && <><div className="px-mobile-backdrop" onClick={() => setOpen(false)} aria-hidden="true" /><div className="px-mobile">{nav}</div></>}
</header> </header>
); );
} }

View File

@ -714,11 +714,15 @@ button {
@media (max-width: 760px) { @media (max-width: 760px) {
.px-nav { display: none; } .px-nav { display: none; }
.px-menu { display: inline-flex; } .px-menu { display: inline-flex; }
.px-mobile-backdrop { position: fixed; inset: 0; background: rgba(8,4,10,0.55); z-index: 49; animation: px-fade .15s ease-out; }
@keyframes px-fade { from { opacity: 0; } to { opacity: 1; } }
.px-mobile { .px-mobile {
display: flex; flex-direction: column; gap: 6px; display: flex; flex-direction: column; gap: 7px;
position: absolute; top: 100%; right: 8px; position: absolute; top: calc(100% + 4px); right: 8px; left: 8px;
padding: 8px; background: #1a0d05; border: 3px solid #000; z-index: 50; padding: 10px; background: #160d05; border: 3px solid #000; border-radius: 12px; z-index: 50;
box-shadow: 0 14px 34px rgba(0,0,0,0.6); animation: px-fade .15s ease-out;
} }
.px-mobile .px-nav-btn { width: 100%; text-align: center; padding: 12px 10px; font-size: 9px; }
.px-board { left: 50%; transform: translate(-50%, 0); top: auto; bottom: 12px; width: min(94vw, 420px); } .px-board { left: 50%; transform: translate(-50%, 0); top: auto; bottom: 12px; width: min(94vw, 420px); }
@keyframes px-board-in { from { opacity: 0; } to { opacity: 1; } } @keyframes px-board-in { from { opacity: 0; } to { opacity: 1; } }
.px-char img { height: auto; } .px-char img { height: auto; }