add sandwich nav

This commit is contained in:
Bartal Læarsson
2026-06-22 13:29:26 +01:00
parent 9323d6e9c3
commit 74c28c4f35
2 changed files with 115 additions and 3 deletions
+83 -2
View File
@@ -109,9 +109,9 @@ input, select, textarea { max-width: 100%; }
header {
border-bottom: 1px solid var(--header-border);
padding: 1rem 1.5rem;
display: flex;
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: 1.2rem;
background: var(--nav-bg);
backdrop-filter: blur(12px) saturate(120%);
-webkit-backdrop-filter: blur(12px) saturate(120%);
@@ -120,6 +120,8 @@ header {
z-index: 20;
transition: background 0.3s ease;
}
.brand { justify-self: center; }
nav { justify-self: end; }
.back-link {
font-family: 'JetBrains Mono', monospace;
@@ -479,6 +481,83 @@ details.confirm[open]::before {
}
.theme-toggle:hover { transform: scale(1.08); }
/* ── Hamburger (hidden on desktop) ── */
.nav-hamburger {
display: none; /* shown only at ≤640px */
flex-direction: column;
gap: 4px;
background: none;
border: none;
cursor: pointer;
padding: 6px;
justify-self: end;
}
.nav-hamburger span {
display: block;
width: 20px;
height: 1.5px;
background: var(--muted);
transition: background 0.2s;
}
.nav-hamburger:hover span { background: var(--fg); }
/* ── Off-canvas overlay ── */
.nav-overlay {
position: fixed; inset: 0;
background: rgba(0,0,0,0.4);
z-index: 49;
opacity: 0; pointer-events: none;
transition: opacity 0.3s;
}
.nav-overlay.open { opacity: 1; pointer-events: auto; }
/* ── Off-canvas panel ── */
.nav-offcanvas {
position: fixed; top: 0; right: 0;
width: 100vw; height: 100vh;
background: var(--bg);
z-index: 50;
transform: translateX(100%);
transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
display: flex; flex-direction: column;
padding: calc(60px + 2rem) 2rem 2rem;
overflow-y: auto;
}
.nav-offcanvas.open { transform: translateX(0); }
.offcanvas-header {
position: absolute; top: 0; left: 0; right: 0;
height: 60px;
display: flex; align-items: center; justify-content: space-between;
padding: 0 1.25rem;
border-bottom: 1px solid var(--border);
}
.nav-close {
background: none; border: none;
font-size: 1.3rem; color: var(--muted);
cursor: pointer; padding: 0.5rem;
font-family: 'JetBrains Mono', monospace;
}
.nav-close:hover { color: var(--fg); }
.offcanvas-links {
display: flex; flex-direction: column;
gap: 0.15rem; width: 100%;
}
.offcanvas-links a {
font-family: 'JetBrains Mono', monospace;
font-size: 1.05rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--muted);
text-decoration: none;
padding: 0.75rem 0;
border-bottom: 1px solid var(--border);
transition: color 0.2s;
}
.offcanvas-links a:first-child { border-top: 1px solid var(--border); }
.offcanvas-links a:hover { color: var(--fg); padding-left: 0.5rem; }
@media (max-width: 640px) {
header { padding: 0.7rem 0.9rem; gap: 0.6rem; }
.back-link { font-size: 0.58rem; padding: 0.25rem 0.4rem; letter-spacing: 0.08em; }
@@ -489,4 +568,6 @@ details.confirm[open]::before {
.theme-toggle { width: 20px; height: 20px; bottom: 1rem; right: 0.9rem; }
.reset-banner { top: 44px; }
.running-bar { top: 44px; }
.nav-desktop { display: none; }
.nav-hamburger { display: flex; }
}
+32 -1
View File
@@ -19,16 +19,34 @@
<link rel="stylesheet" href="/static/app.css">
</head>
<body>
<header>
<a href="https://fló.fo" class="back-link">← FLÓ.FO</a>
<span class="brand">FLÓ <span class="brand-sep">/</span> <span class="brand-sub">ZEITKORT</span></span>
<nav>
<nav class="nav-desktop">
<a href="/">Timer</a>
<a hx-get="/settings" hx-target="#main" href="javascript:void(0)">Settings</a>
<a hx-get="/about" hx-target="#main" href="javascript:void(0)">About</a>
</nav>
<button id="nav-hamburger" class="nav-hamburger" aria-label="Open menu">
<span></span><span></span><span></span>
</button>
</header>
<!-- Off-canvas mobile menu -->
<div id="nav-overlay" class="nav-overlay"></div>
<div id="nav-offcanvas" class="nav-offcanvas">
<div class="offcanvas-header">
<span class="brand">FLÓ <span class="brand-sep">/</span> <span class="brand-sub">ZEITKORT</span></span>
<button id="nav-close" class="nav-close" aria-label="Close menu">&#x2715;</button>
</div>
<div class="offcanvas-links">
<a href="/">Timer</a>
<a hx-get="/settings" hx-target="#main" href="javascript:void(0)">Settings</a>
<a hx-get="/about" hx-target="#main" href="javascript:void(0)">About</a>
</div>
</div>
<div class="reset-banner" role="status" aria-live="polite">
<span class="reset-label">POC reset in</span>
<span id="reset-countdown" class="reset-countdown" data-reset-at="{{rfc3339 .ResetAt}}">--:--</span>
@@ -70,6 +88,19 @@
}
});
})();
(function () {
var overlay = document.getElementById('nav-overlay');
var panel = document.getElementById('nav-offcanvas');
var openBtn = document.getElementById('nav-hamburger');
var closeBtn = document.getElementById('nav-close');
function open() { panel.classList.add('open'); overlay.classList.add('open'); }
function close() { panel.classList.remove('open'); overlay.classList.remove('open'); }
if (openBtn) openBtn.addEventListener('click', open);
if (closeBtn) closeBtn.addEventListener('click', close);
if (overlay) overlay.addEventListener('click', close);
panel.querySelectorAll('a').forEach(function(a) { a.addEventListener('click', close); });
})();
</script>
</body>
</html>{{end}}