73 lines
2.0 KiB
Svelte
73 lines
2.0 KiB
Svelte
<!-- TRACES: UR-035 | JA-029 | DR-040 -->
|
|
<script lang="ts">
|
|
import { goto } from "$app/navigation";
|
|
import type { Person } from "$lib/api/types";
|
|
|
|
interface Props {
|
|
people: Person[];
|
|
roleFilter: string[]; // e.g., ["Director", "Writer", "Producer"]
|
|
label?: string; // e.g., "Directed by", "Written by"
|
|
maxShow?: number; // Default: 3
|
|
}
|
|
|
|
let {
|
|
people,
|
|
roleFilter,
|
|
label,
|
|
maxShow = 3
|
|
}: Props = $props();
|
|
|
|
// Filter and limit people by role
|
|
const filteredPeople = $derived(
|
|
people
|
|
.filter(p => roleFilter.includes(p.type || "") && p.id && p.id.trim() !== "")
|
|
.slice(0, maxShow)
|
|
);
|
|
|
|
const totalMatching = $derived(
|
|
people.filter(p => roleFilter.includes(p.type || "") && p.id && p.id.trim() !== "").length
|
|
);
|
|
|
|
function handlePersonClick(personId: string, e: MouseEvent) {
|
|
e.preventDefault();
|
|
goto(`/library/${personId}`);
|
|
}
|
|
|
|
// Generate label if not provided
|
|
const displayLabel = $derived.by(() => {
|
|
if (label) return label;
|
|
|
|
if (roleFilter.length === 1) {
|
|
const role = roleFilter[0];
|
|
if (role === "Director") return "Directed by";
|
|
if (role === "Writer") return "Written by";
|
|
if (role === "Producer") return "Produced by";
|
|
if (role === "Composer") return "Music by";
|
|
return `${role}:`;
|
|
}
|
|
return "Credits:";
|
|
});
|
|
</script>
|
|
|
|
{#if filteredPeople.length > 0}
|
|
<div class="text-sm text-gray-400 flex flex-wrap items-baseline gap-2">
|
|
<span class="text-gray-500">{displayLabel}</span>
|
|
<div class="flex flex-wrap gap-1">
|
|
{#each filteredPeople as person, index (person.id)}
|
|
<button
|
|
onclick={(e) => handlePersonClick(person.id, e)}
|
|
class="text-[var(--color-jellyfin)] hover:underline"
|
|
>
|
|
{person.name}
|
|
</button>
|
|
{#if index < filteredPeople.length - 1}
|
|
<span class="text-gray-500">,</span>
|
|
{/if}
|
|
{/each}
|
|
{#if totalMatching > maxShow}
|
|
<span class="text-gray-500">+{totalMatching - maxShow} more</span>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
{/if}
|