mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-31 14:33:50 -04:00
wip: Series details
This commit is contained in:
parent
e1059aceed
commit
8f80d6c96d
@ -1,35 +0,0 @@
|
||||
import { z } from "zod";
|
||||
import { ImagesP, ResourceP } from "../traits";
|
||||
import { zdate } from "../utils";
|
||||
|
||||
export const SeasonP = ResourceP("season").merge(ImagesP).extend({
|
||||
/**
|
||||
* The name of this season.
|
||||
*/
|
||||
name: z.string(),
|
||||
/**
|
||||
* The number of this season. This can be set to 0 to indicate specials.
|
||||
*/
|
||||
seasonNumber: z.number(),
|
||||
/**
|
||||
* A quick overview of this season.
|
||||
*/
|
||||
overview: z.string().nullable(),
|
||||
/**
|
||||
* The starting air date of this season.
|
||||
*/
|
||||
startDate: zdate().nullable(),
|
||||
/**
|
||||
* The ending date of this season.
|
||||
*/
|
||||
endDate: zdate().nullable(),
|
||||
/**
|
||||
* The number of episodes available on kyoo of this season.
|
||||
*/
|
||||
episodesCount: z.number(),
|
||||
});
|
||||
|
||||
/**
|
||||
* A season of a Show.
|
||||
*/
|
||||
export type Season = z.infer<typeof SeasonP>;
|
31
front/src/models/season.ts
Normal file
31
front/src/models/season.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { z } from "zod/v4";
|
||||
import { KImage } from "./utils/images";
|
||||
import { zdate } from "./utils/utils";
|
||||
|
||||
export const Season = z.object({
|
||||
id: z.string(),
|
||||
slug: z.string(),
|
||||
seasonNumber: z.number().gte(0),
|
||||
name: z.string().nullable(),
|
||||
description: z.string().nullable(),
|
||||
entryCount: z.number(),
|
||||
startAir: zdate().nullable(),
|
||||
endAir: zdate().nullable(),
|
||||
externalId: z.record(
|
||||
z.string(),
|
||||
z.object({
|
||||
serieId: z.string(),
|
||||
season: z.number(),
|
||||
link: z.string().nullable(),
|
||||
}),
|
||||
),
|
||||
|
||||
poster: KImage.nullable(),
|
||||
thumbnail: KImage.nullable(),
|
||||
banner: KImage.nullable(),
|
||||
|
||||
createdAt: zdate(),
|
||||
updatedAt: zdate(),
|
||||
});
|
||||
|
||||
export type Season = z.infer<typeof Season>;
|
@ -1 +1,2 @@
|
||||
export { MovieDetails } from "./movie";
|
||||
export { SerieDetails } from "./serie";
|
||||
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Kyoo - A portable and vast media library solution.
|
||||
* Copyright (c) Kyoo.
|
||||
*
|
||||
* See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
*
|
||||
* Kyoo is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* Kyoo is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Avatar, Link, P, Skeleton, SubP } from "@kyoo/primitives";
|
||||
import { type Stylable, useYoshiki } from "yoshiki/native";
|
||||
|
||||
export const PersonAvatar = ({
|
||||
slug,
|
||||
name,
|
||||
role,
|
||||
poster,
|
||||
isLoading,
|
||||
...props
|
||||
}: {
|
||||
isLoading: boolean;
|
||||
slug?: string;
|
||||
name?: string;
|
||||
role?: string;
|
||||
poster?: string | null;
|
||||
} & Stylable) => {
|
||||
const { css } = useYoshiki();
|
||||
|
||||
return (
|
||||
<Link href={slug ? `/person/${slug}` : ""} {...props}>
|
||||
<Avatar src={poster} alt={name} size={PersonAvatar.width} fill />
|
||||
<Skeleton>{isLoading || <P {...css({ textAlign: "center" })}>{name}</P>}</Skeleton>
|
||||
{(isLoading || role) && (
|
||||
<Skeleton>{isLoading || <SubP {...css({ textAlign: "center" })}>{role}</SubP>}</Skeleton>
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
PersonAvatar.width = 300;
|
@ -1,38 +1,22 @@
|
||||
/*
|
||||
* Kyoo - A portable and vast media library solution.
|
||||
* Copyright (c) Kyoo.
|
||||
*
|
||||
* See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
*
|
||||
* Kyoo is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* Kyoo is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
type Episode,
|
||||
EpisodeP,
|
||||
type QueryIdentifier,
|
||||
type Season,
|
||||
SeasonP,
|
||||
useInfiniteFetch,
|
||||
} from "@kyoo/models";
|
||||
import { H2, HR, IconButton, Menu, P, Skeleton, tooltip, ts, usePageStyle } from "@kyoo/primitives";
|
||||
import MenuIcon from "@material-symbols/svg-400/rounded/menu-fill.svg";
|
||||
import type { ComponentType } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { View } from "react-native";
|
||||
import { rem, useYoshiki } from "yoshiki/native";
|
||||
import { InfiniteFetch } from "../fetch-infinite";
|
||||
import { type Episode, type Season, useInfiniteFetch } from "~/models";
|
||||
import {
|
||||
H2,
|
||||
HR,
|
||||
IconButton,
|
||||
Menu,
|
||||
P,
|
||||
Skeleton,
|
||||
tooltip,
|
||||
ts,
|
||||
usePageStyle,
|
||||
} from "~/primitives";
|
||||
import type { QueryIdentifier } from "~/query";
|
||||
import { InfiniteFetch } from "~/query/fetch-infinite";
|
||||
import { EpisodeLine, episodeDisplayNumber } from "./episode";
|
||||
|
||||
type SeasonProcessed = Season & { href: string };
|
||||
@ -63,10 +47,21 @@ export const SeasonHeader = ({
|
||||
>
|
||||
{seasonNumber}
|
||||
</P>
|
||||
<H2 {...css({ marginX: ts(1), fontSize: rem(1.5), flexGrow: 1, flexShrink: 1 })}>
|
||||
<H2
|
||||
{...css({
|
||||
marginX: ts(1),
|
||||
fontSize: rem(1.5),
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
})}
|
||||
>
|
||||
{name ?? t("show.season", { number: seasonNumber })}
|
||||
</H2>
|
||||
<Menu Trigger={IconButton} icon={MenuIcon} {...tooltip(t("show.jumpToSeason"))}>
|
||||
<Menu
|
||||
Trigger={IconButton}
|
||||
icon={MenuIcon}
|
||||
{...tooltip(t("show.jumpToSeason"))}
|
||||
>
|
||||
{seasons
|
||||
?.filter((x) => x.episodesCount > 0)
|
||||
.map((x) => (
|
||||
@ -90,7 +85,13 @@ SeasonHeader.Loader = () => {
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View {...css({ flexDirection: "row", marginX: ts(1), justifyContent: "space-between" })}>
|
||||
<View
|
||||
{...css({
|
||||
flexDirection: "row",
|
||||
marginX: ts(1),
|
||||
justifyContent: "space-between",
|
||||
})}
|
||||
>
|
||||
<View {...css({ flexDirection: "row", alignItems: "center" })}>
|
||||
<Skeleton
|
||||
variant="custom"
|
||||
@ -101,7 +102,9 @@ SeasonHeader.Loader = () => {
|
||||
height: rem(1.5),
|
||||
})}
|
||||
/>
|
||||
<Skeleton {...css({ marginX: ts(1), width: rem(12), height: rem(2) })} />
|
||||
<Skeleton
|
||||
{...css({ marginX: ts(1), width: rem(12), height: rem(2) })}
|
||||
/>
|
||||
</View>
|
||||
<IconButton icon={MenuIcon} disabled />
|
||||
</View>
|
||||
@ -110,18 +113,20 @@ SeasonHeader.Loader = () => {
|
||||
);
|
||||
};
|
||||
|
||||
SeasonHeader.query = (slug: string): QueryIdentifier<Season, SeasonProcessed> => ({
|
||||
parser: SeasonP,
|
||||
path: ["show", slug, "seasons"],
|
||||
SeasonHeader.query = (slug: string): QueryIdentifier<Season> => ({
|
||||
parser: Season,
|
||||
path: ["series", slug, "seasons"],
|
||||
params: {
|
||||
// Fetch all seasons at one, there won't be hundred of thems anyways.
|
||||
limit: 0,
|
||||
fields: ["episodesCount"],
|
||||
},
|
||||
infinite: {
|
||||
value: true,
|
||||
map: (seasons) =>
|
||||
seasons.map((x) => ({ ...x, href: `/show/${slug}?season=${x.seasonNumber}` })),
|
||||
seasons.map((x) => ({
|
||||
...x,
|
||||
href: `/show/${slug}?season=${x.seasonNumber}`,
|
||||
})),
|
||||
},
|
||||
});
|
||||
|
||||
@ -150,7 +155,9 @@ export const EpisodeList = <Props,>({
|
||||
divider
|
||||
Header={Header}
|
||||
headerProps={headerProps}
|
||||
getItemType={(item) => (!item || item.firstOfSeason ? "withHeader" : "normal")}
|
||||
getItemType={(item) =>
|
||||
!item || item.firstOfSeason ? "withHeader" : "normal"
|
||||
}
|
||||
contentContainerStyle={pageStyle}
|
||||
placeholderCount={5}
|
||||
Render={({ item }) => {
|
||||
@ -161,7 +168,11 @@ export const EpisodeList = <Props,>({
|
||||
<>
|
||||
{item.firstOfSeason &&
|
||||
(sea ? (
|
||||
<SeasonHeader name={sea.name} seasonNumber={sea.seasonNumber} seasons={seasons} />
|
||||
<SeasonHeader
|
||||
name={sea.name}
|
||||
seasonNumber={sea.seasonNumber}
|
||||
seasons={seasons}
|
||||
/>
|
||||
) : (
|
||||
<SeasonHeader.Loader />
|
||||
))}
|
||||
|
127
front/src/ui/details/serie.tsx
Normal file
127
front/src/ui/details/serie.tsx
Normal file
@ -0,0 +1,127 @@
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Platform, View } from "react-native";
|
||||
import Svg, { Path, type SvgProps } from "react-native-svg";
|
||||
import { percent, useYoshiki } from "yoshiki/native";
|
||||
import { Container, focusReset, H2, SwitchVariant, ts } from "~/primitives";
|
||||
import { useQueryState } from "~/utils";
|
||||
import { EpisodeLine, episodeDisplayNumber } from "./episode";
|
||||
import { Header } from "./header";
|
||||
import { EpisodeList } from "./season";
|
||||
|
||||
export 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>
|
||||
);
|
||||
};
|
||||
|
||||
export const ShowWatchStatusCard = ({
|
||||
watchedPercent,
|
||||
status,
|
||||
nextEpisode,
|
||||
}: ShowWatchStatus) => {
|
||||
const { t } = useTranslation();
|
||||
const [focused, setFocus] = useState(false);
|
||||
|
||||
if (!nextEpisode) return null;
|
||||
|
||||
return (
|
||||
<SwitchVariant>
|
||||
{({ css }) => (
|
||||
<Container
|
||||
{...css([
|
||||
{
|
||||
marginY: ts(2),
|
||||
borderRadius: 16,
|
||||
overflow: "hidden",
|
||||
borderWidth: ts(0.5),
|
||||
borderStyle: "solid",
|
||||
borderColor: (theme) => theme.background,
|
||||
backgroundColor: (theme) => theme.background,
|
||||
},
|
||||
focused && {
|
||||
...focusReset,
|
||||
borderColor: (theme) => theme.accent,
|
||||
},
|
||||
])}
|
||||
>
|
||||
<H2 {...css({ marginLeft: ts(2) })}>{t("show.nextUp")}</H2>
|
||||
<EpisodeLine
|
||||
{...nextEpisode}
|
||||
showSlug={null}
|
||||
watchedPercent={watchedPercent || null}
|
||||
watchedStatus={status || null}
|
||||
displayNumber={episodeDisplayNumber(nextEpisode)}
|
||||
onHoverIn={() => setFocus(true)}
|
||||
onHoverOut={() => setFocus(false)}
|
||||
onFocus={() => setFocus(true)}
|
||||
onBlur={() => setFocus(false)}
|
||||
/>
|
||||
</Container>
|
||||
)}
|
||||
</SwitchVariant>
|
||||
);
|
||||
};
|
||||
|
||||
const ShowHeader = ({ children, slug, ...props }) => {
|
||||
const { css, theme } = useYoshiki();
|
||||
|
||||
return (
|
||||
<View
|
||||
{...css(
|
||||
[
|
||||
{ bg: (theme) => theme.background },
|
||||
Platform.OS === "web" && {
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
// @ts-ignore Web only property
|
||||
overflowY: "auto" as any,
|
||||
},
|
||||
],
|
||||
props,
|
||||
)}
|
||||
>
|
||||
<Header kind="serie" slug={slug} />
|
||||
{/* <DetailsCollections type="serie" slug={slug} /> */}
|
||||
{/* <Staff slug={slug} /> */}
|
||||
<SvgWave
|
||||
fill={theme.variant.background}
|
||||
{...css({ flexShrink: 0, flexGrow: 1, display: "flex" })}
|
||||
/>
|
||||
<View {...css({ bg: theme.variant.background })}>
|
||||
<Container>{children}</Container>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
)
|
||||
|
||||
export const ShowDetails = () => {
|
||||
const { css, theme } = useYoshiki();
|
||||
const [slug] = useQueryState("slug", undefined!);
|
||||
|
||||
return (
|
||||
<View {...css({ bg: theme.variant.background, flex: 1 })}>
|
||||
<EpisodeList
|
||||
slug={slug}
|
||||
season={season}
|
||||
Header={ShowHeader}
|
||||
headerProps={{ slug }}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Kyoo - A portable and vast media library solution.
|
||||
* Copyright (c) Kyoo.
|
||||
*
|
||||
* See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
*
|
||||
* Kyoo is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* Kyoo is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
type QueryIdentifier,
|
||||
type QueryPage,
|
||||
type Show,
|
||||
ShowP,
|
||||
type ShowWatchStatus,
|
||||
} from "@kyoo/models";
|
||||
import { Container, H2, SwitchVariant, focusReset, ts } from "@kyoo/primitives";
|
||||
import { forwardRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Platform, View, type ViewProps } from "react-native";
|
||||
import Svg, { Path, type SvgProps } from "react-native-svg";
|
||||
import { percent, useYoshiki } from "yoshiki/native";
|
||||
import { DefaultLayout } from "../../../packages/ui/src/layoutpackages/ui/src/layout";
|
||||
import { DetailsCollections } from "./collection";
|
||||
import { EpisodeLine, episodeDisplayNumber } from "./episode";
|
||||
import { Header } from "./header";
|
||||
import { EpisodeList, SeasonHeader } from "./season";
|
||||
|
||||
export 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>
|
||||
);
|
||||
};
|
||||
|
||||
export const ShowWatchStatusCard = ({ watchedPercent, status, nextEpisode }: ShowWatchStatus) => {
|
||||
const { t } = useTranslation();
|
||||
const [focused, setFocus] = useState(false);
|
||||
|
||||
if (!nextEpisode) return null;
|
||||
|
||||
return (
|
||||
<SwitchVariant>
|
||||
{({ css }) => (
|
||||
<Container
|
||||
{...css([
|
||||
{
|
||||
marginY: ts(2),
|
||||
borderRadius: 16,
|
||||
overflow: "hidden",
|
||||
borderWidth: ts(0.5),
|
||||
borderStyle: "solid",
|
||||
borderColor: (theme) => theme.background,
|
||||
backgroundColor: (theme) => theme.background,
|
||||
},
|
||||
focused && {
|
||||
...focusReset,
|
||||
borderColor: (theme) => theme.accent,
|
||||
},
|
||||
])}
|
||||
>
|
||||
<H2 {...css({ marginLeft: ts(2) })}>{t("show.nextUp")}</H2>
|
||||
<EpisodeLine
|
||||
{...nextEpisode}
|
||||
showSlug={null}
|
||||
watchedPercent={watchedPercent || null}
|
||||
watchedStatus={status || null}
|
||||
displayNumber={episodeDisplayNumber(nextEpisode)}
|
||||
onHoverIn={() => setFocus(true)}
|
||||
onHoverOut={() => setFocus(false)}
|
||||
onFocus={() => setFocus(true)}
|
||||
onBlur={() => setFocus(false)}
|
||||
/>
|
||||
</Container>
|
||||
)}
|
||||
</SwitchVariant>
|
||||
);
|
||||
};
|
||||
|
||||
const ShowHeader = forwardRef<View, ViewProps & { slug: string }>(function ShowHeader(
|
||||
{ children, slug, ...props },
|
||||
ref,
|
||||
) {
|
||||
const { css, theme } = useYoshiki();
|
||||
|
||||
return (
|
||||
<View
|
||||
ref={ref}
|
||||
{...css(
|
||||
[
|
||||
{ bg: (theme) => theme.background },
|
||||
Platform.OS === "web" && {
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
// @ts-ignore Web only property
|
||||
overflowY: "auto" as any,
|
||||
},
|
||||
],
|
||||
props,
|
||||
)}
|
||||
>
|
||||
<Header type="show" query={query(slug)} />
|
||||
<DetailsCollections type="show" slug={slug} />
|
||||
{/* <Staff slug={slug} /> */}
|
||||
<SvgWave
|
||||
fill={theme.variant.background}
|
||||
{...css({ flexShrink: 0, flexGrow: 1, display: "flex" })}
|
||||
/>
|
||||
<View {...css({ bg: theme.variant.background })}>
|
||||
<Container>{children}</Container>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
||||
const query = (slug: string): QueryIdentifier<Show> => ({
|
||||
parser: ShowP,
|
||||
path: ["show", slug],
|
||||
params: {
|
||||
fields: ["studio", "firstEpisode", "watchStatus"],
|
||||
},
|
||||
});
|
||||
|
||||
export const ShowDetails: QueryPage<{ slug: string; season: string }> = ({ slug, season }) => {
|
||||
const { css, theme } = useYoshiki();
|
||||
return (
|
||||
<View {...css({ bg: theme.variant.background, flex: 1 })}>
|
||||
<EpisodeList slug={slug} season={season} Header={ShowHeader} headerProps={{ slug }} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
ShowDetails.getFetchUrls = ({ slug, season }) => [
|
||||
query(slug),
|
||||
DetailsCollections.query("show", slug),
|
||||
// ShowStaff.query(slug),
|
||||
EpisodeList.query(slug, season),
|
||||
SeasonHeader.query(slug),
|
||||
];
|
||||
|
||||
ShowDetails.getLayout = { Layout: DefaultLayout, props: { transparent: true } };
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Kyoo - A portable and vast media library solution.
|
||||
* Copyright (c) Kyoo.
|
||||
*
|
||||
* See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
*
|
||||
* Kyoo is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* Kyoo is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// import { Person, PersonP, QueryIdentifier } from "@kyoo/models";
|
||||
// import { useTranslation } from "react-i18next";
|
||||
// import { InfiniteFetch } from "../fetch-infinite";
|
||||
// import { PersonAvatar } from "./person";
|
||||
|
||||
// export const Staff = ({ slug }: { slug: string }) => {
|
||||
// const { t } = useTranslation();
|
||||
//
|
||||
// return (
|
||||
// <InfiniteFetch
|
||||
// query={Staff.query(slug)}
|
||||
// horizontal
|
||||
// layout={{ numColumns: 1, size: PersonAvatar.width }}
|
||||
// empty={t("show.staff-none")}
|
||||
// >
|
||||
// {(item, key) => (
|
||||
// <PersonAvatar
|
||||
// key={key}
|
||||
// isLoading={item.isLoading}
|
||||
// slug={item?.slug}
|
||||
// name={item?.name}
|
||||
// role={item?.type ? `${item?.type} (${item?.role})` : item?.role}
|
||||
// poster={item?.poster}
|
||||
// // sx={{ width: { xs: "7rem", lg: "10rem" }, flexShrink: 0, px: 2 }}
|
||||
// />
|
||||
// )}
|
||||
// </InfiniteFetch>
|
||||
// );
|
||||
// };
|
||||
//
|
||||
// Staff.query = (slug: string): QueryIdentifier<Person> => ({
|
||||
// parser: PersonP,
|
||||
// path: ["show", slug, "people"],
|
||||
// infinite: true,
|
||||
// });
|
Loading…
x
Reference in New Issue
Block a user