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:
parent
705144bcf7
commit
049e9d68a8
4 changed files with 45 additions and 4 deletions
|
|
@ -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 ─────────────────────────────────────────────────── */
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue