Commit Graph
3 Commits
Author SHA1 Message Date
logan 1ab767a317 feat(shell): take the top bar out of the phone's layout
The row is deleted from the grid template below 600px, not the header
hidden. That is 3.25em of a 439 CSS px viewport -- the single biggest
vertical win the reference device has to give, and the reason the issue
asks for the row rather than for a smaller bar.

Each of the five things the bar held has somewhere else to be there:
nav-history is the platform's own back gesture and was already gone from
899 down, the job indicator is <job-band> (#62, which is what this was
blocked on), the search box is a modal opened from the view's own
header, the library filter is Settings -> Libraries, and the wordmark
stays where it is.

Three things are load-bearing.

**The header is visually hidden rather than display: none**, because
that h1 is the document's top-level heading and several pages have no
other one -- page-header renders no h1 when its heading is empty, and
Settings has no page-header at all. Its four controls are display: none
*inside* it, which is what keeps them out of the tab order: a
visually-hidden container is still focusable, and tabbing into a search
box nobody can see is worse than not having one.

**The fit pass stands down**, from the bar's computed position rather
than from a width. With the bar out of flow there is no content box to
measure children against, and a pass that ran would collapse the
wordmark on every resize and report success about a 1px box.

**top-bar-fit.spec.ts keeps 390 and asserts the stronger property.**
"Nothing hangs out of the bar" is trivially true of a bar with no row
and would pass on a build that merely broke it, so what that width asks
now is that the content starts where the row above it ends. Measuring
against the window instead would have been asserting "and no background
job is running", which that spec is not about and cannot arrange.

Closes #57
2026-08-20 20:03:20 -04:00
logan 23f5a0c53a feat(shell): show background jobs in the phone's layout, not a popover
The header indicator is a disclosure anchored to a bar 3.25em tall on a
screen 439 CSS px tall, and it was reported as unreadable behind other
UI. Background work is the one thing a phone should not make you open
something to see, and #57 deletes the bar it hangs from and is blocked
on it having somewhere else to live. Below 600px the indicator stands
down and <job-band> takes over.

It is the existing job-panel at `kinds="*"`, so pause, cancel, Details
and the log come along, and so does applyJobControl.

**It is in the layout, not over it**, and that was measured rather than
assumed. The first version put the panel in notification-host's fixed
band: it renders correctly, sits on top and stays inside the viewport,
and is unusable -- at 424x439 a compact panel showing two jobs is
~216px of a 439px screen, drawn over the content and swallowing every
tap under it. Four e2e specs caught it, and none of them was about
jobs: two phone-shell journeys and the header's action menu, all
failing on clicks the band was intercepting. As a grid row above the
main panel it pushes instead, which is #24's one sentence deciding a
layout question -- a band that hides the app to say the app is busy has
traded the popover's fault for a worse one.

It renders nothing above 600px, from matchMedia rather than a media
query, because that decides whether the element exists: Settings
already holds four job-panels and a fifth answering for every kind is
bottom-nav's "resolved to 2 elements" trap again. index.css keeps it
display:none off the phone for a second reason -- an in-flow grid child
with no named area is auto-placed into one of the shell's rows, which
is what the skip link is absolutely positioned to avoid.

top-bar-fit's 390px case asserted the indicator was up, so that it
could not pass by measuring the idle case under another name. At phone
width it is now deliberately away, so the assertion takes the other
branch of the same rule -- the indicator is hidden, the band has the
row, and the bar still has nothing hanging out of it -- rather than
the width being quietly dropped from the list.

The report's own symptom is deliberately not asserted anywhere: it did
not reproduce in this tier. Measured at 424x439 the popover was neither
clipped nor covered, so a spec claiming a stacking fix would be
asserting something that was never true here. The spec says so.

Closes #62
2026-08-20 18:17:35 -04:00
logan ae85df0dad fix(shell): give the top bar a measured fit at every width
The bar was 611px inside a 600px viewport at the bottom of the Compact
band, and 862px while a scan with a real library's title ran, because
`job-indicator` is `hidden` when idle and 235px wide when it is not.
`body` is `overflow-x: auto`, so a user got a horizontal scrollbar on a
shell #24 promised would not need one — and the band is 600 to 899 with
work in flight, not the 600 to 610 the idle measurement suggested.

`services/top-bar-fit.ts` is `page-header`'s treatment one bar up: a
ResizeObserver, every pass starting from all-visible, hiding the
lowest-priority child until it fits. Measured rather than breakpointed
because three of the five children are as wide as their content — the
library filter by the longest library name, the indicator by the
running job's title, the search box by its view-scoped placeholder — so
any width picked is right for one library, one job and one view.

What yields is decided by #24's own sentence, which rules out the two
cheapest candidates in the Direction. Hiding the library filter takes
away an action, since it is the only control in the app that selects a
library (filed as #148, which is the phone already doing it), and
collapsing search to an icon is #57's, which is blocked behind #62. So
the wordmark yields first — a brand the window title bar repeats, and
visually-hidden rather than `display: none` because that h1 is the
document's heading — and then the indicator's label, leaving the ring,
which the component already does below 600px and whose live region
announces the state either way.

"Fits" is the children against the content box, not `scrollWidth`
against `clientWidth`: `scrollWidth` counts the left padding and not
the right, so the first version read 700/700 with the indicator sitting
in the whole right gutter. And the bar does not resize when a job
starts, which is the case this is for, so every child is observed too.

Pinned before it was fixed, as the issue asks. On the unfixed build the
new spec fails at 600 idle and at 600, 800 and 900 with a job, and
passes at 390, 899 and 1440; `layout-overflow.spec.ts` gains 600x600
and failed there. That spec asserts on the *shell*, so it was green
throughout this defect — the per-child measurement is #69's lesson, and
it is what caught the gutter case above.

Closes #143
2026-08-19 21:35:03 -04:00