mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-29 18:16:06 +00: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>(
|
||||
(props: DropdownProps) => (
|
||||
<div className="relative my-4 w-72 ">
|
||||
<div className="relative my-4 max-w-[18rem]">
|
||||
<Listbox value={props.selectedItem} onChange={props.setSelectedItem}>
|
||||
{({ open }) => (
|
||||
<>
|
||||
|
@ -37,7 +37,7 @@ export const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(
|
|||
leaveFrom="opacity-100"
|
||||
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) => (
|
||||
<Listbox.Option
|
||||
className={({ active }) =>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { IconPatch } from "components/buttons/IconPatch";
|
||||
import { Dropdown, OptionItem } from "components/Dropdown";
|
||||
import { Icons } from "components/Icon";
|
||||
import { WatchedEpisode } from "components/media/WatchedEpisodeButton";
|
||||
import { useLoading } from "hooks/useLoading";
|
||||
import { serializePortableMedia } from "hooks/usePortableMedia";
|
||||
|
@ -17,6 +19,28 @@ export interface SeasonsProps {
|
|||
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) {
|
||||
const [searchSeasons, loading, error, success] = useLoading(
|
||||
(portableMedia: MWPortableMedia) => getSeasonDataFromMedia(portableMedia)
|
||||
|
@ -58,8 +82,8 @@ export function Seasons(props: SeasonsProps) {
|
|||
|
||||
return (
|
||||
<>
|
||||
{loading ? <p>Loading...</p> : null}
|
||||
{error ? <p>error!</p> : null}
|
||||
{loading ? <LoadingSeasons /> : null}
|
||||
{error ? <LoadingSeasons error /> : null}
|
||||
{success && seasons.seasons.length ? (
|
||||
<>
|
||||
<Dropdown
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import {
|
||||
convertMediaToPortable,
|
||||
getEpisodeFromMedia,
|
||||
getProviderFromId,
|
||||
MWMediaMeta,
|
||||
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__"]`)
|
||||
)[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 {
|
||||
seasons: data.map((d: any) => ({
|
||||
sort: d.seasonNumber === 0 ? 999 : d.seasonNumber,
|
||||
id: d.seasonNumber.toString(),
|
||||
type: d.seasonNumber === 0 ? "special" : "season",
|
||||
title: d.seasonNumber === 0 ? "Specials" : undefined,
|
||||
title: d.name,
|
||||
episodes: d.episodes.map((e: any) => ({
|
||||
title: e.name,
|
||||
sort: e.episodeNumber,
|
||||
|
|
|
@ -2,7 +2,7 @@ import { IconPatch } from "components/buttons/IconPatch";
|
|||
import { Icons } from "components/Icon";
|
||||
import { Navigation } from "components/layout/Navigation";
|
||||
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 { ArrowLink } from "components/text/ArrowLink";
|
||||
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" />
|
||||
</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>
|
||||
</Paper>
|
||||
|
|
Loading…
Reference in a new issue