From 076e982b69dbbaf6b91d064cd64aabe6b93cf72e Mon Sep 17 00:00:00 2001 From: Roland Date: Wed, 5 Aug 2026 16:47:33 -0600 Subject: [PATCH] ui: a Back button is a row of one, not a stretched flex child Reported: the Back button fills the page width on the domain and channel edit pages. It fills it on all nine pages that have one, and this is mine from the last PR. `.wrolpi-stack` is a flex column at `align-items: stretch`, deliberately -- a panel was full-width as a block element and has to stay that way. A BARE button as a direct child of that stack is stretched too, and every page's Back button was one. On the domain, channel and playlist edit pages it also pushed the button beside it onto its own line, where the two had been inline. Wrapping each in a `.wrolpi-button-row` fixes both without touching the stack: the row is the stretched child, and it lays its buttons out at their own width. The three pages that have a second button get one row holding both, which is how they read before. Also the Videos, Archives and Documents select bars, whose Tag/Delete/Invert/ Clear were four touching buttons in a bare div. They are inline elements rather than interpolations, which is the shape the bare-siblings scan does not see. Guarded twice: the row keeps its buttons their own width inside a stack while itself stretching (both halves, since a row that refused to stretch would pass a test that only looked at the button), and every `` in the app is inside a row. Co-Authored-By: Claude Opus 5 (1M context) --- app/src/components/Archive.js | 16 ++++++------ app/src/components/Channels.js | 12 +++++---- app/src/components/Common.test.js | 35 +++++++++++++++++++++++++++ app/src/components/Docs.js | 4 +-- app/src/components/Playlists.js | 12 +++++---- app/src/components/VideoPlayer.js | 2 +- app/src/components/Videos.js | 2 +- app/src/components/ui/ui-layout.cy.js | 26 ++++++++++++++++++++ 8 files changed, 88 insertions(+), 21 deletions(-) diff --git a/app/src/components/Archive.js b/app/src/components/Archive.js index ee5bca1f..73c4e25b 100644 --- a/app/src/components/Archive.js +++ b/app/src/components/Archive.js @@ -254,7 +254,7 @@ function ArchivePage() { const labelStyle = {whiteSpace: 'nowrap', paddingRight: '1.5em', verticalAlign: 'top'}; return <> - +
{screenshot} @@ -619,7 +619,7 @@ export function DomainEditPage() { if (!form.ready) { if (form.error) { return <> - +

{form.error}

@@ -685,10 +685,12 @@ export function DomainEditPage() { const [descriptionProps] = form.getCustomProps({name: 'description', path: 'description'}); return <> - - - - +
+ + + + +
{domain?.needs_reorganization && ( @@ -1171,7 +1173,7 @@ function ArchivesPage() { setSelectedArchives([]); } - const selectElm =
+ const selectElm =
- +
+ + + + +
{channel?.needs_reorganization && ( @@ -419,7 +421,7 @@ export function ChannelNewPage() { } return <> - +
New Channel
diff --git a/app/src/components/Common.test.js b/app/src/components/Common.test.js index f2824797..565575ba 100644 --- a/app/src/components/Common.test.js +++ b/app/src/components/Common.test.js @@ -1002,6 +1002,41 @@ describe('a row of buttons', () => { expect(offenders).toEqual([]); }); + + it('puts every Back button in a row, so the page stack cannot stretch it', () => { + /* + * A page's blocks are stacked by `.wrolpi-stack`, which is a flex column at + * `align-items: stretch` -- deliberately, because a panel was full-width as a block + * element and has to stay that way. A BARE button as a direct child of that stack is + * stretched too, and every page's Back button was one: full-page-width, and on the domain, + * channel and playlist edit pages the button beside it was pushed onto its own line where + * the two had been inline before. + * + * A row fixes it without touching the stack: the row is the stretched child, and it lays + * its buttons out at their own width. Nine sites, so this scan rather than nine + * assertions -- and a scan because a stretched button is still a working button. + */ + const offenders = []; + let found = 0; + + for (const file of sourceFiles()) { + const text = fs.readFileSync(file, 'utf8'); + const tags = tagsIn(text); + + for (const match of text.matchAll(/ + const selectElm =
; return <> - +
{isCbz && activePath && } diff --git a/app/src/components/Playlists.js b/app/src/components/Playlists.js index 24c285b9..28e4de5d 100644 --- a/app/src/components/Playlists.js +++ b/app/src/components/Playlists.js @@ -346,7 +346,7 @@ export function PlaylistViewPage() { const items = playlist.items || []; return <> - +
{playlist.name} @@ -498,10 +498,12 @@ export function PlaylistEditPage() { const form = {error: null, loading: false, disabled: !editable || !name.trim(), ready: true}; return <> - - - - +
+ + + + +
-
+
diff --git a/app/src/components/Videos.js b/app/src/components/Videos.js index 1ba05690..2e0625a8 100644 --- a/app/src/components/Videos.js +++ b/app/src/components/Videos.js @@ -175,7 +175,7 @@ export function VideosPage() { setSelectedVideos([]); } - const selectElm =
+ const selectElm =
+ The page +
); + + cy.get('.wrolpi-stack').should(($stack) => { + const stack = $stack[0].getBoundingClientRect(); + const row = $stack[0].querySelector('.wrolpi-button-row').getBoundingClientRect(); + const button = $stack[0].querySelector('button').getBoundingClientRect(); + + expect(stack.width, 'the stack has a width to fill').to.be.greaterThan(200); + expect(row.width, 'the row stretches, as the panel does').to.be.closeTo(stack.width, 0.5); + expect(button.width, 'the button does not').to.be.lessThan(stack.width / 2); + }); + }); + it('grows its gap with the interface scale', () => { cy.mountUI(
);