Completed discovery page

This commit is contained in:
Aleksi Lassila
2023-07-31 00:09:07 +03:00
parent 77153a96c5
commit 8e60c8fad2
37 changed files with 876 additions and 325 deletions

View File

@@ -4,14 +4,14 @@
import { TMDB_IMAGES } from '$lib/constants';
import { Clock, Star } from 'radix-icons-svelte';
export let tmdbId: string;
export let tmdbId: number;
export let type: 'movie' | 'series' = 'movie';
export let title: string;
export let genres: string[];
export let genres: string[] = [];
export let runtimeMinutes = 0;
export let seasons = 0;
export let completionTime = '';
export let backdropUrl: string;
export let backdropUri: string;
export let rating: number;
export let available = true;
@@ -23,22 +23,19 @@
}
</script>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<div
tabindex={0}
<a
class={classNames(
'rounded overflow-hidden relative shadow-2xl shrink-0 aspect-video selectable',
'rounded overflow-hidden relative shadow-lg shrink-0 aspect-video selectable block hover:text-inherit',
{
'h-40': size === 'md',
'h-60': size === 'lg',
'w-full': size === 'dynamic'
}
)}
href={`/${type}/${tmdbId}`}
>
<div style={'width: ' + progress + '%'} class="h-[2px] bg-zinc-200 bottom-0 absolute z-[1]" />
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
on:click={() => window.open(`/${type}/${tmdbId}`, '_self')}
class="h-full w-full opacity-0 hover:opacity-100 transition-opacity flex flex-col justify-between cursor-pointer p-2 px-3 relative z-[1] peer"
style={progress > 0 ? 'padding-bottom: 0.6rem;' : ''}
>
@@ -82,7 +79,7 @@
</div>
</div>
<div
style={"background-image: url('" + TMDB_IMAGES + backdropUrl + "')"}
style={"background-image: url('" + TMDB_IMAGES + backdropUri + "')"}
class="absolute inset-0 bg-center bg-cover peer-hover:scale-105 transition-transform"
/>
<div
@@ -91,4 +88,4 @@
'bg-[#00000055] peer-hover:bg-darken': !available
})}
/>
</div>
</a>

View File

@@ -0,0 +1,3 @@
<div class="grid gap-x-4 gap-y-8 grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
<slot />
</div>

View File

@@ -1,42 +1,47 @@
import type { RadarrMovie } from '$lib/apis/radarr/radarrApi';
import { fetchTmdbMovieImages } from '$lib/apis/tmdb/tmdbApi';
import type { TmdbMovie } from '$lib/apis/tmdb/tmdbApi';
import {
fetchTmdbMovieImages,
getTmdbMovieBackdrop,
getTmdbMovieImages,
getTmdbSeriesBackdrop,
getTmdbSeriesImages
} from '$lib/apis/tmdb/tmdbApi';
import type { TmdbMovie, TmdbMovie2, TmdbSeries2 } from '$lib/apis/tmdb/tmdbApi';
import type { ComponentProps } from 'svelte';
import type Card from './Card.svelte';
export interface CardProps {
tmdbId: string;
title: string;
genres: string[];
runtimeMinutes: number;
backdropUrl: string;
rating: number;
}
export const fetchCardProps = async (movie: RadarrMovie): Promise<CardProps> => {
const backdropUrl = fetchTmdbMovieImages(String(movie.tmdbId)).then(
(r) => r.backdrops.filter((b) => b.iso_639_1 === 'en')[0].file_path
);
export const fetchCardTmdbMovieProps = async (movie: TmdbMovie2): Promise<ComponentProps<Card>> => {
const backdropUri = getTmdbMovieBackdrop(movie.id || 0);
return {
tmdbId: String(movie.tmdbId),
title: String(movie.title),
genres: movie.genres as string[],
runtimeMinutes: movie.runtime as any,
backdropUrl: await backdropUrl,
rating: movie.ratings?.tmdb?.value || movie.ratings?.imdb?.value || 0
};
};
export const fetchCardPropsTmdb = async (movie: TmdbMovie): Promise<CardProps> => {
const backdropUrl = fetchTmdbMovieImages(String(movie.id))
.then((r) => r.backdrops.filter((b) => b.iso_639_1 === 'en')[0]?.file_path)
.catch(console.error);
return {
tmdbId: String(movie.id),
title: String(movie.original_title),
genres: movie.genres.map((g) => g.name),
tmdbId: movie.id || 0,
title: movie.title || '',
genres: movie.genres?.map((g) => g.name || '') || [],
runtimeMinutes: movie.runtime,
backdropUrl: (await backdropUrl) || '',
backdropUri: (await backdropUri) || '',
rating: movie.vote_average || 0
};
};
export const fetchCardTmdbSeriesProps = async (
series: TmdbSeries2
): Promise<ComponentProps<Card>> => {
const backdropUri = getTmdbSeriesBackdrop(series.id || 0);
return {
tmdbId: series.id || 0,
title: series.name || '',
genres: series.genres?.map((g) => g.name || '') || [],
runtimeMinutes: series.episode_run_time?.[0],
backdropUri: (await backdropUri) || '',
rating: series.vote_average || 0,
type: 'series'
};
};
export const fetchCardTmdbProps = async (
item: TmdbSeries2 | TmdbMovie2
): Promise<ComponentProps<Card>> => {
if ('name' in item) return fetchCardTmdbSeriesProps(item);
return fetchCardTmdbMovieProps(item);
};