diff --git a/src/Container.svelte b/src/Container.svelte index e0dd568..d5b728e 100644 --- a/src/Container.svelte +++ b/src/Container.svelte @@ -31,8 +31,6 @@ export let debugOutline = false; export let focusOnClick = false; - export let registrar: Registrar = () => () => {}; - export let active = true; const { registerer, ...rest } = new Selectable(name) @@ -93,8 +91,6 @@ }) .getStores(); - $: unregister = registrar(rest.container); - export const selectable = rest.container; export const hasFocus = rest.hasFocus; export const hasFocusWithin = rest.hasFocusWithin; @@ -120,7 +116,6 @@ dispatch('mount', rest.container); return () => { - unregister(); rest.container._unmountContainer(); }; }); diff --git a/src/lib/components/CardGrid.svelte b/src/lib/components/CardGrid.svelte index d5b5584..e370c0b 100644 --- a/src/lib/components/CardGrid.svelte +++ b/src/lib/components/CardGrid.svelte @@ -1,18 +1,33 @@ + + + + {#each $tmdbSeasons || [] as season, i} + { + scrollIntoView({ horizontal: 64 })(event); + seasonIndex = i; + }} + registrar={seasonButtons.registrar(i)} + focusOnClick + > + + Season {season.season_number} + + + {/each} + + + {#each $tmdbSeasons?.[seasonIndex]?.episodes || [] as episode} + {@const jellyfinEpisodeId = $jellyfinEpisodes?.find( + (i) => + i.IndexNumber === episode.episode_number && i.ParentIndexNumber === episode.season_number + )?.Id} + playerState.streamJellyfinId(jellyfinEpisodeId) + : undefined} + /> + {/each} + + diff --git a/src/lib/components/SeriesPage/SeriesPage.svelte b/src/lib/components/SeriesPage/SeriesPage.svelte index 4538cdf..33812be 100644 --- a/src/lib/components/SeriesPage/SeriesPage.svelte +++ b/src/lib/components/SeriesPage/SeriesPage.svelte @@ -13,13 +13,13 @@ import { playerState } from '../VideoPlayer/VideoPlayer'; import { modalStack } from '../Modal/modal.store'; import { derived } from 'svelte/store'; - import EpisodeCarousel from './EpisodeCarousel.svelte'; import { scrollIntoView, useRegistrar } from '../../selectable'; import ScrollHelper from '../ScrollHelper.svelte'; import SonarrMediaMangerModal from '../MediaManager/sonarr/SonarrMediaMangerModal.svelte'; import Carousel from '../Carousel/Carousel.svelte'; import TmdbPersonCard from '../PersonCard/TmdbPersonCard.svelte'; import TmdbCard from '../Card/TmdbCard.svelte'; + import EpisodeGrid from './EpisodeGrid.svelte'; export let id: string; @@ -50,7 +50,7 @@ const episodeCards = useRegistrar(); let scrollTop: number; - $: showEpisodeInfo = scrollTop > 140; + $: showEpisodeInfo = false; // scrollTop > 140; @@ -152,7 +152,7 @@ focusOnMount on:navigate={handleGoBack} on:back={handleGoBack} - {registrar} + on:mount={registrar} > {#if $nextJellyfinEpisode} - {#await $tmdbSeries then series} diff --git a/src/lib/selectable.ts b/src/lib/selectable.ts index 169caa7..f61b00a 100644 --- a/src/lib/selectable.ts +++ b/src/lib/selectable.ts @@ -2,7 +2,7 @@ import { derived, get, type Readable, type Writable, writable } from 'svelte/sto import { getScrollParent } from './utils'; export type Registerer = (htmlElement: HTMLElement) => { destroy: () => void }; -export type Registrar = (selectable: Selectable) => () => void; +export type Registrar = (e: CustomEvent) => () => void; export type Direction = 'up' | 'down' | 'left' | 'right'; export type FlowDirection = 'vertical' | 'horizontal'; @@ -815,17 +815,17 @@ export const scrollIntoView: (...args: [Offsets]) => (e: CustomEvent export const useRegistrar = (): { registrar: Registrar } & Readable => { const selectable = writable(); - function registrar(_selectable: Selectable) { + const registrar: Registrar = (e) => { selectable.update((prev) => { if (prev) { - console.warn('Overwriting existing selectable', prev, _selectable); + console.warn('Overwriting existing selectable', prev, e.detail); } - return _selectable; + return e.detail; }); return () => selectable.set(undefined); - } + }; return { registrar, @@ -833,6 +833,48 @@ export const useRegistrar = (): { registrar: Registrar } & Readable(): { + registrar: (key: T) => Registrar; + get: (key: T) => Readable; +} => { + const map = new Map>(); + + const registrar = + (key: T): Registrar => + (e) => { + if (!map.has(key)) { + map.set(key, writable()); + } + + const store = map.get(key); + store?.update((prev) => { + if (prev) { + console.warn('Overwriting existing selectable', prev, e.detail); + } + + return e.detail; + }); + + return () => store?.set(undefined); + }; + + const get = (key: T): Readable => { + const store = map.get(key); + if (!store) { + const newStore = writable(); + map.set(key, newStore); + return newStore; + } else { + return store; + } + }; + + return { + registrar, + get + }; +}; + const sidebar = useRegistrar(); const episodeCards = useRegistrar(); diff --git a/src/lib/utils.ts b/src/lib/utils.ts index b658c63..fb60c41 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,4 +1,4 @@ -import { writable } from 'svelte/store'; +import { type Readable, writable } from 'svelte/store'; export function formatMinutesToTime(minutes: number) { const days = Math.floor(minutes / 60 / 24); @@ -105,3 +105,11 @@ export function getScrollParent( } } } + +export function subscribeUntil(store: Readable, fn: (value: T) => boolean) { + const unsubscribe = store.subscribe((v) => { + if (fn(v)) { + unsubscribe(); + } + }); +}