fix: mobile fixed nav bar and detail page polish

- Make nav bar fixed on mobile with safe-area-inset-top support for
  notched devices (10% reduction) and 1rem minimum for non-notched
- Adjust timeline sticky month headings to sit flush below the fixed
  nav with matching top/bottom padding
- Update IntersectionObserver rootMargin to account for fixed nav height
  so stuck-state accent border triggers correctly
- Increase main content top padding on mobile for balanced spacing on
  detail pages
- Add remaining field to bag edit form with +/- stepper buttons
- Make admin page passkey/token forms responsive with icon-only mobile
  delete/revoke buttons
- Make detail page action buttons stack vertically on mobile with equal
  width
This commit is contained in:
Jon Seager 2026-02-11 09:53:43 +00:00
parent 705144bcf7
commit 049e9d68a8
No known key found for this signature in database
4 changed files with 45 additions and 4 deletions

View file

@ -213,6 +213,32 @@ input.input-field[type="number"] {
background-color: var(--accent-subtle); background-color: var(--accent-subtle);
} }
/* ── Mobile fixed nav ─────────────────────────────────────────── */
@media (max-width: 767px) {
:root {
--fixed-nav-h: calc(
max(1rem, env(safe-area-inset-top, 0px) * 0.9) + 3.25rem
);
}
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 30;
background-color: var(--page);
padding-top: max(1rem, calc(env(safe-area-inset-top, 0px) * 0.9));
padding-left: 1.5rem;
padding-right: 1.5rem;
}
main {
padding-top: calc(var(--fixed-nav-h) + 2rem);
}
}
/* ── Sticky Submit ────────────────────────────────────────────── */ /* ── Sticky Submit ────────────────────────────────────────────── */
.sticky-submit { .sticky-submit {
@ -502,6 +528,12 @@ input.input-field[type="number"] {
.timeline-item { .timeline-item {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
/* Stick below fixed nav; 0.5rem tucks behind nav, 1rem visible = matches bottom */
.timeline-heading {
top: calc(var(--fixed-nav-h) - 0.5rem);
padding-top: 1.5rem;
}
} }
/* ── Data page ─────────────────────────────────────────────────── */ /* ── Data page ─────────────────────────────────────────────────── */

View file

@ -2,7 +2,10 @@
<html lang="en" data-star-root> <html lang="en" data-star-root>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta
name="viewport"
content="width=device-width, initial-scale=1, viewport-fit=cover"
/>
<meta <meta
name="description" name="description"
content="{% block description %} content="{% block description %}
@ -181,7 +184,7 @@
</head> </head>
<body class="min-h-screen bg-page text-text"> <body class="min-h-screen bg-page text-text">
<main <main
class="mx-auto flex w-full max-w-5xl flex-col gap-8 px-6 py-4 md:py-10" class="mx-auto flex w-full max-w-5xl flex-col gap-8 px-6 pb-4 md:py-10"
> >
{% include "partials/nav.html" %} {% block content %}{% endblock %} {% include "partials/nav.html" %} {% block content %}{% endblock %}
<footer <footer

View file

@ -208,13 +208,19 @@
} }
// Sticky header detection - observe all current and future headings // Sticky header detection - observe all current and future headings
// On mobile the nav is fixed, so shrink the observer root by its height
const navBar = document.querySelector(".nav-bar");
const navH =
navBar && matchMedia("(max-width: 767px)").matches
? navBar.getBoundingClientRect().height
: 0;
const stickyObserver = new IntersectionObserver( const stickyObserver = new IntersectionObserver(
(entries) => { (entries) => {
entries.forEach((entry) => { entries.forEach((entry) => {
entry.target.classList.toggle("is-stuck", !entry.isIntersecting); entry.target.classList.toggle("is-stuck", !entry.isIntersecting);
}); });
}, },
{ rootMargin: "-1px 0px 0px 0px", threshold: 1 }, { rootMargin: `-${navH + 1}px 0px 0px 0px`, threshold: 1 },
); );
// Use MutationObserver to watch for new month headings being added // Use MutationObserver to watch for new month headings being added

View file

@ -1,5 +1,5 @@
{% import "partials/icons.html" as icons %} {% import "partials/icons.html" as icons %}
<nav class="border-b pb-4 text-sm"> <nav class="nav-bar border-b pb-4 text-sm">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div class="font-semibold uppercase tracking-[0.25em] text-accent"> <div class="font-semibold uppercase tracking-[0.25em] text-accent">
<a href="/" class="-m-2 inline-block p-2">B{rew}log</a> <a href="/" class="-m-2 inline-block p-2">B{rew}log</a>