mirror of
https://github.com/aleksilassila/reiverr.git
synced 2026-04-21 08:15:12 +02:00
feat: Episode page
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
|
||||
export let inactive: boolean = false;
|
||||
export let focusOnMount: boolean = false;
|
||||
export let style: 'primary' | 'secondary' = 'primary';
|
||||
|
||||
let hasFocus: Readable<boolean>;
|
||||
</script>
|
||||
@@ -14,12 +15,9 @@
|
||||
<Container
|
||||
bind:hasFocus
|
||||
class={classNames(
|
||||
'px-6 py-2 rounded-lg font-medium tracking-wide flex items-center',
|
||||
'px-6 py-2 rounded-lg font-medium tracking-wide flex items-center selectable',
|
||||
{
|
||||
// 'bg-primary-500 text-secondary-700': $hasFocus,
|
||||
// 'bg-secondary-700': !$hasFocus,
|
||||
// 'hover:bg-primary-500 hover:text-secondary-700': true,
|
||||
'bg-secondary-700 selectable': true,
|
||||
'bg-secondary-700': style === 'primary',
|
||||
'cursor-pointer': !inactive,
|
||||
'cursor-not-allowed pointer-events-none opacity-40': inactive
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import Container from '../../../Container.svelte';
|
||||
import classNames from 'classnames';
|
||||
import { Check, CheckCircled, TriangleRight } from 'radix-icons-svelte';
|
||||
import { ArrowDown, Check, TriangleRight } from 'radix-icons-svelte';
|
||||
import type { Readable } from 'svelte/store';
|
||||
import AnimateScale from '../AnimateScale.svelte';
|
||||
|
||||
@@ -22,10 +22,7 @@
|
||||
class={classNames(
|
||||
'w-full h-64',
|
||||
'flex flex-col shrink-0',
|
||||
'overflow-hidden rounded-2xl cursor-pointer group relative px-4 py-3 selectable transition-opacity',
|
||||
{
|
||||
'opacity-75': !isOnDeck && !$hasFocus
|
||||
}
|
||||
'overflow-hidden rounded-2xl cursor-pointer group relative px-4 py-3 selectable transition-opacity'
|
||||
)}
|
||||
on:clickOrSelect
|
||||
on:enter
|
||||
@@ -55,24 +52,28 @@
|
||||
</div>
|
||||
<!-- Background Image -->
|
||||
<div
|
||||
class="absolute inset-0 bg-center bg-cover"
|
||||
class={classNames('absolute inset-0 bg-center bg-cover', {
|
||||
// 'opacity-75': !isOnDeck && !$hasFocus
|
||||
})}
|
||||
style={`background-image: url('${backdropUrl}')`}
|
||||
/>
|
||||
<!-- Background Overlay / Tint -->
|
||||
<div
|
||||
class={classNames('absolute inset-0', {
|
||||
'bg-gradient-to-t from-secondary-900/75 from-10% to-40% to-transparent': true
|
||||
'bg-gradient-to-t from-secondary-900/75 from-10% to-40% ': true,
|
||||
'to-secondary-900/25': !isOnDeck && !$hasFocus
|
||||
|
||||
// isOnDeck || $hasFocus,
|
||||
// 'bg-gradient-to-t from-secondary-900/75 from-10% to-40% to-secondary-900/25':
|
||||
// !isOnDeck && !$hasFocus
|
||||
})}
|
||||
/>
|
||||
{#if handlePlay}
|
||||
<div
|
||||
class={classNames(
|
||||
'group-hover:opacity-100 absolute inset-0 z-20 flex items-center justify-center'
|
||||
)}
|
||||
>
|
||||
<div
|
||||
class={classNames(
|
||||
'opacity-0 group-focus-within:opacity-100 group-hover:opacity-100 absolute inset-0 z-20 flex items-center justify-center'
|
||||
)}
|
||||
>
|
||||
{#if handlePlay}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class={classNames(
|
||||
@@ -84,7 +85,17 @@
|
||||
>
|
||||
<TriangleRight size={32} />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{:else if !isOnDeck}
|
||||
<div
|
||||
class={classNames(
|
||||
'rounded-full p-4 cursor-pointer',
|
||||
'bg-zinc-900/90 text-zinc-200',
|
||||
'hover:bg-primary-500 hover:text-secondary-800' // group-focus-within:text-secondary-800 group-focus-within:bg-primary-500
|
||||
)}
|
||||
>
|
||||
<ArrowDown size={19} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Container>
|
||||
</AnimateScale>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script lang="ts">
|
||||
import EpisodeCard from './EpisodeCard.svelte';
|
||||
import type { TmdbEpisode } from '../../apis/tmdb/tmdb-api';
|
||||
import type { TmdbSeasonEpisode } from '../../apis/tmdb/tmdb-api';
|
||||
import { TMDB_BACKDROP_SMALL } from '../../constants';
|
||||
|
||||
export let episode: TmdbEpisode;
|
||||
export let episode: TmdbSeasonEpisode;
|
||||
export let handlePlay: (() => void) | undefined;
|
||||
export let isWatched = false;
|
||||
export let playbackProgress = 0;
|
||||
|
||||
0
src/lib/components/HeroInfo/HeroInfoSubtitle.svelte
Normal file
0
src/lib/components/HeroInfo/HeroInfoSubtitle.svelte
Normal file
0
src/lib/components/HeroInfo/HeroInfoTags.svelte
Normal file
0
src/lib/components/HeroInfo/HeroInfoTags.svelte
Normal file
17
src/lib/components/HeroInfo/HeroInfoTitle.svelte
Normal file
17
src/lib/components/HeroInfo/HeroInfoTitle.svelte
Normal file
@@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
import classNames from 'classnames';
|
||||
|
||||
export let title: string | undefined;
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={classNames(
|
||||
'text-left font-medium tracking-wider text-zinc-200 hover:text-amber-200 mt-1',
|
||||
{
|
||||
'text-4xl sm:text-5xl lg:text-6xl': (title?.length || 0) < 15,
|
||||
'text-3xl sm:text-4xl lg:text-5xl': (title?.length || 0) >= 15
|
||||
}
|
||||
)}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
@@ -5,7 +5,7 @@
|
||||
import { derived, get, type Readable } from 'svelte/store';
|
||||
import {
|
||||
tmdbApi,
|
||||
type TmdbEpisode,
|
||||
type TmdbSeasonEpisode,
|
||||
type TmdbSeason,
|
||||
type TmdbSeriesFull2
|
||||
} from '../../apis/tmdb/tmdb-api';
|
||||
@@ -24,9 +24,9 @@
|
||||
export let nextJellyfinEpisode: Readable<JellyfinItem | undefined>;
|
||||
|
||||
// Exports
|
||||
export let selectedTmdbEpisode: TmdbEpisode | undefined;
|
||||
export let selectedTmdbEpisode: TmdbSeasonEpisode | undefined;
|
||||
|
||||
const containers = new Map<TmdbSeason | TmdbEpisode, Selectable>();
|
||||
const containers = new Map<TmdbSeason | TmdbSeasonEpisode, Selectable>();
|
||||
let scrollTop: number;
|
||||
|
||||
const { data: tmdbSeasons, isLoading: isTmdbSeasonsLoading } = useDependantRequest(
|
||||
@@ -58,7 +58,7 @@
|
||||
if (seasonSelectable) seasonSelectable.focus({ setFocusedElement: false });
|
||||
}
|
||||
|
||||
function handleEpisodeMount(event: CustomEvent<Selectable>, tmdbEpisode: TmdbEpisode) {
|
||||
function handleEpisodeMount(event: CustomEvent<Selectable>, tmdbEpisode: TmdbSeasonEpisode) {
|
||||
containers.set(tmdbEpisode, event.detail);
|
||||
const selectable = event.detail;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { type Readable } from 'svelte/store';
|
||||
import { tmdbApi, type TmdbEpisode, type TmdbSeriesFull2 } from '../../apis/tmdb/tmdb-api';
|
||||
import { tmdbApi, type TmdbSeasonEpisode, type TmdbSeriesFull2 } from '../../apis/tmdb/tmdb-api';
|
||||
import Container from '../../../Container.svelte';
|
||||
import { useDependantRequest } from '../../stores/data.store';
|
||||
import type { JellyfinItem } from '../../apis/jellyfin/jellyfin-api';
|
||||
@@ -44,7 +44,7 @@
|
||||
episodeCard.subscribe((e) => e?.focus({ setFocusedElement: false, propagate: false }));
|
||||
});
|
||||
|
||||
function handleOpenEpisodePage(episode: TmdbEpisode) {
|
||||
function handleOpenEpisodePage(episode: TmdbSeasonEpisode) {
|
||||
navigate(`season/${episode.season_number}/episode/${episode.episode_number}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import HeroCarousel from '../HeroCarousel/HeroCarousel.svelte';
|
||||
import DetachedPage from '../DetachedPage/DetachedPage.svelte';
|
||||
import { useActionRequest, useDependantRequest, useRequest } from '../../stores/data.store';
|
||||
import { tmdbApi, type TmdbEpisode } from '../../apis/tmdb/tmdb-api';
|
||||
import { tmdbApi, type TmdbSeasonEpisode } from '../../apis/tmdb/tmdb-api';
|
||||
import { PLATFORM_WEB, TMDB_IMAGES_ORIGINAL } from '../../constants';
|
||||
import classNames from 'classnames';
|
||||
import { DotFilled, Download, ExternalLink, File, Play, Plus } from 'radix-icons-svelte';
|
||||
@@ -48,7 +48,7 @@
|
||||
sonarrApi.addSeriesToSonarr
|
||||
);
|
||||
|
||||
let selectedTmdbEpisode: TmdbEpisode | undefined;
|
||||
let selectedTmdbEpisode: TmdbSeasonEpisode | undefined;
|
||||
const episodeCards = useRegistrar();
|
||||
|
||||
let scrollTop: number;
|
||||
@@ -267,4 +267,4 @@
|
||||
</div>
|
||||
</DetachedPage>
|
||||
|
||||
<Route path="/season/:season/episode/:episode/*" component={EpisodePage} />
|
||||
<Route path="/season/:season/episode/:episode/*" component={EpisodePage} {id} />
|
||||
|
||||
Reference in New Issue
Block a user