Replace the mobile tab bar with a hamburger menu

Six tabs (Queue, On-call, Alerts, Team, Admin, Account) had already
outgrown the bottom bar once: 56b8191 let it auto-size its columns to
fit however many there were, but on a phone that only left each tab
55-65px wide. Squeezing further wasn't an option, so the bar is gone
on mobile and a hamburger button in the topbar opens a menu instead.

The menu reuses the sheet + menu-item pattern already used for the
snooze and assign-to actions in incident.js, rather than a new overlay
component. It lists the same sections the sidebar does, including
hiding Admin for non-admins, and the triggered-incident badge that
used to sit on the Queue tab icon now shows on the hamburger button.

Desktop (>=900px) is untouched: the sidebar is the same markup, CSS
alone hides it below 900px and shows it above, so nothing there
changed behaviourally.

Claude-Session: https://claude.ai/code/session_01RHPj4ggeFdEjKKfm4SHbD7
This commit is contained in:
Niklas Ye
2026-09-22 21:47:15 +02:00
parent 429d5fdda3
commit e536fdd2c0
5 changed files with 86 additions and 29 deletions
+16 -21
View File
@@ -48,7 +48,11 @@
--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
--topbar-h: 52px;
--tabbar-h: 58px;
/* No bottom tab bar on any breakpoint any more — mobile uses the hamburger
menu in the topbar, desktop the sidebar — so this stays 0. Kept as a
variable rather than deleted since .view, .toast and .nav's own height
calc still read it. */
--tabbar-h: 0px;
--safe-top: env(safe-area-inset-top, 0px);
--safe-bottom: env(safe-area-inset-bottom, 0px);
}
@@ -196,7 +200,13 @@ input:focus, textarea:focus { outline: none; border-color: var(--accent); box-sh
-webkit-backdrop-filter: saturate(1.4) blur(12px);
border-bottom: 1px solid var(--border);
}
.topbar-title { font-size: 18px; font-weight: 700; letter-spacing: -0.01em; }
.topbar-left { display: flex; align-items: center; gap: 8px; min-width: 0; }
.topbar-title {
font-size: 18px; font-weight: 700; letter-spacing: -0.01em;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
#menu-btn { position: relative; }
.nav-badge.menu-btn-badge { top: 2px; left: auto; right: 2px; }
.open-pill {
display: inline-flex; align-items: center; gap: 6px;
@@ -209,15 +219,12 @@ input:focus, textarea:focus { outline: none; border-color: var(--accent); box-sh
.open-pill.has-triggered::before { background: var(--crit); }
.open-pill.all-acked::before { background: var(--warn); }
/* Bottom tab bar on phones. */
/* Hidden on phones — mobile navigates through the hamburger menu in the
topbar instead (see #menu-btn / openNavMenu in app.js). Reappears as the
left sidebar from 900px, where the desktop block below redeclares display. */
.nav {
display: none;
position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
/* One column per link, however many there are. This was repeat(4, 1fr) when
there were four tabs; Team and Admin arriving pushed six items into four
columns, which on a phone is how they stopped fitting. Auto columns mean
the next tab cannot break the row either — and Admin is only rendered for
an administrator, so the count genuinely varies between viewers. */
display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
height: calc(var(--tabbar-h) + var(--safe-bottom));
padding-bottom: var(--safe-bottom);
background: color-mix(in srgb, var(--surface) 92%, transparent);
@@ -239,16 +246,6 @@ input:focus, textarea:focus { outline: none; border-color: var(--accent); box-sh
}
.nav-link svg { width: 24px; height: 24px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
/* Narrow phones, where six tabs each get about 55-65px. Tightening is enough:
the widest label, "On-call", is about 38px at this size, so nothing has to
be hidden. The ellipsis above is the backstop if a future tab is named
something longer. */
@media (max-width: 420px) {
.nav-link { font-size: 10px; gap: 1px; }
.nav-link svg { width: 21px; height: 21px; }
.nav-badge { left: calc(50% + 4px); min-width: 16px; height: 16px; font-size: 10px; line-height: 16px; }
}
.nav-link[aria-current="page"] { color: var(--accent); }
.nav-badge {
position: absolute; top: 6px; left: calc(50% + 6px);
@@ -601,8 +598,6 @@ kbd {
/* ---------- desktop ---------- */
@media (min-width: 900px) {
:root { --tabbar-h: 0px; }
.app { display: grid; grid-template-columns: 220px 1fr; height: 100dvh; }
.nav {