diff --git a/src/Container.svelte b/src/Container.svelte index aeb11b5..6d79893 100644 --- a/src/Container.svelte +++ b/src/Container.svelte @@ -1,6 +1,6 @@ + + + + Selectable.focusLeft() + }} + > + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lib/components/HeroShowcase/HeroShowcase.ts b/src/lib/components/HeroShowcase/HeroShowcase.ts new file mode 100644 index 0000000..826542e --- /dev/null +++ b/src/lib/components/HeroShowcase/HeroShowcase.ts @@ -0,0 +1,33 @@ +import type { getTmdbPopularMovies } from '../../apis/tmdb/tmdbApi'; + +export type RatingSource = 'tmdb'; // TODO: Add more rating sources & move elsewhere + +export type ShowcaseItemProps = { + posterUrl: string; + backdropUrl: string; + + trailerUrl?: string; + + title: string; + year?: number; + runtime?: number; + rating?: number; + ratingSource?: RatingSource; + genres: string[]; +}; + +export async function getShowcasePropsFromTmdb( + response: Awaited> +): Promise { + return response.slice(0, 10).map((movie) => ({ + title: movie.title || '', + posterUrl: movie.poster_path || '', + backdropUrl: movie.backdrop_path || '', + rating: movie.vote_average, + genres: [], //(movie as any)?.genres?.map((genre: any) => genre?.name), + year: movie.release_date ? new Date(movie.release_date).getFullYear() : undefined, + runtime: (movie as any).runtime || 0, + ratingSource: 'tmdb', + trailerUrl: '' + })); +} diff --git a/src/lib/components/HeroShowcase/HeroShowcaseBackground.svelte b/src/lib/components/HeroShowcase/HeroShowcaseBackground.svelte new file mode 100644 index 0000000..c4fd409 --- /dev/null +++ b/src/lib/components/HeroShowcase/HeroShowcaseBackground.svelte @@ -0,0 +1,34 @@ + + +
+ {#await items then items} + {#each items as item, index} +
+
+
+ {/each} + {/await} +
diff --git a/src/lib/components/HeroShowcase/PageDots.svelte b/src/lib/components/HeroShowcase/PageDots.svelte new file mode 100644 index 0000000..cec18e9 --- /dev/null +++ b/src/lib/components/HeroShowcase/PageDots.svelte @@ -0,0 +1,41 @@ + + +
+ {#each Array.from({ length }) as _, i} + + + +
onJump(i)}> + +
+ {/each} +
diff --git a/src/lib/components/Sidebar/Sidebar.svelte b/src/lib/components/Sidebar/Sidebar.svelte index 4dc629d..879be1c 100644 --- a/src/lib/components/Sidebar/Sidebar.svelte +++ b/src/lib/components/Sidebar/Sidebar.svelte @@ -3,7 +3,6 @@ import classNames from 'classnames'; import type { Readable } from 'svelte/store'; import Container from '../../../Container.svelte'; - import SidebarItem from './SidebarItem.svelte'; import { useNavigate } from 'svelte-navigator'; let isNavBarOpen: Readable; @@ -14,12 +13,13 @@ const asd2 = ''; const itemContainer = (index: number, _focusIndex: number) => classNames('h-12 flex items-center', { - 'text-amber-300': _focusIndex === index + 'text-amber-300': _focusIndex === index, + 'text-stone-300': _focusIndex !== index }); --> -
+
navigate('/')}>
diff --git a/src/lib/components/Sidebar/SidebarItem.svelte b/src/lib/components/Sidebar/SidebarItem.svelte deleted file mode 100644 index ff542ab..0000000 --- a/src/lib/components/Sidebar/SidebarItem.svelte +++ /dev/null @@ -1,26 +0,0 @@ - - - -
- - -
-
diff --git a/src/lib/pages/BrowseSeriesPage.svelte b/src/lib/pages/BrowseSeriesPage.svelte index 6be2528..229b0f5 100644 --- a/src/lib/pages/BrowseSeriesPage.svelte +++ b/src/lib/pages/BrowseSeriesPage.svelte @@ -1,6 +1,6 @@ - -
- {$_('discover.streamingNow')} -
- {#await fetchNowStreaming()} - - {:then props} - {#each props as prop (prop.tmdbId)} - - - - {/each} - {/await} -
+ + +
+ {$_('discover.streamingNow')} +
+ {#await fetchNowStreaming()} + + {:then props} + {#each props as prop (prop.tmdbId)} + + + + {/each} + {/await} +
+
+ diff --git a/src/lib/selectable.ts b/src/lib/selectable.ts index 086c9e4..9598598 100644 --- a/src/lib/selectable.ts +++ b/src/lib/selectable.ts @@ -4,6 +4,12 @@ export type Registerer = (htmlElement: HTMLElement) => { destroy: () => void }; export type Direction = 'up' | 'down' | 'left' | 'right'; export type FlowDirection = 'vertical' | 'horizontal'; +export type NavigationActions = { + [direction in Direction]?: (selectable: Selectable) => boolean; +} & { + back?: (selectable: Selectable) => boolean; + enter?: (selectable: Selectable) => boolean; +}; export class Selectable { id: symbol; @@ -19,6 +25,7 @@ export class Selectable { }; private focusByDefault: boolean = false; private isInitialized: boolean = false; + private navigationActions: NavigationActions = {}; private direction: FlowDirection = 'vertical'; @@ -299,6 +306,15 @@ export class Selectable { this.htmlElement.click(); } } + + setNavigationActions(actions: NavigationActions) { + this.navigationActions = actions; + return this; + } + + getNavigationActions(): NavigationActions { + return this.navigationActions; + } } export function handleKeyboardNavigation(event: KeyboardEvent) { @@ -317,15 +333,26 @@ export function handleKeyboardNavigation(event: KeyboardEvent) { // console.log('Currently focused object: ', currentlyFocusedObject.name, currentlyFocusedObject); + const navigationActions = currentlyFocusedObject.getNavigationActions(); if (event.key === 'ArrowUp') { - if (Selectable.focusUp()) event.preventDefault(); + if (navigationActions.up && navigationActions.up(currentlyFocusedObject)) + event.preventDefault(); + else if (Selectable.focusUp()) event.preventDefault(); } else if (event.key === 'ArrowDown') { - if (Selectable.focusDown()) event.preventDefault(); + if (navigationActions.down && navigationActions.down(currentlyFocusedObject)) + event.preventDefault(); + else if (Selectable.focusDown()) event.preventDefault(); } else if (event.key === 'ArrowLeft') { - if (Selectable.focusLeft()) event.preventDefault(); + if (navigationActions.left && navigationActions.left(currentlyFocusedObject)) + event.preventDefault(); + else if (Selectable.focusLeft()) event.preventDefault(); } else if (event.key === 'ArrowRight') { - if (Selectable.focusRight()) event.preventDefault(); + if (navigationActions.right && navigationActions.right(currentlyFocusedObject)) + event.preventDefault(); + else if (Selectable.focusRight()) event.preventDefault(); } else if (event.key === 'Enter') { - currentlyFocusedObject.click(); + if (navigationActions.enter && navigationActions.enter(currentlyFocusedObject)) + event.preventDefault(); + else currentlyFocusedObject.click(); } }