fix/43-queue-panel-selection
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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 |
||
|
|
c79d4d47a3 |
test: cover jobs in Settings, and unpick two shared selectors
The spec worth having is not that the tab is gone -- that is one line of a table -- but that nothing became unreachable when it went. #24 promises that no action is ever unreachable at any supported size, and deleting a destination is exactly the change that quietly breaks it. Two existing selectors had to give. `config-section .header` is ambiguous the moment a section holds a job, because `job-details-drawer` carries that class too -- so `settings-reach.spec.ts` locates a disclosure by role and name instead. And `page-header`'s and `offline-icons`'s view lists lose an entry each. Closes #27 |
||
|
|
ede183d026 |
test(shell): check 900x600, which is narrower than the minimum
The sidebar collapses to icons *below* 900, so the main panel is 843px at 899 and 700px at 900: the narrowest content area any desktop width produces is at the top of the Compact band, not at the enforced floor. A viewport list that stopped at "the minimum" was missing its own worst case. MinWidth's comment loses both reasons it used to give, because neither mechanism can happen any more — the subtitle is display:none from 899 down, and the sidebar host is overflow-y:auto (at 600x460 its scrollHeight is 434 against a 332px client, and Settings is reachable after scrolling). The value does not change: 800x600 is where desktop chrome stops being comfortable, not where the app breaks, and below 600 the phone layout takes over. A floor defended by two expired mechanisms is a number nobody can argue with, which is worse than either answer. Closes #24 |
||
|
|
57fbbdf0d2 |
feat(ui): a shell a phone can be held in
Plan 016 B2, phase 1. Below 600px the grid drops its sidebar column, `bottom-nav` becomes the primary navigation, and the shell fits the viewport instead of scrolling sideways out of it. 600 rather than the sidebar's own 900, because 900 is a laptop and the answer there is a narrower sidebar, which is still a sidebar. Under 600 there is no room for one at all: 360px of viewport over a 200px nav is not a layout. **The tab bar is four destinations and a way to everything else.** Three to five is where touch targets stop being thumb-sized -- eleven over 360px is 32px each -- so the four are the ones plan 016's subset says a phone is for, and "More" opens the *existing* `app-sidebar` in a drawer rather than listing the destinations a second time. Two lists is two places to add the next view to. That reuse has a cost this found the hard way: a shared component brings its `data-testid`s with it, so rendering the drawer's sidebar unconditionally put a second `nav-home` (and ten siblings) in the DOM and **failed 30 existing specs** with "resolved to 2 elements" -- on a desktop viewport, where this element is `display: none` and the drawer can never open. It renders only while the drawer is open, and the component test asserts the absence, because the failure is invisible from inside the component and lands in files nobody touched. **What made the shell overflow was minimums, not padding.** Measured at 360px: the body was 652px wide, because a `min-width` in a flex row is a hard floor and a grid item's implicit minimum is its content. So `min-width: 0` on the boxes between the viewport and the content, and each component stands its own non-essential parts down in its *own* stylesheet -- search-bar's 200px floor, job-indicator's label (the visible one; the live region that announces it is untouched), audio-player's seek bar and volume. A media query inside a shadow root is answered by the viewport, so this is the component saying what it drops rather than the shell reaching in. Volume goes because the hardware keys own it on a phone, which is the same reason mediacontrols' Android handler implements no volume callback. Seeking goes because 4px is not a thumb target; it belongs to the full-screen now-playing view, which is the next phase. An existing spec therefore asserts the opposite of what it did: layout-overflow's 320px case used to require that the 464px behind `overflow: hidden` could be *scrolled to*, which was the remedy available while the shell had one layout. It reflows now -- 320px in a 320px viewport, exactly -- and reflow is what WCAG 1.4.10 asked for. |
||
|
|
4efd17d477 |
fix(a11y): let the shell scroll sideways when it does not fit
a11y.21 (WCAG 1.4.10), measured rather than taken as filed. The finding's mechanism is vertical — "the 4em bars grow while the viewport does not, and anything that no longer fits is clipped with no scrollbar" — and that is not what happens. The middle row is `1fr` and absorbs the growth exactly: at 200% text on 800x600 the bars go 64px to 128px and the panel 472px to 344px, with the footer still landing on 600. Nothing is clipped vertically, and Settings stays reachable because the sidebar scrolls (007 phase 5). What is real is the axis the finding does not mention. At 200% text the shell is 1014px wide in an 800px viewport, and at 320px — 400% page zoom of 1280, the width 1.4.10 names — it is 784px, so 464px of the app including the job indicator and the queue button sat behind `overflow: hidden` with no way to reach it. So the horizontal axis scrolls and the vertical one stays fixed, which also keeps the transport where a desktop player's transport belongs. At every size this app promises there is no overflow on either axis and no scrollbar appears, which the three viewport cases assert. The first version of the spec passed on the broken build: `overflow: hidden` still permits programmatic scrolling, so `scrollLeft = 9999` proves nothing. It is a wheel gesture now. |
||
|
|
9d420cda0a |
fix(a11y): add a skip link, demote the subtitle, and size the sort arrow
a11y.30: `<main id="main-content">` existed and nothing linked to it, so a keyboard user walked the library filter, the search box, the job indicator and eleven nav items before reaching content, on every navigation. Two things in it are load-bearing and only checkable against the running document: the link is out of flow in *both* states, because `body` is a grid with named areas and an in-flow extra child is auto-placed into one of them; and `<main>` needs tabindex="-1", or the fragment link moves the scroll, leaves the tab sequence where it was, and looks like it worked. a11y.29: `<h1>` followed by `<h3>` for type size. An `hgroup` takes one heading plus paragraphs, so a `<p>` is also what it was meant to hold. a11y.34: the sort arrow was 10px, below the type scale's own floor, with a comment acknowledging it. Half of that finding was closed by Phase 1 — the direction is announced now, via aria-sort — and the other half is one declaration. And the state that landed in: the hgroup measured 67px inside a 64px bar, so dropping the h3's bottom margin shortened the block, moved the flex-centred pair down, and clipped the subtitle's descenders. The overflow was pre-existing; `margin-block: 0` on the title is the fix, pinned by a new layout-overflow case. |
||
|
|
e9ca16362f |
fix(ui): make the app fit the window it enforces a minimum for
The track list shared out its whole clientWidth across the resizable columns while every row spends 24px on the favourite column and 2x8px on its own padding before the first one starts, so the grid was always exactly 40px wider than the box holding it and the last column was clipped at every size (scrollWidth 1280 vs clientWidth 1240, measured). Both numbers now live in one place and are read by the two call sites that had written them out separately, which is how they came to disagree. The enforced minimum was 512x384, which the layout had never supported: at 700x480 the eleven sidebar items needed 406px of a 352px pane, overflow:hidden cut the last two off with nothing to scroll, and Settings and Jobs could not be reached at all. The pane scrolls now, the sidebar collapses to icons below 900px (its .collapsed mode existed and only a manual drag ever reached it), the subtitle hides at the same breakpoint so the title stops wrapping out of the 4em bar, and the minimum is 800x600 - measured as where the shell still works rather than picked as a round number. |