@@ -3,15 +3,36 @@ import Base from "../../layouts/Base.astro";
33import MediaCard from " ../../components/MediaCard.astro" ;
44import ActionBar from " ../../components/ActionBar.astro" ;
55import CommentsSection from " ../../components/CommentsSection.astro" ;
6+ import FilterPanel from " ../../components/FilterPanel.astro" ;
67import { api , type MediaItem } from " ../../lib/api" ;
78export const prerender = false ;
89
910const { id } = Astro .params ;
1011const { token } = Astro .locals ;
11- const person = await api .media .getPerson (Number (id ), 1 , token );
12+ const collectionParam = Astro .url .searchParams .get (" collection" );
13+ const collection: " in" | " out" | " " = collectionParam === " in" || collectionParam === " out" ? collectionParam : " " ;
14+ const genre = Astro .url .searchParams .getAll (" genre" );
15+ const year = Astro .url .searchParams .getAll (" year" ).map (Number ).filter ((y ) => ! Number .isNaN (y ));
16+ const minRating = Astro .url .searchParams .get (" min_rating" ) ?? " " ;
17+ const person = await api .media .getPerson (Number (id ), 1 , token , { collection , genre , year , minRating });
1218
1319const credits = person .credits || [];
1420const totalPages = Math .ceil (person .total_credits / person .page_size );
21+
22+ const MOVIE_GENRES = [
23+ " Action" , " Adventure" , " Animation" , " Comedy" , " Crime" , " Documentary" ,
24+ " Drama" , " Family" , " Fantasy" , " History" , " Horror" , " Music" , " Mystery" ,
25+ " Romance" , " Science Fiction" , " Thriller" , " War" , " Western" ,
26+ ];
27+ const TV_GENRES = [
28+ " Action & Adventure" , " Animation" , " Comedy" , " Crime" , " Documentary" ,
29+ " Drama" , " Family" , " Kids" , " Mystery" , " News" , " Reality" ,
30+ " Sci-Fi & Fantasy" , " Soap" , " Talk" , " War & Politics" , " Western" ,
31+ ];
32+ const CREDIT_GENRES = Array .from (new Set ([... MOVIE_GENRES , ... TV_GENRES ])).sort ();
33+
34+ const currentYear = new Date ().getFullYear ();
35+ const years = Array .from ({ length: currentYear - 1949 }, (_ , i ) => currentYear - i );
1536---
1637
1738<Base title ={ person .name } >
@@ -93,17 +114,42 @@ const totalPages = Math.ceil(person.total_credits / person.page_size);
93114 )}
94115
95116 <div >
96- <h2 class =" section-headline mb-6" >Known For</h2 >
97- <div id =" credits-grid" class =" grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4" >
98- { credits .map ((item ) => (
99- <div class = " flex flex-col gap-1" >
100- <MediaCard item = { item as unknown as MediaItem } />
101- { item .character && (
102- <p class = " text-xs text-zinc-500 truncate px-1" >as { item .character } </p >
103- )}
104- </div >
105- ))}
117+ <div class =" flex flex-wrap items-center justify-between gap-4 mb-6" >
118+ <h2 class =" section-headline" >Known For</h2 >
119+ <FilterPanel
120+ id =" person-credits-filters"
121+ basePath ={ ` /person/${id } ` }
122+ sections ={ [
123+ { key: " collection" , label: " Collection" , options: [{ value: " in" , label: " In My Collection" }, { value: " out" , label: " Not In My Collection" }], selected: collection ? [collection ] : [], multi: false },
124+ { key: " genre" , label: " Genre" , options: CREDIT_GENRES .map ((g ) => ({ value: g , label: g })), selected: genre },
125+ { key: " year" , label: " Year" , options: years .map ((y ) => ({ value: String (y ), label: String (y ) })), selected: year .map (String ) },
126+ {
127+ key: " min_rating" ,
128+ label: " Rating" ,
129+ options: [
130+ ... [9 , 8 , 7 , 6 , 5 ].map ((r ) => ({ value: String (r ), label: ` ${r }+ Stars ` })),
131+ { value: " lt5" , label: " Less than 5 Stars" },
132+ ],
133+ selected: minRating ? [minRating ] : [],
134+ multi: false ,
135+ },
136+ ]}
137+ />
106138 </div >
139+ { credits .length === 0 && (collection || genre .length > 0 || year .length > 0 || minRating ) ? (
140+ <p class = " text-zinc-500 text-sm" >No matching credits found.</p >
141+ ) : (
142+ <div id = " credits-grid" class = " grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4" >
143+ { credits .map ((item ) => (
144+ <div class = " flex flex-col gap-1" >
145+ <MediaCard item = { item as unknown as MediaItem } />
146+ { item .character && (
147+ <p class = " text-xs text-zinc-500 truncate px-1" >as { item .character } </p >
148+ )}
149+ </div >
150+ ))}
151+ </div >
152+ )}
107153 { totalPages > 1 && (
108154 <div id = " credits-pagination" class = " flex items-center justify-center gap-3 mt-8" >
109155 <button id = " credits-prev" disabled class = " px-4 py-2 text-sm rounded-lg bg-zinc-800 text-zinc-400 border border-zinc-700 disabled:opacity-40 disabled:cursor-not-allowed cursor-pointer hover:bg-zinc-700 transition-colors" >← Prev</button >
@@ -164,7 +210,7 @@ const totalPages = Math.ceil(person.total_credits / person.page_size);
164210 }
165211</script >
166212
167- <script define:vars ={ { personId: person .tmdb_id , totalCredits: person .total_credits , pageSize: person .page_size }} >
213+ <script define:vars ={ { personId: person .tmdb_id , totalCredits: person .total_credits , pageSize: person .page_size , collection , genre , year , minRating }} >
168214 const totalPages = Math.ceil(totalCredits / pageSize);
169215 let currentPage = 1;
170216 let loading = false;
@@ -188,7 +234,12 @@ const totalPages = Math.ceil(person.total_credits / person.page_size);
188234 grid.style.pointerEvents = 'none';
189235
190236 try {
191- const res = await fetch('/partials/person-credits?person_id=' + personId + '&page=' + page);
237+ const params = new URLSearchParams({ person_id: String(personId), page: String(page) });
238+ if (collection) params.set('collection', collection);
239+ genre.forEach((g) => params.append('genre', g));
240+ year.forEach((y) => params.append('year', String(y)));
241+ if (minRating) params.set('min_rating', minRating);
242+ const res = await fetch('/partials/person-credits?' + params.toString());
192243 if (!res.ok) return;
193244 const html = await res.text();
194245 const tmp = document.createElement('div');
0 commit comments