First working POC
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
<script lang="ts">
|
||||
import type { MediaItem } from "$lib/api/types";
|
||||
import { auth } from "$lib/stores/auth";
|
||||
import { onMount } from "svelte";
|
||||
import LibraryGrid from "./LibraryGrid.svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
|
||||
interface Props {
|
||||
person: MediaItem;
|
||||
}
|
||||
|
||||
let { person }: Props = $props();
|
||||
|
||||
let movies = $state<MediaItem[]>([]);
|
||||
let series = $state<MediaItem[]>([]);
|
||||
let loading = $state(true);
|
||||
|
||||
onMount(async () => {
|
||||
await loadFilmography();
|
||||
});
|
||||
|
||||
async function loadFilmography() {
|
||||
loading = true;
|
||||
try {
|
||||
const repo = auth.getRepository();
|
||||
const result = await repo.getItemsByPerson(person.id, {
|
||||
limit: 100,
|
||||
includeItemTypes: ["Movie", "Series"],
|
||||
});
|
||||
|
||||
// Separate movies and series
|
||||
movies = result.items.filter(item => item.type === "Movie");
|
||||
series = result.items.filter(item => item.type === "Series");
|
||||
} catch (e) {
|
||||
console.error("Failed to load filmography:", e);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
function getImageUrl(): string {
|
||||
try {
|
||||
const repo = auth.getRepository();
|
||||
return repo.getImageUrl(person.id, "Primary", {
|
||||
maxWidth: 400,
|
||||
tag: person.primaryImageTag,
|
||||
});
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function handleItemClick(item: MediaItem) {
|
||||
goto(`/library/${item.id}`);
|
||||
}
|
||||
|
||||
const imageUrl = $derived(getImageUrl());
|
||||
</script>
|
||||
|
||||
<div class="space-y-8">
|
||||
<!-- Person header -->
|
||||
<div class="flex gap-6 pt-4">
|
||||
<!-- Profile image -->
|
||||
<div class="flex-shrink-0 w-48">
|
||||
{#if imageUrl && person.primaryImageTag}
|
||||
<img
|
||||
src={imageUrl}
|
||||
alt={person.name}
|
||||
class="w-full rounded-lg shadow-lg"
|
||||
/>
|
||||
{:else}
|
||||
<div class="w-full aspect-square bg-[var(--color-surface)] rounded-lg flex items-center justify-center">
|
||||
<svg class="w-16 h-16 text-gray-600" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
|
||||
</svg>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Info -->
|
||||
<div class="flex-1 space-y-4">
|
||||
<h1 class="text-3xl font-bold text-white">{person.name}</h1>
|
||||
|
||||
<span class="inline-block px-2 py-1 bg-[var(--color-surface)] rounded text-sm text-gray-400">
|
||||
Person
|
||||
</span>
|
||||
|
||||
{#if person.overview}
|
||||
<p class="text-gray-300 leading-relaxed max-w-2xl">{person.overview}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filmography - separated by type -->
|
||||
<div class="space-y-8">
|
||||
{#if movies.length > 0}
|
||||
<LibraryGrid
|
||||
title="Movies"
|
||||
items={movies}
|
||||
{loading}
|
||||
showViewToggle={false}
|
||||
onItemClick={handleItemClick}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if series.length > 0}
|
||||
<LibraryGrid
|
||||
title="TV Series"
|
||||
items={series}
|
||||
{loading}
|
||||
showViewToggle={false}
|
||||
onItemClick={handleItemClick}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if !loading && movies.length === 0 && series.length === 0}
|
||||
<div class="text-center py-12 text-gray-400">
|
||||
<p>No filmography found</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user