Let the tab bar fit however many tabs there are
The bottom tab bar was grid-template-columns: repeat(4, 1fr), written when there were four tabs. Team and Admin arrived in the last two releases and nothing updated that number, so six items were being laid into four columns -- which on a phone is the reported symptom, tabs that do not fit the width. grid-auto-flow: column with grid-auto-columns: 1fr makes the count follow the markup instead. That also handles a case a fixed number cannot: Admin is only rendered for an administrator, so the tab count genuinely differs between two people looking at the same install. Then the compactness. Each link gets min-width: 0 so a column may shrink below its label's natural width, and the label itself ellipsises rather than widening the bar. Under 420px the font drops to 10px, the icons to 21px and the badge shrinks to match. No icon-only breakpoint. The arithmetic says the labels fit: six tabs on a 320px phone give about 53px each, and the widest label, "On-call", is about 38px at 10px. A media query that never fires is dead code, and the ellipsis is the backstop if a future tab is named something longer. The links gained aria-labels regardless. The icons are aria-hidden, so the visible text was the accessible name, and it should not be the only one. The desktop sidebar is unaffected: it overrides display, padding and font-size itself, so none of the phone rules reach it. Not verified on a phone -- I cannot open a browser here, so this is the cause identified from the CSS and the widths worked out on paper. Claude-Session: https://claude.ai/code/session_01RHPj4ggeFdEjKKfm4SHbD7
This commit is contained in:
@@ -199,7 +199,12 @@ input:focus, textarea:focus { outline: none; border-color: var(--accent); box-sh
|
|||||||
/* Bottom tab bar on phones. */
|
/* Bottom tab bar on phones. */
|
||||||
.nav {
|
.nav {
|
||||||
position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
|
position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
|
||||||
display: grid; grid-template-columns: repeat(4, 1fr);
|
/* 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));
|
height: calc(var(--tabbar-h) + var(--safe-bottom));
|
||||||
padding-bottom: var(--safe-bottom);
|
padding-bottom: var(--safe-bottom);
|
||||||
background: color-mix(in srgb, var(--surface) 92%, transparent);
|
background: color-mix(in srgb, var(--surface) 92%, transparent);
|
||||||
@@ -212,8 +217,25 @@ input:focus, textarea:focus { outline: none; border-color: var(--accent); box-sh
|
|||||||
position: relative;
|
position: relative;
|
||||||
display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
|
display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
|
||||||
color: var(--faint); font-size: 11px; font-weight: 600;
|
color: var(--faint); font-size: 11px; font-weight: 600;
|
||||||
|
/* min-width lets a column shrink below its label's natural width, which is
|
||||||
|
what stops six tabs widening the bar past the screen. */
|
||||||
|
min-width: 0; padding: 0 2px;
|
||||||
}
|
}
|
||||||
.nav-link svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
|
.nav-label {
|
||||||
|
max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||||
|
}
|
||||||
|
.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-link[aria-current="page"] { color: var(--accent); }
|
||||||
.nav-badge {
|
.nav-badge {
|
||||||
position: absolute; top: 6px; left: calc(50% + 6px);
|
position: absolute; top: 6px; left: calc(50% + 6px);
|
||||||
|
|||||||
@@ -77,31 +77,31 @@
|
|||||||
<img src="/icon.svg" alt="" width="28" height="28">
|
<img src="/icon.svg" alt="" width="28" height="28">
|
||||||
<span>terdut</span>
|
<span>terdut</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="nav-link" href="/" data-section="queue">
|
<a class="nav-link" href="/" data-section="queue" aria-label="Queue">
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/></svg>
|
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/></svg>
|
||||||
<span class="nav-label">Queue</span>
|
<span class="nav-label">Queue</span>
|
||||||
<span class="nav-badge" data-badge hidden></span>
|
<span class="nav-badge" data-badge hidden></span>
|
||||||
</a>
|
</a>
|
||||||
<a class="nav-link" href="/oncall" data-section="oncall">
|
<a class="nav-link" href="/oncall" data-section="oncall" aria-label="On-call">
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="5" width="17" height="15" rx="2"/><path d="M3.5 10h17M8 3v4M16 3v4"/></svg>
|
<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="5" width="17" height="15" rx="2"/><path d="M3.5 10h17M8 3v4M16 3v4"/></svg>
|
||||||
<span class="nav-label">On-call</span>
|
<span class="nav-label">On-call</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="nav-link" href="/alerts" data-section="alerts">
|
<a class="nav-link" href="/alerts" data-section="alerts" aria-label="Alerts">
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15z"/><path d="M10 20.5a2 2 0 0 0 4 0"/></svg>
|
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15z"/><path d="M10 20.5a2 2 0 0 0 4 0"/></svg>
|
||||||
<span class="nav-label">Alerts</span>
|
<span class="nav-label">Alerts</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="nav-link" href="/team" data-section="team">
|
<a class="nav-link" href="/team" data-section="team" aria-label="Team">
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="9" cy="8" r="3"/><circle cx="17" cy="9" r="2.5"/><path d="M3 19a6 6 0 0 1 12 0M15 19a5 5 0 0 1 6-4"/></svg>
|
<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="9" cy="8" r="3"/><circle cx="17" cy="9" r="2.5"/><path d="M3 19a6 6 0 0 1 12 0M15 19a5 5 0 0 1 6-4"/></svg>
|
||||||
<span class="nav-label">Team</span>
|
<span class="nav-label">Team</span>
|
||||||
</a>
|
</a>
|
||||||
<!-- Hidden unless the signed-in user is a system administrator; app.js
|
<!-- Hidden unless the signed-in user is a system administrator; app.js
|
||||||
unhides it once /api/me says so. The server refuses every admin
|
unhides it once /api/me says so. The server refuses every admin
|
||||||
endpoint regardless, so this is a courtesy and not a gate. -->
|
endpoint regardless, so this is a courtesy and not a gate. -->
|
||||||
<a class="nav-link" href="/admin" data-section="admin" id="nav-admin" hidden>
|
<a class="nav-link" href="/admin" data-section="admin" aria-label="Admin" id="nav-admin" hidden>
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3l7 3v6c0 4-3 7-7 9-4-2-7-5-7-9V6z"/></svg>
|
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3l7 3v6c0 4-3 7-7 9-4-2-7-5-7-9V6z"/></svg>
|
||||||
<span class="nav-label">Admin</span>
|
<span class="nav-label">Admin</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="nav-link" href="/more" data-section="more">
|
<a class="nav-link" href="/more" data-section="more" aria-label="Account">
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg>
|
<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg>
|
||||||
<span class="nav-label">Account</span>
|
<span class="nav-label">Account</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
Reference in New Issue
Block a user