Compare commits

..

3 Commits

Author SHA1 Message Date
Niklas Ye 8869ac864f Set the chart's placeholder version to 0.15.1
CI / test (push) Successful in 4s
CI / chart (push) Successful in 1s
CI / security (push) Successful in 10s
Release / test (push) Successful in 4s
Release / chart (push) Successful in 2s
Release / binaries (push) Successful in 22s
Release / image (push) Successful in 56s
Release / scan-image (push) Successful in 3s
Cosmetic, as in 4c85e76 and 041e159. `make helm-package` passes --version
and --app-version from the tag, so neither field decides anything about
what release.yaml publishes.

Done anyway because a tree heading for v0.15.1 that still says 0.15.0
tells a reader something false. appVersion keeps the v, per
APPVERSION_PREFIX in .release.conf.
2026-09-21 11:23:56 +02:00
niklas 0677e74cf8 Merge pull request 'Let the tab bar fit however many tabs there are' (#21) from compact-nav into main
CI / chart (push) Successful in 1s
CI / test (push) Successful in 6s
CI / security (push) Successful in 12s
Reviewed-on: #21
2026-09-21 09:23:31 +00:00
Niklas Ye 56b8191a78 Let the tab bar fit however many tabs there are
CI / chart (pull_request) Successful in 2s
CI / security (pull_request) Successful in 17s
CI / test (pull_request) Successful in 2m33s
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
2026-09-21 11:18:30 +02:00
3 changed files with 32 additions and 10 deletions
+2 -2
View File
@@ -15,5 +15,5 @@ type: application
# appVersion and image.tag in values.yaml no longer agree, and that is not an oversight:
# image.tag stays "latest", which is what a local install actually pulls. appVersion is
# metadata and drives nothing.
version: 0.15.0
appVersion: "v0.15.0"
version: 0.15.1
appVersion: "v0.15.1"
+24 -2
View File
@@ -199,7 +199,12 @@ input:focus, textarea:focus { outline: none; border-color: var(--accent); box-sh
/* Bottom tab bar on phones. */
.nav {
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));
padding-bottom: var(--safe-bottom);
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;
display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
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-badge {
position: absolute; top: 6px; left: calc(50% + 6px);
+6 -6
View File
@@ -77,31 +77,31 @@
<img src="/icon.svg" alt="" width="28" height="28">
<span>terdut</span>
</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>
<span class="nav-label">Queue</span>
<span class="nav-badge" data-badge hidden></span>
</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>
<span class="nav-label">On-call</span>
</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>
<span class="nav-label">Alerts</span>
</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>
<span class="nav-label">Team</span>
</a>
<!-- Hidden unless the signed-in user is a system administrator; app.js
unhides it once /api/me says so. The server refuses every admin
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>
<span class="nav-label">Admin</span>
</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>
<span class="nav-label">Account</span>
</a>