mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-24 19:11:49 +01:00
responsiveness and loading states
This commit is contained in:
parent
570ca14905
commit
7709ffd90f
@ -16,7 +16,7 @@ interface DropdownProps {
|
|||||||
|
|
||||||
export const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(
|
export const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(
|
||||||
(props: DropdownProps) => (
|
(props: DropdownProps) => (
|
||||||
<div className="relative my-4 w-72 ">
|
<div className="relative my-4 max-w-[18rem]">
|
||||||
<Listbox value={props.selectedItem} onChange={props.setSelectedItem}>
|
<Listbox value={props.selectedItem} onChange={props.setSelectedItem}>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<>
|
<>
|
||||||
@ -37,7 +37,7 @@ export const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(
|
|||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<Listbox.Options className="bg-denim-500 scrollbar-thin scrollbar-track-denim-400 scrollbar-thumb-denim-200 absolute bottom-11 z-10 mt-1 max-h-60 w-72 overflow-auto rounded-md py-1 text-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:bottom-10 sm:text-sm">
|
<Listbox.Options className="bg-denim-500 scrollbar-thin scrollbar-track-denim-400 scrollbar-thumb-denim-200 absolute bottom-11 left-0 right-0 z-10 mt-1 max-h-60 overflow-auto rounded-md py-1 text-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:bottom-10 sm:text-sm">
|
||||||
{props.options.map((opt) => (
|
{props.options.map((opt) => (
|
||||||
<Listbox.Option
|
<Listbox.Option
|
||||||
className={({ active }) =>
|
className={({ active }) =>
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
import { IconPatch } from "components/buttons/IconPatch";
|
||||||
import { Dropdown, OptionItem } from "components/Dropdown";
|
import { Dropdown, OptionItem } from "components/Dropdown";
|
||||||
|
import { Icons } from "components/Icon";
|
||||||
import { WatchedEpisode } from "components/media/WatchedEpisodeButton";
|
import { WatchedEpisode } from "components/media/WatchedEpisodeButton";
|
||||||
import { useLoading } from "hooks/useLoading";
|
import { useLoading } from "hooks/useLoading";
|
||||||
import { serializePortableMedia } from "hooks/usePortableMedia";
|
import { serializePortableMedia } from "hooks/usePortableMedia";
|
||||||
@ -17,6 +19,28 @@ export interface SeasonsProps {
|
|||||||
media: MWMedia;
|
media: MWMedia;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function LoadingSeasons(props: { error?: boolean }) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div className="bg-denim-400 mb-3 mt-5 h-10 w-56 rounded opacity-50" />
|
||||||
|
</div>
|
||||||
|
{!props.error ? (
|
||||||
|
<>
|
||||||
|
<div className="bg-denim-400 mr-3 mb-3 inline-block h-10 w-10 rounded opacity-50" />
|
||||||
|
<div className="bg-denim-400 mr-3 mb-3 inline-block h-10 w-10 rounded opacity-50" />
|
||||||
|
<div className="bg-denim-400 mr-3 mb-3 inline-block h-10 w-10 rounded opacity-50" />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
|
<IconPatch icon={Icons.WARNING} className="text-red-400" />
|
||||||
|
<p>Failed to load seasons and episodes</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function Seasons(props: SeasonsProps) {
|
export function Seasons(props: SeasonsProps) {
|
||||||
const [searchSeasons, loading, error, success] = useLoading(
|
const [searchSeasons, loading, error, success] = useLoading(
|
||||||
(portableMedia: MWPortableMedia) => getSeasonDataFromMedia(portableMedia)
|
(portableMedia: MWPortableMedia) => getSeasonDataFromMedia(portableMedia)
|
||||||
@ -58,8 +82,8 @@ export function Seasons(props: SeasonsProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{loading ? <p>Loading...</p> : null}
|
{loading ? <LoadingSeasons /> : null}
|
||||||
{error ? <p>error!</p> : null}
|
{error ? <LoadingSeasons error /> : null}
|
||||||
{success && seasons.seasons.length ? (
|
{success && seasons.seasons.length ? (
|
||||||
<>
|
<>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
convertMediaToPortable,
|
convertMediaToPortable,
|
||||||
getEpisodeFromMedia,
|
|
||||||
getProviderFromId,
|
getProviderFromId,
|
||||||
MWMediaMeta,
|
MWMediaMeta,
|
||||||
MWMediaType,
|
MWMediaType,
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
import {
|
|
||||||
MWMediaProvider,
|
|
||||||
MWMediaSeasons,
|
|
||||||
MWMediaType,
|
|
||||||
MWPortableMedia,
|
|
||||||
MWQuery,
|
|
||||||
} from "providers/types";
|
|
||||||
|
|
||||||
import { MWMediaStream, MWProviderMediaResult } from "providers";
|
|
||||||
|
|
||||||
export const tempScraper: MWMediaProvider = {
|
|
||||||
id: "temp",
|
|
||||||
enabled: true,
|
|
||||||
type: [MWMediaType.MOVIE, MWMediaType.SERIES],
|
|
||||||
displayName: "temp",
|
|
||||||
|
|
||||||
async getMediaFromPortable(
|
|
||||||
media: MWPortableMedia
|
|
||||||
): Promise<MWProviderMediaResult> {
|
|
||||||
return {
|
|
||||||
...media,
|
|
||||||
year: "1234",
|
|
||||||
title: "temp",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
async searchForMedia(query: MWQuery): Promise<MWProviderMediaResult[]> {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
|
|
||||||
async getStream(media: MWPortableMedia): Promise<MWMediaStream> {
|
|
||||||
return {
|
|
||||||
url: "hi",
|
|
||||||
type: "mp4",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
async getSeasonDataFromMedia(media): Promise<MWMediaSeasons> {
|
|
||||||
return {
|
|
||||||
seasons: [],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
@ -84,13 +84,22 @@ export const theFlixScraper: MWMediaProvider = {
|
|||||||
.querySelectorAll(`script[id="__NEXT_DATA__"]`)
|
.querySelectorAll(`script[id="__NEXT_DATA__"]`)
|
||||||
)[0];
|
)[0];
|
||||||
|
|
||||||
const data = JSON.parse(node.innerHTML).props.pageProps.selectedTv.seasons;
|
let data = JSON.parse(node.innerHTML).props.pageProps.selectedTv.seasons;
|
||||||
|
|
||||||
|
data = data.filter((season: any) => season.releaseDate != null);
|
||||||
|
data = data.map((season: any) => {
|
||||||
|
const episodes = season.episodes.filter(
|
||||||
|
(episode: any) => episode.releaseDate != null
|
||||||
|
);
|
||||||
|
return { ...season, episodes };
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
seasons: data.map((d: any) => ({
|
seasons: data.map((d: any) => ({
|
||||||
sort: d.seasonNumber === 0 ? 999 : d.seasonNumber,
|
sort: d.seasonNumber === 0 ? 999 : d.seasonNumber,
|
||||||
id: d.seasonNumber.toString(),
|
id: d.seasonNumber.toString(),
|
||||||
type: d.seasonNumber === 0 ? "special" : "season",
|
type: d.seasonNumber === 0 ? "special" : "season",
|
||||||
title: d.seasonNumber === 0 ? "Specials" : undefined,
|
title: d.name,
|
||||||
episodes: d.episodes.map((e: any) => ({
|
episodes: d.episodes.map((e: any) => ({
|
||||||
title: e.name,
|
title: e.name,
|
||||||
sort: e.episodeNumber,
|
sort: e.episodeNumber,
|
||||||
|
@ -2,7 +2,7 @@ import { IconPatch } from "components/buttons/IconPatch";
|
|||||||
import { Icons } from "components/Icon";
|
import { Icons } from "components/Icon";
|
||||||
import { Navigation } from "components/layout/Navigation";
|
import { Navigation } from "components/layout/Navigation";
|
||||||
import { Paper } from "components/layout/Paper";
|
import { Paper } from "components/layout/Paper";
|
||||||
import { Seasons } from "components/layout/Seasons";
|
import { LoadingSeasons, Seasons } from "components/layout/Seasons";
|
||||||
import { SkeletonVideoPlayer, VideoPlayer } from "components/media/VideoPlayer";
|
import { SkeletonVideoPlayer, VideoPlayer } from "components/media/VideoPlayer";
|
||||||
import { ArrowLink } from "components/text/ArrowLink";
|
import { ArrowLink } from "components/text/ArrowLink";
|
||||||
import { DotList } from "components/text/DotList";
|
import { DotList } from "components/text/DotList";
|
||||||
@ -110,7 +110,14 @@ function LoadingMediaFooter(props: { error?: boolean }) {
|
|||||||
<span className="bg-denim-400 mr-4 inline-block h-2 w-12 rounded-full" />
|
<span className="bg-denim-400 mr-4 inline-block h-2 w-12 rounded-full" />
|
||||||
<span className="bg-denim-400 mr-4 inline-block h-2 w-12 rounded-full" />
|
<span className="bg-denim-400 mr-4 inline-block h-2 w-12 rounded-full" />
|
||||||
</div>
|
</div>
|
||||||
{props.error ? "error!" : null}
|
{props.error ? (
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
|
<IconPatch icon={Icons.WARNING} className="text-red-400" />
|
||||||
|
<p>Your url may be invalid</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<LoadingSeasons />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
Loading…
Reference in New Issue
Block a user