From 6fc21899d12d416483f357278c051cf27e96d9f1 Mon Sep 17 00:00:00 2001 From: Yi-111-a <153097222+Yi-111-a@users.noreply.github.com> Date: Tue, 29 Sep 2026 13:36:44 +0800 Subject: [PATCH] fix(ui): show every album genre below the lg breakpoint AlbumDetails swapped the genre chip list for the single `record.genre` string whenever the viewport was below the `lg` breakpoint, so a multi-genre album showed only its primary genre below 1280px, even when there was room for all of them. SingleFieldList already sets `flexWrap: 'wrap'`, so the chips wrap on their own. Render GenreList unconditionally, which is also what AlbumInfo does for the same field. Fixes #6243 Co-Authored-By: opencode/space-bunny-free Signed-off-by: Yi-111-a <153097222+Yi-111-a@users.noreply.github.com> --- ui/src/album/AlbumDetails.jsx | 6 +--- ui/src/album/AlbumDetails.test.jsx | 58 ++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/ui/src/album/AlbumDetails.jsx b/ui/src/album/AlbumDetails.jsx index 8d636a047..7c12c1b6b 100644 --- a/ui/src/album/AlbumDetails.jsx +++ b/ui/src/album/AlbumDetails.jsx @@ -302,11 +302,7 @@ const AlbumDetails = (props) => { /> )} - {isDesktop ? ( - - ) : ( - {record.genre} - )} + {!isXsmall && ( {config.enableExternalServices && ( diff --git a/ui/src/album/AlbumDetails.test.jsx b/ui/src/album/AlbumDetails.test.jsx index afc4bf0a0..2b6213c3a 100644 --- a/ui/src/album/AlbumDetails.test.jsx +++ b/ui/src/album/AlbumDetails.test.jsx @@ -411,3 +411,61 @@ describe('AlbumDetails cover animation', () => { expect(cover.className).not.toMatch(/noCoverAnimation/) }) }) + +describe('AlbumDetails genres', () => { + const albumRecord = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + genre: 'Folk Metal', + genres: [ + { id: 'g1', name: 'Folk Metal' }, + { id: 'g2', name: 'Progressive Metal' }, + { id: 'g3', name: 'Folk Rock' }, + ], + } + + const { breakpoints } = createTheme() + + // Resolve the media queries against a viewport width instead of a fixed value, + // so a single case can cover both sides of the `lg` breakpoint. + const mockViewportWidth = (width) => + vi.mocked(useMediaQuery).mockImplementation((query) => { + const media = query({ breakpoints }) + const min = /min-width:\s*([\d.]+)px/.exec(media) + if (min) return width >= parseFloat(min[1]) + const max = /max-width:\s*([\d.]+)px/.exec(media) + if (max) return width <= parseFloat(max[1]) + return false + }) + + const renderAlbum = () => + render( + + + + + , + ) + + // The genre chips used to be swapped for the single `record.genre` string + // whenever the viewport was below the `lg` breakpoint, so a multi-genre album + // showed only its primary genre. See #6243. + test.each([ + ['xs', 400], + ['sm', 800], + ['md', 1000], + ['lg', 1400], + ])('renders the genre chip list at the %s breakpoint', (_, width) => { + mockViewportWidth(width) + + const { container } = renderAlbum() + + expect(container.querySelector('[class*="genreList"]')).not.toBeNull() + // The collapsed fallback rendered `record.genre` as a bare

. No other + // is left in AlbumDetails. + expect(container.querySelector('p')).toBeNull() + }) +})