diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-07 11:38:39 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-07 11:38:39 +0200 |
| commit | 219093c823494bc8d760c99a7a55c4a23059abb5 (patch) | |
| tree | 98ef5b17bceea51a6b090bf61b2f91dadb168e49 /packages | |
| parent | 926937413857e6a139388ad6e2fa33b2d2808ca8 (diff) | |
| download | meshbay-219093c823494bc8d760c99a7a55c4a23059abb5.tar.gz | |
fix(hub): move "clear finished" into the finished group's head
9269374 let the transfers header wrap, which broke the one-line header
test_layout_measured enforces. The button now sits beside what it clears,
and the header is title and summary only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/app.js | 21 | ||||
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/style.css | 17 | ||||
| -rw-r--r-- | packages/meshbay-hub/tests/test_layout_measured.py | 24 |
3 files changed, 46 insertions, 16 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js index bdab271..c1913c0 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js @@ -228,18 +228,23 @@ function TransferWidget() { running: running.length, waiting: waiting.length })} </span> `} - ${finished.length > 0 && html` - <button class="btn-secondary" - onClick=${() => transfers.clearFinished()}> - ${t('transfers.clear')} - </button> - `} </div> ${groups.map(([label, rows]) => html` <div class="transfer-group" key=${label}> - ${groups.length > 1 && html` + ${/* The finished group always gets its head, because clearing it + lives there. It used to sit in the panel header, where the + title, the summary and the button together outgrow the + panel in French and on a phone: the header either scrolled + the panel sideways or wrapped and changed height. */''} + ${(groups.length > 1 || label === 'finished') && html` <div class="transfer-group-head"> - ${t('transfers.group_' + label, { n: rows.length })} + <span>${t('transfers.group_' + label, { n: rows.length })}</span> + ${label === 'finished' && html` + <button class="btn-secondary" + onClick=${() => transfers.clearFinished()}> + ${t('transfers.clear')} + </button> + `} </div> `} ${rows.map(it => html`<${TransferRow} it=${it} key=${it.id} />`)} diff --git a/packages/meshbay-hub/src/meshbay_hub/static/style.css b/packages/meshbay-hub/src/meshbay_hub/static/style.css index f9dc3d8..539ac12 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/style.css +++ b/packages/meshbay-hub/src/meshbay_hub/static/style.css @@ -2735,10 +2735,9 @@ button:disabled { opacity: 0.5; cursor: not-allowed; } } .transfer-head { display: flex; - flex-wrap: wrap; align-items: center; justify-content: space-between; - gap: 4px 8px; + gap: 8px; font-weight: 600; font-size: 0.85em; color: var(--text); @@ -5391,18 +5390,24 @@ h2 .gn-owner, h3 .gn-owner { font-size: 0.55em; } and go pushes every row under it. */ white-space: nowrap; } -/* Title, summary and this button do not fit 330 px in French, and every row - below truncates rather than scrolls: the button takes a line of its own, - still on the right, instead of pushing the panel into a sideways scroll. */ -.transfer-head .btn-secondary { margin-left: auto; } .transfer-group + .transfer-group { border-top: 1px solid var(--border); } .transfer-group-head { + display: flex; + align-items: center; + justify-content: space-between; padding: .35rem .6rem .2rem; font-size: .78em; text-transform: uppercase; letter-spacing: .04em; color: var(--text-dim); } +/* A button, not a label: none of the head's small capitals. */ +.transfer-group-head .btn-secondary { + text-transform: none; + letter-spacing: normal; + font-size: 1.05em; + padding: 2px 8px; +} /* Finished rows recede rather than disappear: somebody who just downloaded three files wants to see that all three are there. */ .transfer-item.transfer-done .transfer-name, diff --git a/packages/meshbay-hub/tests/test_layout_measured.py b/packages/meshbay-hub/tests/test_layout_measured.py index c5d6280..57d325a 100644 --- a/packages/meshbay-hub/tests/test_layout_measured.py +++ b/packages/meshbay-hub/tests/test_layout_measured.py @@ -167,7 +167,6 @@ GROUPED = textwrap.dedent(""" <div class="transfer-head"> <span class="transfer-head-title">Transfers</span> <span class="transfer-head-summary">2 running · 3 waiting</span> - <button class="btn-secondary">Clear finished</button> </div> <div class="transfer-group"> <div class="transfer-group-head">Running</div> @@ -195,6 +194,16 @@ GROUPED = textwrap.dedent(""" <span>1.2 GB</span></div> </div> </div> + <div class="transfer-group"> + <div class="transfer-group-head"><span>Finished</span> + <button class="btn-secondary">Clear finished</button></div> + <div class="transfer-item transfer-done"> + <div class="transfer-line"> + <span class="transfer-kind">↓</span> + <span class="transfer-name">A Finished File.mkv</span> + </div> + </div> + </div> </div> </div> <a class="nav-notif" href="#/">🔔</a> @@ -205,7 +214,8 @@ GROUPED = textwrap.dedent(""" GROUPED_SELECTORS = [".transfer-panel", ".transfer-head", ".transfer-head-summary", ".transfer-group-head", ".transfer-name", - ".transfer-item.transfer-queued .dl-progress"] + ".transfer-item.transfer-queued .dl-progress", + ".transfer-group-head .btn-secondary"] @pytest.fixture(scope="module") @@ -253,6 +263,16 @@ def test_the_header_summary_does_not_push_the_header_taller(grouped): f"at {width} px the summary wrapped to {summary['height']} px") +def test_clearing_finished_rows_stays_inside_the_panel(grouped): + """The button lives in the finished group's head. In the panel header it + pushed the panel into a sideways scroll, or wrapped the header.""" + for width in WIDTHS: + boxes = grouped[str(width)]["boxes"] + button = boxes[".transfer-group-head .btn-secondary"] + assert button["right"] <= boxes[".transfer-panel"]["right"], ( + f"at {width} px the clear button sticks out of the panel: {button}") + + def test_the_waiting_bar_is_as_wide_as_a_progress_bar(grouped): """A waiting row has no inner fill element — the stripes are on the track itself. Getting that wrong renders a zero-width bar, which reads as a |