feat(web): add ArtistRow component
One row in the artists list: avatar initial, name, album count, chevron. Entire row is an <a> for click + keyboard activation.
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
<script lang="ts">
|
||||
import type { ArtistRef } from '$lib/api/types';
|
||||
|
||||
let { artist }: { artist: ArtistRef } = $props();
|
||||
|
||||
const initial = $derived(artist.name ? artist.name.charAt(0).toUpperCase() : '');
|
||||
const countLabel = $derived(artist.album_count === 1 ? '1 album' : `${artist.album_count} albums`);
|
||||
</script>
|
||||
|
||||
<a
|
||||
href={`/artists/${artist.id}`}
|
||||
class="flex items-center gap-3 border-b border-border px-3 py-3 hover:bg-surface-hover focus-visible:ring-2 focus-visible:ring-accent"
|
||||
>
|
||||
<span
|
||||
class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-surface font-semibold"
|
||||
aria-hidden="true"
|
||||
>
|
||||
{initial}
|
||||
</span>
|
||||
<span class="flex-1 truncate">{artist.name}</span>
|
||||
<span class="text-sm text-text-secondary">{countLabel}</span>
|
||||
<span class="text-text-secondary" aria-hidden="true">›</span>
|
||||
</a>
|
||||
@@ -0,0 +1,29 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import { render, screen } from '@testing-library/svelte';
|
||||
import ArtistRow from './ArtistRow.svelte';
|
||||
import type { ArtistRef } from '$lib/api/types';
|
||||
|
||||
const artist: ArtistRef = { id: 'abc', name: 'alice', album_count: 12 };
|
||||
|
||||
describe('ArtistRow', () => {
|
||||
test('renders initial, name, album count inside a link to /artists/:id', () => {
|
||||
render(ArtistRow, { props: { artist } });
|
||||
|
||||
const link = screen.getByRole('link');
|
||||
expect(link).toHaveAttribute('href', '/artists/abc');
|
||||
expect(link).toHaveTextContent('alice');
|
||||
expect(link).toHaveTextContent('12 albums');
|
||||
expect(link).toHaveTextContent('A'); // initial letter
|
||||
});
|
||||
|
||||
test('singular "1 album" when album_count is 1', () => {
|
||||
render(ArtistRow, { props: { artist: { ...artist, album_count: 1 } } });
|
||||
expect(screen.getByRole('link')).toHaveTextContent('1 album');
|
||||
});
|
||||
|
||||
test('empty name still renders a safe initial', () => {
|
||||
render(ArtistRow, { props: { artist: { ...artist, name: '' } } });
|
||||
// No crash; initial container present but empty or a placeholder char.
|
||||
expect(screen.getByRole('link')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user