mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 04:04:21 -04:00
Make episode list work on mobile
This commit is contained in:
parent
eabf5e1faf
commit
2ac4c434f5
@ -35,7 +35,7 @@ export const Container = <AsProps = ViewProps,>({
|
|||||||
{
|
{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
paddingHorizontal: px(15),
|
paddingHorizontal: px(15),
|
||||||
marginHorizontal: "auto",
|
alignSelf: "center",
|
||||||
width: {
|
width: {
|
||||||
xs: percent(100),
|
xs: percent(100),
|
||||||
sm: px(540),
|
sm: px(540),
|
||||||
|
@ -24,9 +24,9 @@ import { alpha } from "./themes";
|
|||||||
import { ts } from "./utils";
|
import { ts } from "./utils";
|
||||||
|
|
||||||
export const HR = ({
|
export const HR = ({
|
||||||
orientation,
|
orientation = "horizontal",
|
||||||
...props
|
...props
|
||||||
}: { orientation: "vertical" | "horizontal" } & Stylable) => {
|
}: { orientation?: "vertical" | "horizontal" } & Stylable) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -87,5 +87,5 @@ export const ItemGrid = ({
|
|||||||
|
|
||||||
ItemGrid.layout = {
|
ItemGrid.layout = {
|
||||||
size: px(150),
|
size: px(150),
|
||||||
numColumns: { xs: 3, md: 5, xl: 7 },
|
numColumns: { xs: 3, sm: 5, xl: 7 },
|
||||||
} satisfies Layout;
|
} satisfies Layout;
|
||||||
|
@ -22,7 +22,7 @@ import { H6, Image, Link, P, Skeleton, ts } from "@kyoo/primitives";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import { Layout, WithLoading } from "../fetch";
|
import { Layout, WithLoading } from "../fetch";
|
||||||
import { percent, rem, Stylable, useYoshiki, vw } from "yoshiki/native";
|
import { percent, rem, Stylable, useYoshiki } from "yoshiki/native";
|
||||||
|
|
||||||
export const episodeDisplayNumber = (
|
export const episodeDisplayNumber = (
|
||||||
episode: {
|
episode: {
|
||||||
@ -111,5 +111,5 @@ export const EpisodeLine = ({
|
|||||||
};
|
};
|
||||||
EpisodeLine.layout = {
|
EpisodeLine.layout = {
|
||||||
numColumns: 1,
|
numColumns: 1,
|
||||||
size: 100, //vw(18) / (16 / 9) + ts(2),
|
size: 100,
|
||||||
} satisfies Layout;
|
} satisfies Layout;
|
||||||
|
@ -40,7 +40,7 @@ import {
|
|||||||
} from "@kyoo/primitives";
|
} from "@kyoo/primitives";
|
||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { View } from "react-native";
|
import { Platform, View } from "react-native";
|
||||||
import {
|
import {
|
||||||
Theme,
|
Theme,
|
||||||
md,
|
md,
|
||||||
@ -55,8 +55,8 @@ import {
|
|||||||
Stylable,
|
Stylable,
|
||||||
} from "yoshiki/native";
|
} from "yoshiki/native";
|
||||||
import { Fetch } from "../fetch";
|
import { Fetch } from "../fetch";
|
||||||
import PlayArrow from "@material-symbols/svg-400/rounded/play_arrow-fill.svg"
|
import PlayArrow from "@material-symbols/svg-400/rounded/play_arrow-fill.svg";
|
||||||
import Theaters from "@material-symbols/svg-400/rounded/theaters-fill.svg"
|
import Theaters from "@material-symbols/svg-400/rounded/theaters-fill.svg";
|
||||||
|
|
||||||
const TitleLine = ({
|
const TitleLine = ({
|
||||||
isLoading,
|
isLoading,
|
||||||
@ -100,7 +100,10 @@ const TitleLine = ({
|
|||||||
layout={{
|
layout={{
|
||||||
width: { xs: percent(50), md: percent(25) },
|
width: { xs: percent(50), md: percent(25) },
|
||||||
}}
|
}}
|
||||||
{...css({ maxWidth: { xs: px(175), sm: "unset" }, flexShrink: 0 })}
|
{...css({
|
||||||
|
maxWidth: { xs: px(175), sm: Platform.OS === "web" ? "unset" : 99999999 },
|
||||||
|
flexShrink: 0,
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
<View
|
<View
|
||||||
{...css({
|
{...css({
|
||||||
|
@ -20,23 +20,32 @@
|
|||||||
|
|
||||||
import { Episode, EpisodeP, QueryIdentifier, Season } from "@kyoo/models";
|
import { Episode, EpisodeP, QueryIdentifier, Season } from "@kyoo/models";
|
||||||
import { Container, SwitchVariant, ts } from "@kyoo/primitives";
|
import { Container, SwitchVariant, ts } from "@kyoo/primitives";
|
||||||
import Svg, { SvgProps, Path } from "react-native-svg";
|
|
||||||
import { Stylable } from "yoshiki/native";
|
import { Stylable } from "yoshiki/native";
|
||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import { InfiniteFetch } from "../fetch-infinite";
|
import { InfiniteFetch } from "../fetch-infinite";
|
||||||
import { episodeDisplayNumber, EpisodeLine } from "./episode";
|
import { episodeDisplayNumber, EpisodeLine } from "./episode";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ComponentType } from "react";
|
||||||
|
|
||||||
const EpisodeGrid = ({ slug, season }: { slug: string; season: string | number }) => {
|
export const EpisodeList = ({
|
||||||
|
slug,
|
||||||
|
season,
|
||||||
|
Header,
|
||||||
|
}: {
|
||||||
|
slug: string;
|
||||||
|
season: string | number;
|
||||||
|
Header: ComponentType<{ children: JSX.Element }>;
|
||||||
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InfiniteFetch
|
<InfiniteFetch
|
||||||
query={EpisodeGrid.query(slug, season)}
|
query={EpisodeList.query(slug, season)}
|
||||||
placeholderCount={15}
|
placeholderCount={15}
|
||||||
layout={EpisodeLine.layout}
|
layout={EpisodeLine.layout}
|
||||||
empty={t("show.episode-none")}
|
empty={t("show.episode-none")}
|
||||||
divider
|
divider
|
||||||
|
Header={Header}
|
||||||
>
|
>
|
||||||
{(item) => (
|
{(item) => (
|
||||||
<EpisodeLine
|
<EpisodeLine
|
||||||
@ -48,7 +57,7 @@ const EpisodeGrid = ({ slug, season }: { slug: string; season: string | number }
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
EpisodeGrid.query = (slug: string, season: string | number): QueryIdentifier<Episode> => ({
|
EpisodeList.query = (slug: string, season: string | number): QueryIdentifier<Episode> => ({
|
||||||
parser: EpisodeP,
|
parser: EpisodeP,
|
||||||
path: ["shows", slug, "episode"],
|
path: ["shows", slug, "episode"],
|
||||||
params: {
|
params: {
|
||||||
@ -57,47 +66,34 @@ EpisodeGrid.query = (slug: string, season: string | number): QueryIdentifier<Epi
|
|||||||
infinite: true,
|
infinite: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const SvgWave = (props: SvgProps) => (
|
|
||||||
<Svg viewBox="0 372.979 612 52.771" {...props}>
|
|
||||||
<Path d="M0 375.175c68-5.1 136-.85 204 7.948 68 9.052 136 22.652 204 24.777s136-8.075 170-12.878l34-4.973v35.7H0" />
|
|
||||||
</Svg>
|
|
||||||
);
|
|
||||||
|
|
||||||
export const SeasonTab = ({
|
export const SeasonTab = ({
|
||||||
slug,
|
slug,
|
||||||
season,
|
season,
|
||||||
...props
|
...props
|
||||||
}: { slug: string; season: number | string } & Stylable) => {
|
}: { slug: string; season: number | string } & Stylable) => {
|
||||||
// TODO: handle absolute number only shows (without seasons)
|
// TODO: handle absolute number only shows (without seasons)
|
||||||
|
return null;
|
||||||
return (
|
return (
|
||||||
<SwitchVariant>
|
<View>
|
||||||
{({ css, theme }) => (
|
<Container>
|
||||||
<View>
|
{/* <Tabs value={season} onChange={(_, i) => setSeason(i)} aria-label="List of seasons"> */}
|
||||||
<SvgWave fill={theme.background} {...css({ marginTop: { xs: ts(2), md: 0 } })} />
|
{/* {seasons */}
|
||||||
<View {...css({ bg: (theme) => theme.background }, props)}>
|
{/* ? seasons.map((x) => ( */}
|
||||||
<Container>
|
{/* <Tab */}
|
||||||
{/* <Tabs value={season} onChange={(_, i) => setSeason(i)} aria-label="List of seasons"> */}
|
{/* key={x.seasonNumber} */}
|
||||||
{/* {seasons */}
|
{/* label={x.name} */}
|
||||||
{/* ? seasons.map((x) => ( */}
|
{/* value={x.seasonNumber} */}
|
||||||
{/* <Tab */}
|
{/* component={Link} */}
|
||||||
{/* key={x.seasonNumber} */}
|
{/* to={{ query: { ...router.query, season: x.seasonNumber } }} */}
|
||||||
{/* label={x.name} */}
|
{/* shallow */}
|
||||||
{/* value={x.seasonNumber} */}
|
{/* replace */}
|
||||||
{/* component={Link} */}
|
{/* /> */}
|
||||||
{/* to={{ query: { ...router.query, season: x.seasonNumber } }} */}
|
{/* )) */}
|
||||||
{/* shallow */}
|
{/* : [...Array(3)].map((_, i) => ( */}
|
||||||
{/* replace */}
|
{/* <Tab key={i} label={<Skeleton width="5rem" />} value={i + 1} disabled /> */}
|
||||||
{/* /> */}
|
{/* ))} */}
|
||||||
{/* )) */}
|
{/* </Tabs> */}
|
||||||
{/* : [...Array(3)].map((_, i) => ( */}
|
</Container>
|
||||||
{/* <Tab key={i} label={<Skeleton width="5rem" />} value={i + 1} disabled /> */}
|
</View>
|
||||||
{/* ))} */}
|
|
||||||
{/* </Tabs> */}
|
|
||||||
<EpisodeGrid slug={slug} season={season} />
|
|
||||||
</Container>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</SwitchVariant>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -19,11 +19,27 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { QueryIdentifier, QueryPage, Show, ShowP } from "@kyoo/models";
|
import { QueryIdentifier, QueryPage, Show, ShowP } from "@kyoo/models";
|
||||||
import { Platform, ScrollView } from "react-native";
|
import { Platform, ScrollView, View, ViewProps } from "react-native";
|
||||||
import { useYoshiki } from "yoshiki/native";
|
import { percent, useYoshiki, vh } from "yoshiki/native";
|
||||||
import { TransparentLayout } from "../layout";
|
import { TransparentLayout } from "../layout";
|
||||||
import { SeasonTab } from "./season";
|
import { EpisodeList, SeasonTab } from "./season";
|
||||||
import { Header } from "./header";
|
import { Header } from "./header";
|
||||||
|
import Svg, { Path, SvgProps } from "react-native-svg";
|
||||||
|
import { Container, SwitchVariant } from "@kyoo/primitives";
|
||||||
|
|
||||||
|
const SvgWave = (props: SvgProps) => {
|
||||||
|
const { css } = useYoshiki();
|
||||||
|
const width = 612;
|
||||||
|
const height = 52.771;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View {...css({ width: percent(100), aspectRatio: width / height })}>
|
||||||
|
<Svg width="100%" height="100%" viewBox="0 372.979 612 52.771" fill="black" {...props}>
|
||||||
|
<Path d="M0,375.175c68,-5.1,136,-0.85,204,7.948c68,9.052,136,22.652,204,24.777s136,-8.075,170,-12.878l34,-4.973v35.7h-612" />
|
||||||
|
</Svg>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const query = (slug: string): QueryIdentifier<Show> => ({
|
const query = (slug: string): QueryIdentifier<Show> => ({
|
||||||
parser: ShowP,
|
parser: ShowP,
|
||||||
@ -34,14 +50,39 @@ const query = (slug: string): QueryIdentifier<Show> => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const ShowDetails: QueryPage<{ slug: string; season: string }> = ({ slug, season }) => {
|
export const ShowDetails: QueryPage<{ slug: string; season: string }> = ({ slug, season }) => {
|
||||||
const { css } = useYoshiki();
|
const { css, theme } = useYoshiki();
|
||||||
|
|
||||||
return (
|
const ShowHeader = ({ children, ...props }: ViewProps) => (
|
||||||
<ScrollView {...css(Platform.OS === "web" && { overflow: "overlay" as any })}>
|
<View
|
||||||
|
{...css(
|
||||||
|
[
|
||||||
|
{ bg: (theme) => theme.background },
|
||||||
|
Platform.OS === "web" && { flexGrow: 1, flexShrink: 1, overflow: "overlay" as any },
|
||||||
|
],
|
||||||
|
props,
|
||||||
|
)}
|
||||||
|
>
|
||||||
<Header slug={slug} query={query(slug)} />
|
<Header slug={slug} query={query(slug)} />
|
||||||
{/* <Staff slug={slug} /> */}
|
{/* <Staff slug={slug} /> */}
|
||||||
<SeasonTab slug={slug} season={season} />
|
<SvgWave
|
||||||
</ScrollView>
|
fill={theme.variant.background}
|
||||||
|
{...css({ flexShrink: 0, flexGrow: 1, display: "flex" })}
|
||||||
|
/>
|
||||||
|
{/* <SeasonTab slug={slug} season={season} /> */}
|
||||||
|
<View {...css({ bg: theme.variant.background })}>
|
||||||
|
<Container>{children}</Container>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SwitchVariant>
|
||||||
|
{({ css, theme }) => (
|
||||||
|
<View {...css({ bg: theme.background, flex: 1 })}>
|
||||||
|
<EpisodeList slug={slug} season={season} Header={ShowHeader} />
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</SwitchVariant>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
import { Page, QueryIdentifier, useInfiniteFetch } from "@kyoo/models";
|
import { Page, QueryIdentifier, useInfiniteFetch } from "@kyoo/models";
|
||||||
import { useBreakpointMap, HR } from "@kyoo/primitives";
|
import { useBreakpointMap, HR } from "@kyoo/primitives";
|
||||||
import { FlashList } from "@shopify/flash-list";
|
import { FlashList } from "@shopify/flash-list";
|
||||||
import { ReactElement } from "react";
|
import { ComponentType, ReactElement } from "react";
|
||||||
import { EmptyView, ErrorView, Layout, WithLoading } from "./fetch";
|
import { EmptyView, ErrorView, Layout, WithLoading } from "./fetch";
|
||||||
|
|
||||||
export const InfiniteFetch = <Data,>({
|
export const InfiniteFetch = <Data,>({
|
||||||
@ -32,6 +32,7 @@ export const InfiniteFetch = <Data,>({
|
|||||||
layout,
|
layout,
|
||||||
empty,
|
empty,
|
||||||
divider = false,
|
divider = false,
|
||||||
|
Header,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
query: QueryIdentifier<Data>;
|
query: QueryIdentifier<Data>;
|
||||||
@ -43,7 +44,8 @@ export const InfiniteFetch = <Data,>({
|
|||||||
i: number,
|
i: number,
|
||||||
) => ReactElement | null;
|
) => ReactElement | null;
|
||||||
empty?: string | JSX.Element;
|
empty?: string | JSX.Element;
|
||||||
divider?: boolean | JSX.Element;
|
divider?: boolean | ComponentType;
|
||||||
|
Header?: ComponentType<{ children: JSX.Element }>;
|
||||||
}): JSX.Element | null => {
|
}): JSX.Element | null => {
|
||||||
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
||||||
|
|
||||||
@ -57,26 +59,14 @@ export const InfiniteFetch = <Data,>({
|
|||||||
return <EmptyView message={empty} />;
|
return <EmptyView message={empty} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const placeholders = [
|
||||||
|
...Array(items ? numColumns - (items.length % numColumns) + numColumns : placeholderCount),
|
||||||
|
].map((_, i) => ({ id: `gen${i}`, isLoading: true } as Data));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FlashList
|
<FlashList
|
||||||
renderItem={({ item, index }) => (
|
renderItem={({ item, index }) => children({ isLoading: false, ...item } as any, index)}
|
||||||
<>
|
data={hasNextPage !== false ? [...(items || []), ...placeholders] : items}
|
||||||
{(divider === true && index !== 0) ? <HR orientation={horizontal ? "vertical" : "horizontal"} /> : divider}
|
|
||||||
{children({ isLoading: false, ...item } as any, index)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
data={
|
|
||||||
hasNextPage
|
|
||||||
? [
|
|
||||||
...(items || []),
|
|
||||||
...[
|
|
||||||
...Array(
|
|
||||||
items ? numColumns - (items.length % numColumns) + numColumns : placeholderCount,
|
|
||||||
),
|
|
||||||
].map((_, i) => ({ id: `gen${i}`, isLoading: true } as Data)),
|
|
||||||
]
|
|
||||||
: items
|
|
||||||
}
|
|
||||||
horizontal={horizontal}
|
horizontal={horizontal}
|
||||||
keyExtractor={(item: any) => item.id?.toString()}
|
keyExtractor={(item: any) => item.id?.toString()}
|
||||||
numColumns={numColumns}
|
numColumns={numColumns}
|
||||||
@ -85,6 +75,8 @@ export const InfiniteFetch = <Data,>({
|
|||||||
onEndReachedThreshold={0.5}
|
onEndReachedThreshold={0.5}
|
||||||
onRefresh={refetch}
|
onRefresh={refetch}
|
||||||
refreshing={isRefetching}
|
refreshing={isRefetching}
|
||||||
|
ItemSeparatorComponent={divider === true ? HR : divider || null}
|
||||||
|
ListHeaderComponent={Header}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
import { Page, QueryIdentifier, useInfiniteFetch } from "@kyoo/models";
|
import { Page, QueryIdentifier, useInfiniteFetch } from "@kyoo/models";
|
||||||
import { HR } from "@kyoo/primitives";
|
import { HR } from "@kyoo/primitives";
|
||||||
import { Fragment, ReactElement, useRef } from "react";
|
import { ComponentType, Fragment, ReactElement, useRef } from "react";
|
||||||
import { Stylable, useYoshiki } from "yoshiki";
|
import { Stylable, useYoshiki } from "yoshiki";
|
||||||
import { EmptyView, ErrorView, Layout, WithLoading } from "./fetch";
|
import { EmptyView, ErrorView, Layout, WithLoading } from "./fetch";
|
||||||
|
|
||||||
@ -93,7 +93,8 @@ export const InfiniteFetch = <Data,>({
|
|||||||
layout,
|
layout,
|
||||||
horizontal = false,
|
horizontal = false,
|
||||||
empty,
|
empty,
|
||||||
divider = false,
|
divider: Divider = false,
|
||||||
|
Header,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
query: QueryIdentifier<Data>;
|
query: QueryIdentifier<Data>;
|
||||||
@ -105,7 +106,8 @@ export const InfiniteFetch = <Data,>({
|
|||||||
i: number,
|
i: number,
|
||||||
) => ReactElement | null;
|
) => ReactElement | null;
|
||||||
empty?: string | JSX.Element;
|
empty?: string | JSX.Element;
|
||||||
divider?: boolean | JSX.Element;
|
divider?: boolean | ComponentType;
|
||||||
|
Header?: ComponentType<{ children: JSX.Element }>;
|
||||||
}): JSX.Element | null => {
|
}): JSX.Element | null => {
|
||||||
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
||||||
|
|
||||||
@ -118,7 +120,7 @@ export const InfiniteFetch = <Data,>({
|
|||||||
return <EmptyView message={empty} />;
|
return <EmptyView message={empty} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const list = (
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
layout={grid ? "grid" : horizontal ? "horizontal" : "vertical"}
|
layout={grid ? "grid" : horizontal ? "horizontal" : "vertical"}
|
||||||
loadMore={fetchNextPage}
|
loadMore={fetchNextPage}
|
||||||
@ -126,7 +128,7 @@ export const InfiniteFetch = <Data,>({
|
|||||||
isFetching={isFetching}
|
isFetching={isFetching}
|
||||||
loader={[...Array(12)].map((_, i) => (
|
loader={[...Array(12)].map((_, i) => (
|
||||||
<Fragment key={i.toString()}>
|
<Fragment key={i.toString()}>
|
||||||
{(divider === true && i !== 0) ? <HR orientation={horizontal ? "vertical" : "horizontal"} /> : divider}
|
{Divider && i !== 0 && (Divider === true ? <HR /> : <Divider />)}
|
||||||
{children({ isLoading: true } as any, i)}
|
{children({ isLoading: true } as any, i)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
@ -134,10 +136,12 @@ export const InfiniteFetch = <Data,>({
|
|||||||
>
|
>
|
||||||
{items?.map((item, i) => (
|
{items?.map((item, i) => (
|
||||||
<Fragment key={(item as any).id?.toString()}>
|
<Fragment key={(item as any).id?.toString()}>
|
||||||
{(divider === true && i !== 0) ? <HR orientation={horizontal ? "vertical" : "horizontal"} /> : divider}
|
{Divider && i !== 0 && (Divider === true ? <HR /> : <Divider />)}
|
||||||
{children({ ...item, isLoading: false } as any, i)}
|
{children({ ...item, isLoading: false } as any, i)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return Header ? <Header>{list}</Header> : list;
|
||||||
};
|
};
|
||||||
|
@ -48,10 +48,12 @@ export const Fetch = <Data,>({
|
|||||||
const { data, error } = useFetch(query);
|
const { data, error } = useFetch(query);
|
||||||
|
|
||||||
if (error) return <ErrorView error={error} />;
|
if (error) return <ErrorView error={error} />;
|
||||||
if (!data)
|
if (!data) {
|
||||||
return (
|
const placeholders = [...Array(placeholderCount)].map((_, i) =>
|
||||||
<>{[...Array(placeholderCount)].map((_, i) => children({ isLoading: true } as any, i))}</>
|
children({ isLoading: true } as any, i),
|
||||||
);
|
);
|
||||||
|
return <>{placeholderCount === 1 ? placeholders[0] : placeholders}</>;
|
||||||
|
}
|
||||||
if (!isPage<object>(data))
|
if (!isPage<object>(data))
|
||||||
return children(data ? { ...data, isLoading: false } : ({ isLoading: true } as any), 0);
|
return children(data ? { ...data, isLoading: false } : ({ isLoading: true } as any), 0);
|
||||||
return <>{data.items.map((item, i) => children({ ...item, isLoading: false } as any, i))}</>;
|
return <>{data.items.map((item, i) => children({ ...item, isLoading: false } as any, i))}</>;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user