diff --git a/web/src/lib/components/LibrarySkeleton.svelte b/web/src/lib/components/LibrarySkeleton.svelte new file mode 100644 index 00000000..deef89f9 --- /dev/null +++ b/web/src/lib/components/LibrarySkeleton.svelte @@ -0,0 +1,48 @@ + + +{#if variant === 'list'} +
+ {#each Array.from({ length: count }) as _, i (i)} +
+ + + +
+ {/each} +
+{:else if variant === 'grid'} +
+ {#each Array.from({ length: count }) as _, i (i)} +
+
+
+
+
+ {/each} +
+{:else} +
+
+
+
+
+
+
+
+
+
+ {#each Array.from({ length: 10 }) as _, i (i)} +
+ {/each} +
+
+{/if} diff --git a/web/src/lib/components/LibrarySkeleton.test.ts b/web/src/lib/components/LibrarySkeleton.test.ts new file mode 100644 index 00000000..78784f39 --- /dev/null +++ b/web/src/lib/components/LibrarySkeleton.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, test } from 'vitest'; +import { render, screen } from '@testing-library/svelte'; +import LibrarySkeleton from './LibrarySkeleton.svelte'; + +describe('LibrarySkeleton', () => { + test('variant="list" renders count placeholder rows', () => { + render(LibrarySkeleton, { props: { variant: 'list', count: 5 } }); + const container = screen.getByTestId('skeleton-list'); + expect(container.querySelectorAll('[data-skeleton-row]').length).toBe(5); + }); + + test('variant="grid" renders count placeholder cards', () => { + render(LibrarySkeleton, { props: { variant: 'grid', count: 6 } }); + const container = screen.getByTestId('skeleton-grid'); + expect(container.querySelectorAll('[data-skeleton-card]').length).toBe(6); + }); + + test('variant="album" renders a hero placeholder with cover block + bars', () => { + render(LibrarySkeleton, { props: { variant: 'album' } }); + expect(screen.getByTestId('skeleton-album')).toBeInTheDocument(); + expect(screen.getByTestId('skeleton-album-cover')).toBeInTheDocument(); + }); +});