From cd0b9c97e105a11b99a54256caa423ac1758f430 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 4 May 2026 06:57:24 -0400 Subject: [PATCH] fix(web/m7-365): align /library/history with albums-page conventions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code-quality review flagged convention drift from sibling library pages. Aligning so the history page matches the same shape: - queryStore + $derived($queryStore) pattern (single subscription point) instead of $query.X everywhere. - h1 uses font-display text-2xl font-medium per FabledSword design system (weights 400/500 only — font-semibold drifted to 600). - h2 uses font-medium + z-10 for sticky-header layering. - InfiniteScrollSentinel uses its `enabled` prop (which exists; the earlier spec note claiming otherwise was wrong) so the observer isn't recreated on every fetch cycle. - Loading more… / End of history footers added to match albums. - onRetry passes query.refetch by reference, not wrapped. - Dropped redundant `as HistoryEvent[]` cast. Also fixed test case 4 which trivially passed regardless of the conditional gate's correctness — now queries the sentinel's actual DOM root (div[aria-hidden="true"].h-px) and asserts presence/absence. Added a positive twin test for hasNextPage=true. --- web/src/routes/library/history/+page.svelte | 38 +++++++++++++-------- web/src/routes/library/history/page.test.ts | 16 ++++++--- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/web/src/routes/library/history/+page.svelte b/web/src/routes/library/history/+page.svelte index f6be6aff..789a4a3d 100644 --- a/web/src/routes/library/history/+page.svelte +++ b/web/src/routes/library/history/+page.svelte @@ -1,35 +1,35 @@ {pageTitle('Library · History')} -
-

History

+
+
+

History

+
- {#if $query.isPending} + {#if query.isPending} - {:else if $query.isError} - $query.refetch()} /> + {:else if query.isError} + {:else if flatEvents.length === 0}

No listening history yet.

{:else} {#each grouped as group (group.label)}
-

+

{group.label}

@@ -40,8 +40,16 @@
{/each} - {#if $query.hasNextPage && !$query.isFetchingNextPage} - $query.fetchNextPage()} /> + {#if query.hasNextPage} + query.fetchNextPage()} + /> + {#if query.isFetchingNextPage} +

Loading more…

+ {/if} + {:else if flatEvents.length > 0} +

End of history

{/if} {/if}
diff --git a/web/src/routes/library/history/page.test.ts b/web/src/routes/library/history/page.test.ts index 94090c94..5210ea6a 100644 --- a/web/src/routes/library/history/page.test.ts +++ b/web/src/routes/library/history/page.test.ts @@ -108,10 +108,18 @@ describe('library/history page', () => { mockData = { pages: [{ events: [mkEvent('a', new Date())], has_more: false }] }; mockHasNextPage = false; const { container } = render(HistoryPage); - // Sentinel renders an empty
— assert by absence of the call. - // (We can't easily query for the sentinel itself in the DOM since it has - // no aria role; instead, verify the page renders the song without error.) + // InfiniteScrollSentinel renders