mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-10-31 10:37:13 -04:00 
			
		
		
		
	Split loaders for most items on the main page
This commit is contained in:
		
							parent
							
								
									2756397898
								
							
						
					
					
						commit
						393c58b10a
					
				| @ -213,7 +213,7 @@ export const ItemGrid = ({ | |||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| ItemGrid.Loader = (props: Stylable) => { | ItemGrid.Loader = (props: object) => { | ||||||
| 	const { css } = useYoshiki(); | 	const { css } = useYoshiki(); | ||||||
| 
 | 
 | ||||||
| 	return ( | 	return ( | ||||||
|  | |||||||
| @ -87,7 +87,7 @@ export const BrowsePage: QueryPage = () => { | |||||||
| 				/> | 				/> | ||||||
| 			} | 			} | ||||||
| 			Render={({ item }) => <LayoutComponent {...itemMap(item)} />} | 			Render={({ item }) => <LayoutComponent {...itemMap(item)} />} | ||||||
| 			Loader={() => <LayoutComponent.Loader />} | 			Loader={LayoutComponent.Loader} | ||||||
| 		/> | 		/> | ||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ import { percent, px, rem, useYoshiki } from "yoshiki/native"; | |||||||
| import { ItemContext } from "../components/context-menus"; | import { ItemContext } from "../components/context-menus"; | ||||||
| import type { Layout } from "../fetch"; | import type { Layout } from "../fetch"; | ||||||
| import { ItemWatchStatus } from "./grid"; | import { ItemWatchStatus } from "./grid"; | ||||||
| import { Stylable } from "yoshiki"; | import type { Stylable } from "yoshiki"; | ||||||
| 
 | 
 | ||||||
| export const ItemList = ({ | export const ItemList = ({ | ||||||
| 	href, | 	href, | ||||||
| @ -166,7 +166,7 @@ export const ItemList = ({ | |||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| ItemList.Loader = (props: Stylable) => { | ItemList.Loader = (props: object) => { | ||||||
| 	const { css } = useYoshiki(); | 	const { css } = useYoshiki(); | ||||||
| 
 | 
 | ||||||
| 	return ( | 	return ( | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ import { type ImageStyle, Platform, type PressableProps, View } from "react-nati | |||||||
| import { type Stylable, type Theme, percent, rem, useYoshiki } from "yoshiki/native"; | import { type Stylable, type Theme, percent, rem, useYoshiki } from "yoshiki/native"; | ||||||
| import { ItemProgress } from "../browse/grid"; | import { ItemProgress } from "../browse/grid"; | ||||||
| import { EpisodesContext } from "../components/context-menus"; | import { EpisodesContext } from "../components/context-menus"; | ||||||
| import type { Layout, WithLoading } from "../fetch"; | import type { Layout } from "../fetch"; | ||||||
| 
 | 
 | ||||||
| export const episodeDisplayNumber = (episode: { | export const episodeDisplayNumber = (episode: { | ||||||
| 	seasonNumber?: number | null; | 	seasonNumber?: number | null; | ||||||
| @ -67,23 +67,21 @@ export const EpisodeBox = ({ | |||||||
| 	name, | 	name, | ||||||
| 	overview, | 	overview, | ||||||
| 	thumbnail, | 	thumbnail, | ||||||
| 	isLoading, |  | ||||||
| 	href, | 	href, | ||||||
| 	watchedPercent, | 	watchedPercent, | ||||||
| 	watchedStatus, | 	watchedStatus, | ||||||
| 	...props | 	...props | ||||||
| }: Stylable & | }: Stylable & { | ||||||
| 	WithLoading<{ | 	slug: string; | ||||||
| 		slug: string; | 	// if show slug is null, disable "Go to show" in the context menu
 | ||||||
| 		// if show slug is null, disable "Go to show" in the context menu
 | 	showSlug: string | null; | ||||||
| 		showSlug: string | null; | 	name: string | null; | ||||||
| 		name: string | null; | 	overview: string | null; | ||||||
| 		overview: string | null; | 	href: string; | ||||||
| 		href: string; | 	thumbnail?: ImageProps["src"] | null; | ||||||
| 		thumbnail?: ImageProps["src"] | null; | 	watchedPercent: number | null; | ||||||
| 		watchedPercent: number | null; | 	watchedStatus: WatchStatusV | null; | ||||||
| 		watchedStatus: WatchStatusV | null; | }) => { | ||||||
| 	}>) => { |  | ||||||
| 	const [moreOpened, setMoreOpened] = useState(false); | 	const [moreOpened, setMoreOpened] = useState(false); | ||||||
| 	const { css } = useYoshiki("episodebox"); | 	const { css } = useYoshiki("episodebox"); | ||||||
| 	const { t } = useTranslation(); | 	const { t } = useTranslation(); | ||||||
| @ -126,58 +124,72 @@ export const EpisodeBox = ({ | |||||||
| 				quality="low" | 				quality="low" | ||||||
| 				alt="" | 				alt="" | ||||||
| 				gradient={false} | 				gradient={false} | ||||||
| 				hideLoad={false} |  | ||||||
| 				forcedLoading={isLoading} |  | ||||||
| 				layout={{ width: percent(100), aspectRatio: 16 / 9 }} | 				layout={{ width: percent(100), aspectRatio: 16 / 9 }} | ||||||
| 				{...(css("poster") as any)} | 				{...(css("poster") as any)} | ||||||
| 			> | 			> | ||||||
| 				{(watchedPercent || watchedStatus === WatchStatusV.Completed) && ( | 				{(watchedPercent || watchedStatus === WatchStatusV.Completed) && ( | ||||||
| 					<ItemProgress watchPercent={watchedPercent ?? 100} /> | 					<ItemProgress watchPercent={watchedPercent ?? 100} /> | ||||||
| 				)} | 				)} | ||||||
| 				{slug && watchedStatus !== undefined && ( | 				<EpisodesContext | ||||||
| 					<EpisodesContext | 					slug={slug} | ||||||
| 						slug={slug} | 					showSlug={showSlug} | ||||||
| 						showSlug={showSlug} | 					status={watchedStatus} | ||||||
| 						status={watchedStatus} | 					isOpen={moreOpened} | ||||||
| 						isOpen={moreOpened} | 					setOpen={(v) => setMoreOpened(v)} | ||||||
| 						setOpen={(v) => setMoreOpened(v)} | 					{...css([ | ||||||
| 						{...css([ | 						{ | ||||||
| 							{ | 							position: "absolute", | ||||||
| 								position: "absolute", | 							top: 0, | ||||||
| 								top: 0, | 							right: 0, | ||||||
| 								right: 0, | 							bg: (theme) => theme.darkOverlay, | ||||||
| 								bg: (theme) => theme.darkOverlay, | 						}, | ||||||
| 							}, | 						"more", | ||||||
| 							"more", | 						Platform.OS === "web" && moreOpened && { display: important("flex") }, | ||||||
| 							Platform.OS === "web" && moreOpened && { display: important("flex") }, | 					])} | ||||||
| 						])} | 				/> | ||||||
| 					/> |  | ||||||
| 				)} |  | ||||||
| 			</ImageBackground> | 			</ImageBackground> | ||||||
| 			<Skeleton {...css({ width: percent(50) })}> | 			<P {...css([{ marginY: 0, textAlign: "center" }, "title"])}> | ||||||
| 				{isLoading || ( | 				{name ?? t("show.episodeNoMetadata")} | ||||||
| 					<P {...css([{ marginY: 0, textAlign: "center" }, "title"])}> | 			</P> | ||||||
| 						{name ?? t("show.episodeNoMetadata")} | 			<SubP | ||||||
| 					</P> | 				numberOfLines={3} | ||||||
| 				)} | 				{...css({ | ||||||
| 			</Skeleton> | 					marginTop: 0, | ||||||
| 			<Skeleton {...css({ width: percent(75), height: rem(0.8) })}> | 					textAlign: "center", | ||||||
| 				{isLoading || ( | 				})} | ||||||
| 					<SubP | 			> | ||||||
| 						numberOfLines={3} | 				{overview} | ||||||
| 						{...css({ | 			</SubP> | ||||||
| 							marginTop: 0, |  | ||||||
| 							textAlign: "center", |  | ||||||
| 						})} |  | ||||||
| 					> |  | ||||||
| 						{overview} |  | ||||||
| 					</SubP> |  | ||||||
| 				)} |  | ||||||
| 			</Skeleton> |  | ||||||
| 		</Link> | 		</Link> | ||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | EpisodeBox.Loader = (props: Stylable) => { | ||||||
|  | 	const { css } = useYoshiki(); | ||||||
|  | 
 | ||||||
|  | 	return ( | ||||||
|  | 		<View | ||||||
|  | 			{...css( | ||||||
|  | 				{ | ||||||
|  | 					alignItems: "center", | ||||||
|  | 				}, | ||||||
|  | 				props, | ||||||
|  | 			)} | ||||||
|  | 		> | ||||||
|  | 			<Image.Loader | ||||||
|  | 				layout={{ width: percent(100), aspectRatio: 16 / 9 }} | ||||||
|  | 				{...css({ | ||||||
|  | 					borderColor: (theme) => theme.background, | ||||||
|  | 					borderWidth: ts(0.5), | ||||||
|  | 					borderStyle: "solid", | ||||||
|  | 				})} | ||||||
|  | 			/> | ||||||
|  | 			<Skeleton {...css({ width: percent(50) })} /> | ||||||
|  | 			<Skeleton {...css({ width: percent(75), height: rem(0.8) })} /> | ||||||
|  | 		</View> | ||||||
|  | 	); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export const EpisodeLine = ({ | export const EpisodeLine = ({ | ||||||
| 	slug, | 	slug, | ||||||
| 	showSlug, | 	showSlug, | ||||||
|  | |||||||
| @ -26,18 +26,7 @@ import { | |||||||
| 	SeasonP, | 	SeasonP, | ||||||
| 	useInfiniteFetch, | 	useInfiniteFetch, | ||||||
| } from "@kyoo/models"; | } from "@kyoo/models"; | ||||||
| import { | import { H2, HR, IconButton, Menu, P, Skeleton, tooltip, ts, usePageStyle } from "@kyoo/primitives"; | ||||||
| 	H2, |  | ||||||
| 	H6, |  | ||||||
| 	HR, |  | ||||||
| 	IconButton, |  | ||||||
| 	Menu, |  | ||||||
| 	P, |  | ||||||
| 	Skeleton, |  | ||||||
| 	tooltip, |  | ||||||
| 	ts, |  | ||||||
| 	usePageStyle, |  | ||||||
| } from "@kyoo/primitives"; |  | ||||||
| import MenuIcon from "@material-symbols/svg-400/rounded/menu-fill.svg"; | import MenuIcon from "@material-symbols/svg-400/rounded/menu-fill.svg"; | ||||||
| import type { ComponentType } from "react"; | import type { ComponentType } from "react"; | ||||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ | |||||||
|  * along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
 |  * along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| import { type Page, type QueryIdentifier, useInfiniteFetch } from "@kyoo/models"; | import { type QueryIdentifier, useInfiniteFetch } from "@kyoo/models"; | ||||||
| import { HR, useBreakpointMap } from "@kyoo/primitives"; | import { HR, useBreakpointMap } from "@kyoo/primitives"; | ||||||
| import { type ContentStyle, FlashList } from "@shopify/flash-list"; | import { type ContentStyle, FlashList } from "@shopify/flash-list"; | ||||||
| import { | import { | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ | |||||||
|  * along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
 |  * along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| import { type Page, type QueryIdentifier, useInfiniteFetch } from "@kyoo/models"; | import { type QueryIdentifier, useInfiniteFetch } from "@kyoo/models"; | ||||||
| import { HR } from "@kyoo/primitives"; | import { HR } from "@kyoo/primitives"; | ||||||
| import type { ContentStyle } from "@shopify/flash-list"; | import type { ContentStyle } from "@shopify/flash-list"; | ||||||
| import { | import { | ||||||
|  | |||||||
| @ -75,13 +75,9 @@ export const GenreGrid = ({ genre }: { genre: Genre }) => { | |||||||
| 				layout={{ ...ItemGrid.layout, layout: "horizontal" }} | 				layout={{ ...ItemGrid.layout, layout: "horizontal" }} | ||||||
| 				placeholderCount={2} | 				placeholderCount={2} | ||||||
| 				empty={displayEmpty.current ? t("home.none") : undefined} | 				empty={displayEmpty.current ? t("home.none") : undefined} | ||||||
| 			> | 				Render={({ item }) => <ItemGrid {...itemMap(item)} />} | ||||||
| 				{(x, i) => { | 				Loader={ItemGrid.Loader} | ||||||
| 					// only display empty list if a loading as been displayed (not durring ssr)
 | 			/> | ||||||
| 					if (x.isLoading) displayEmpty.current = true; |  | ||||||
| 					return <ItemGrid key={x.id ?? i} {...itemMap(x)} />; |  | ||||||
| 				}} |  | ||||||
| 			</InfiniteFetchList> |  | ||||||
| 		</> | 		</> | ||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -39,38 +39,40 @@ export const NewsList = () => { | |||||||
| 				getItemType={(x, i) => (x.kind === "movie" || (x.isLoading && i % 2) ? "movie" : "episode")} | 				getItemType={(x, i) => (x.kind === "movie" || (x.isLoading && i % 2) ? "movie" : "episode")} | ||||||
| 				getItemSize={(kind) => (kind === "episode" ? 2 : 1)} | 				getItemSize={(kind) => (kind === "episode" ? 2 : 1)} | ||||||
| 				empty={t("home.none")} | 				empty={t("home.none")} | ||||||
| 			> | 				Render={({ item }) => { | ||||||
| 				{(x, i) => | 					if (item.kind === "episode") { | ||||||
| 					x.kind === "movie" || (x.isLoading && i % 2) ? ( | 						return ( | ||||||
|  | 							<EpisodeBox | ||||||
|  | 								slug={item.slug} | ||||||
|  | 								showSlug={item.show!.slug} | ||||||
|  | 								name={`${item.show!.name} ${episodeDisplayNumber(item)}`} | ||||||
|  | 								overview={item.name} | ||||||
|  | 								thumbnail={item.thumbnail} | ||||||
|  | 								href={item.href} | ||||||
|  | 								watchedPercent={item.watchStatus?.watchedPercent || null} | ||||||
|  | 								watchedStatus={item.watchStatus?.status || null} | ||||||
|  | 								// TODO: Move this into the ItemList (using getItemSize)
 | ||||||
|  | 								// @ts-expect-error This is a web only property
 | ||||||
|  | 								{...css({ gridColumnEnd: "span 2" })} | ||||||
|  | 							/> | ||||||
|  | 						); | ||||||
|  | 					} | ||||||
|  | 					return ( | ||||||
| 						<ItemGrid | 						<ItemGrid | ||||||
| 							isLoading={x.isLoading as any} | 							href={item.href} | ||||||
| 							href={x.href} | 							slug={item.slug} | ||||||
| 							slug={x.slug} | 							name={item.name!} | ||||||
| 							name={x.name!} | 							subtitle={getDisplayDate(item)} | ||||||
| 							subtitle={!x.isLoading ? getDisplayDate(x) : undefined} | 							poster={item.poster} | ||||||
| 							poster={x.poster} | 							watchStatus={item.watchStatus?.status || null} | ||||||
| 							watchStatus={x.watchStatus?.status || null} | 							watchPercent={item.watchStatus?.watchedPercent || null} | ||||||
| 							watchPercent={x.watchStatus?.watchedPercent || null} | 							unseenEpisodesCount={null} | ||||||
| 							type={"movie"} | 							type={"movie"} | ||||||
| 						/> | 						/> | ||||||
| 					) : ( | 					); | ||||||
| 						<EpisodeBox | 				}} | ||||||
| 							isLoading={x.isLoading as any} | 				Loader={({ index }) => (index % 2 ? <EpisodeBox.Loader /> : <ItemGrid.Loader />)} | ||||||
| 							slug={x.slug} | 			/> | ||||||
| 							showSlug={x.kind === "episode" ? x.show!.slug : null} |  | ||||||
| 							name={x.kind === "episode" ? `${x.show!.name} ${episodeDisplayNumber(x)}` : undefined} |  | ||||||
| 							overview={x.name} |  | ||||||
| 							thumbnail={x.thumbnail} |  | ||||||
| 							href={x.href} |  | ||||||
| 							watchedPercent={x.watchStatus?.watchedPercent || null} |  | ||||||
| 							watchedStatus={x.watchStatus?.status || null} |  | ||||||
| 							// TODO: Move this into the ItemList (using getItemSize)
 |  | ||||||
| 							// @ts-expect-error This is a web only property
 |  | ||||||
| 							{...css({ gridColumnEnd: "span 2" })} |  | ||||||
| 						/> |  | ||||||
| 					) |  | ||||||
| 				} |  | ||||||
| 			</InfiniteFetch> |  | ||||||
| 		</> | 		</> | ||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -41,9 +41,9 @@ export const VerticalRecommended = () => { | |||||||
| 				layout={{ ...ItemList.layout, layout: "vertical" }} | 				layout={{ ...ItemList.layout, layout: "vertical" }} | ||||||
| 				fetchMore={false} | 				fetchMore={false} | ||||||
| 				nested | 				nested | ||||||
| 			> | 				Render={({ item }) => <ItemList {...itemMap(item)} />} | ||||||
| 				{(x, i) => <ItemList key={x.id ?? i} {...itemMap(x)} />} | 				Loader={() => <ItemList.Loader />} | ||||||
| 			</InfiniteFetch> | 			/> | ||||||
| 		</View> | 		</View> | ||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -39,55 +39,10 @@ export const WatchlistList = () => { | |||||||
| 	const { css } = useYoshiki(); | 	const { css } = useYoshiki(); | ||||||
| 	const account = useAccount(); | 	const account = useAccount(); | ||||||
| 
 | 
 | ||||||
| 	return ( | 	if (!account) { | ||||||
| 		<> | 		return ( | ||||||
| 			<Header title={t("home.watchlist")} /> | 			<> | ||||||
| 			{account ? ( | 				<Header title={t("home.watchlist")} /> | ||||||
| 				<InfiniteFetch |  | ||||||
| 					query={WatchlistList.query()} |  | ||||||
| 					layout={{ ...ItemGrid.layout, layout: "horizontal" }} |  | ||||||
| 					getItemType={(x, i) => |  | ||||||
| 						(x.kind === "show" && x.watchStatus?.nextEpisode) || (x.isLoading && i % 2) |  | ||||||
| 							? "episode" |  | ||||||
| 							: "item" |  | ||||||
| 					} |  | ||||||
| 					getItemSize={(kind) => (kind === "episode" ? 2 : 1)} |  | ||||||
| 					empty={t("home.none")} |  | ||||||
| 				> |  | ||||||
| 					{(x, i) => { |  | ||||||
| 						const episode = x.kind === "show" ? x.watchStatus?.nextEpisode : null; |  | ||||||
| 						return (x.kind === "show" && x.watchStatus?.nextEpisode) || (x.isLoading && i % 2) ? ( |  | ||||||
| 							<EpisodeBox |  | ||||||
| 								isLoading={x.isLoading as any} |  | ||||||
| 								slug={episode?.slug} |  | ||||||
| 								showSlug={x.slug} |  | ||||||
| 								name={episode ? `${x.name} ${episodeDisplayNumber(episode)}` : undefined} |  | ||||||
| 								overview={episode?.name} |  | ||||||
| 								thumbnail={episode?.thumbnail ?? x.thumbnail} |  | ||||||
| 								href={episode?.href} |  | ||||||
| 								watchedPercent={x.watchStatus?.watchedPercent || null} |  | ||||||
| 								watchedStatus={x.watchStatus?.status || null} |  | ||||||
| 								// TODO: Move this into the ItemList (using getItemSize)
 |  | ||||||
| 								// @ts-expect-error This is a web only property
 |  | ||||||
| 								{...css({ gridColumnEnd: "span 2" })} |  | ||||||
| 							/> |  | ||||||
| 						) : ( |  | ||||||
| 							<ItemGrid |  | ||||||
| 								isLoading={x.isLoading as any} |  | ||||||
| 								href={x.href} |  | ||||||
| 								slug={x.slug} |  | ||||||
| 								name={x.name!} |  | ||||||
| 								subtitle={!x.isLoading ? getDisplayDate(x) : undefined} |  | ||||||
| 								poster={x.poster} |  | ||||||
| 								watchStatus={x.watchStatus?.status || null} |  | ||||||
| 								watchPercent={x.watchStatus?.watchedPercent || null} |  | ||||||
| 								unseenEpisodesCount={x.kind === "show" ? x.watchStatus?.unseenEpisodesCount : null} |  | ||||||
| 								type={x.kind} |  | ||||||
| 							/> |  | ||||||
| 						); |  | ||||||
| 					}} |  | ||||||
| 				</InfiniteFetch> |  | ||||||
| 			) : ( |  | ||||||
| 				<View {...css({ justifyContent: "center", alignItems: "center" })}> | 				<View {...css({ justifyContent: "center", alignItems: "center" })}> | ||||||
| 					<P>{t("home.watchlistLogin")}</P> | 					<P>{t("home.watchlistLogin")}</P> | ||||||
| 					<Button | 					<Button | ||||||
| @ -96,7 +51,60 @@ export const WatchlistList = () => { | |||||||
| 						{...css({ minWidth: ts(24), margin: ts(2) })} | 						{...css({ minWidth: ts(24), margin: ts(2) })} | ||||||
| 					/> | 					/> | ||||||
| 				</View> | 				</View> | ||||||
| 			)} | 			</> | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ( | ||||||
|  | 		<> | ||||||
|  | 			<Header title={t("home.watchlist")} /> | ||||||
|  | 			<InfiniteFetch | ||||||
|  | 				query={WatchlistList.query()} | ||||||
|  | 				layout={{ ...ItemGrid.layout, layout: "horizontal" }} | ||||||
|  | 				getItemType={(x, i) => | ||||||
|  | 					(x.kind === "show" && x.watchStatus?.nextEpisode) || (x.isLoading && i % 2) | ||||||
|  | 						? "episode" | ||||||
|  | 						: "item" | ||||||
|  | 				} | ||||||
|  | 				getItemSize={(kind) => (kind === "episode" ? 2 : 1)} | ||||||
|  | 				empty={t("home.none")} | ||||||
|  | 				Render={({ item }) => { | ||||||
|  | 					const episode = item.kind === "show" ? item.watchStatus?.nextEpisode : null; | ||||||
|  | 					if (episode) { | ||||||
|  | 						return ( | ||||||
|  | 							<EpisodeBox | ||||||
|  | 								slug={episode.slug} | ||||||
|  | 								showSlug={item.slug} | ||||||
|  | 								name={`${item.name} ${episodeDisplayNumber(episode)}`} | ||||||
|  | 								overview={episode.name} | ||||||
|  | 								thumbnail={episode.thumbnail ?? item.thumbnail} | ||||||
|  | 								href={episode.href} | ||||||
|  | 								watchedPercent={item.watchStatus?.watchedPercent || null} | ||||||
|  | 								watchedStatus={item.watchStatus?.status || null} | ||||||
|  | 								// TODO: Move this into the ItemList (using getItemSize)
 | ||||||
|  | 								// @ts-expect-error This is a web only property
 | ||||||
|  | 								{...css({ gridColumnEnd: "span 2" })} | ||||||
|  | 							/> | ||||||
|  | 						); | ||||||
|  | 					} | ||||||
|  | 					return ( | ||||||
|  | 						<ItemGrid | ||||||
|  | 							href={item.href} | ||||||
|  | 							slug={item.slug} | ||||||
|  | 							name={item.name!} | ||||||
|  | 							subtitle={getDisplayDate(item)} | ||||||
|  | 							poster={item.poster} | ||||||
|  | 							watchStatus={item.watchStatus?.status || null} | ||||||
|  | 							watchPercent={item.watchStatus?.watchedPercent || null} | ||||||
|  | 							unseenEpisodesCount={ | ||||||
|  | 								(item.kind === "show" && item.watchStatus?.unseenEpisodesCount) || null | ||||||
|  | 							} | ||||||
|  | 							type={item.kind} | ||||||
|  | 						/> | ||||||
|  | 					); | ||||||
|  | 				}} | ||||||
|  | 				Loader={({ index }) => (index % 2 ? <EpisodeBox.Loader /> : <ItemGrid.Loader />)} | ||||||
|  | 			/> | ||||||
| 		</> | 		</> | ||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user