diff --git a/front/packages/ui/src/browse/grid.tsx b/front/packages/ui/src/browse/grid.tsx index 10c23a9d..ad5e7326 100644 --- a/front/packages/ui/src/browse/grid.tsx +++ b/front/packages/ui/src/browse/grid.tsx @@ -213,7 +213,7 @@ export const ItemGrid = ({ ); }; -ItemGrid.Loader = (props: Stylable) => { +ItemGrid.Loader = (props: object) => { const { css } = useYoshiki(); return ( diff --git a/front/packages/ui/src/browse/index.tsx b/front/packages/ui/src/browse/index.tsx index 9863657e..be1be7c9 100644 --- a/front/packages/ui/src/browse/index.tsx +++ b/front/packages/ui/src/browse/index.tsx @@ -87,7 +87,7 @@ export const BrowsePage: QueryPage = () => { /> } Render={({ item }) => } - Loader={() => } + Loader={LayoutComponent.Loader} /> ); }; diff --git a/front/packages/ui/src/browse/list.tsx b/front/packages/ui/src/browse/list.tsx index 889afacf..d2f50704 100644 --- a/front/packages/ui/src/browse/list.tsx +++ b/front/packages/ui/src/browse/list.tsx @@ -37,7 +37,7 @@ import { percent, px, rem, useYoshiki } from "yoshiki/native"; import { ItemContext } from "../components/context-menus"; import type { Layout } from "../fetch"; import { ItemWatchStatus } from "./grid"; -import { Stylable } from "yoshiki"; +import type { Stylable } from "yoshiki"; export const ItemList = ({ href, @@ -166,7 +166,7 @@ export const ItemList = ({ ); }; -ItemList.Loader = (props: Stylable) => { +ItemList.Loader = (props: object) => { const { css } = useYoshiki(); return ( diff --git a/front/packages/ui/src/details/episode.tsx b/front/packages/ui/src/details/episode.tsx index 7b8c9365..f35c25a7 100644 --- a/front/packages/ui/src/details/episode.tsx +++ b/front/packages/ui/src/details/episode.tsx @@ -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 { ItemProgress } from "../browse/grid"; import { EpisodesContext } from "../components/context-menus"; -import type { Layout, WithLoading } from "../fetch"; +import type { Layout } from "../fetch"; export const episodeDisplayNumber = (episode: { seasonNumber?: number | null; @@ -67,23 +67,21 @@ export const EpisodeBox = ({ name, overview, thumbnail, - isLoading, href, watchedPercent, watchedStatus, ...props -}: Stylable & - WithLoading<{ - slug: string; - // if show slug is null, disable "Go to show" in the context menu - showSlug: string | null; - name: string | null; - overview: string | null; - href: string; - thumbnail?: ImageProps["src"] | null; - watchedPercent: number | null; - watchedStatus: WatchStatusV | null; - }>) => { +}: Stylable & { + slug: string; + // if show slug is null, disable "Go to show" in the context menu + showSlug: string | null; + name: string | null; + overview: string | null; + href: string; + thumbnail?: ImageProps["src"] | null; + watchedPercent: number | null; + watchedStatus: WatchStatusV | null; +}) => { const [moreOpened, setMoreOpened] = useState(false); const { css } = useYoshiki("episodebox"); const { t } = useTranslation(); @@ -126,58 +124,72 @@ export const EpisodeBox = ({ quality="low" alt="" gradient={false} - hideLoad={false} - forcedLoading={isLoading} layout={{ width: percent(100), aspectRatio: 16 / 9 }} {...(css("poster") as any)} > {(watchedPercent || watchedStatus === WatchStatusV.Completed) && ( )} - {slug && watchedStatus !== undefined && ( - setMoreOpened(v)} - {...css([ - { - position: "absolute", - top: 0, - right: 0, - bg: (theme) => theme.darkOverlay, - }, - "more", - Platform.OS === "web" && moreOpened && { display: important("flex") }, - ])} - /> - )} + setMoreOpened(v)} + {...css([ + { + position: "absolute", + top: 0, + right: 0, + bg: (theme) => theme.darkOverlay, + }, + "more", + Platform.OS === "web" && moreOpened && { display: important("flex") }, + ])} + /> - - {isLoading || ( -

- {name ?? t("show.episodeNoMetadata")} -

- )} -
- - {isLoading || ( - - {overview} - - )} - +

+ {name ?? t("show.episodeNoMetadata")} +

+ + {overview} + ); }; +EpisodeBox.Loader = (props: Stylable) => { + const { css } = useYoshiki(); + + return ( + + theme.background, + borderWidth: ts(0.5), + borderStyle: "solid", + })} + /> + + + + ); +}; + export const EpisodeLine = ({ slug, showSlug, diff --git a/front/packages/ui/src/details/season.tsx b/front/packages/ui/src/details/season.tsx index ab6f09b3..7f1a1876 100644 --- a/front/packages/ui/src/details/season.tsx +++ b/front/packages/ui/src/details/season.tsx @@ -26,18 +26,7 @@ import { SeasonP, useInfiniteFetch, } from "@kyoo/models"; -import { - H2, - H6, - HR, - IconButton, - Menu, - P, - Skeleton, - tooltip, - ts, - usePageStyle, -} from "@kyoo/primitives"; +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"; diff --git a/front/packages/ui/src/fetch-infinite.tsx b/front/packages/ui/src/fetch-infinite.tsx index 1ff4231e..d3295798 100644 --- a/front/packages/ui/src/fetch-infinite.tsx +++ b/front/packages/ui/src/fetch-infinite.tsx @@ -18,7 +18,7 @@ * along with Kyoo. If not, see . */ -import { type Page, type QueryIdentifier, useInfiniteFetch } from "@kyoo/models"; +import { type QueryIdentifier, useInfiniteFetch } from "@kyoo/models"; import { HR, useBreakpointMap } from "@kyoo/primitives"; import { type ContentStyle, FlashList } from "@shopify/flash-list"; import { diff --git a/front/packages/ui/src/fetch-infinite.web.tsx b/front/packages/ui/src/fetch-infinite.web.tsx index 61c33051..53186008 100644 --- a/front/packages/ui/src/fetch-infinite.web.tsx +++ b/front/packages/ui/src/fetch-infinite.web.tsx @@ -18,7 +18,7 @@ * along with Kyoo. If not, see . */ -import { type Page, type QueryIdentifier, useInfiniteFetch } from "@kyoo/models"; +import { type QueryIdentifier, useInfiniteFetch } from "@kyoo/models"; import { HR } from "@kyoo/primitives"; import type { ContentStyle } from "@shopify/flash-list"; import { diff --git a/front/packages/ui/src/home/genre.tsx b/front/packages/ui/src/home/genre.tsx index 4deba79c..5f580dc3 100644 --- a/front/packages/ui/src/home/genre.tsx +++ b/front/packages/ui/src/home/genre.tsx @@ -75,13 +75,9 @@ export const GenreGrid = ({ genre }: { genre: Genre }) => { layout={{ ...ItemGrid.layout, layout: "horizontal" }} placeholderCount={2} empty={displayEmpty.current ? t("home.none") : undefined} - > - {(x, i) => { - // only display empty list if a loading as been displayed (not durring ssr) - if (x.isLoading) displayEmpty.current = true; - return ; - }} - + Render={({ item }) => } + Loader={ItemGrid.Loader} + /> ); }; diff --git a/front/packages/ui/src/home/news.tsx b/front/packages/ui/src/home/news.tsx index bb8295e9..3c4ec8aa 100644 --- a/front/packages/ui/src/home/news.tsx +++ b/front/packages/ui/src/home/news.tsx @@ -39,38 +39,40 @@ export const NewsList = () => { getItemType={(x, i) => (x.kind === "movie" || (x.isLoading && i % 2) ? "movie" : "episode")} getItemSize={(kind) => (kind === "episode" ? 2 : 1)} empty={t("home.none")} - > - {(x, i) => - x.kind === "movie" || (x.isLoading && i % 2) ? ( + Render={({ item }) => { + if (item.kind === "episode") { + return ( + + ); + } + return ( - ) : ( - - ) - } - + ); + }} + Loader={({ index }) => (index % 2 ? : )} + /> ); }; diff --git a/front/packages/ui/src/home/vertical.tsx b/front/packages/ui/src/home/vertical.tsx index 813734ca..246ebe26 100644 --- a/front/packages/ui/src/home/vertical.tsx +++ b/front/packages/ui/src/home/vertical.tsx @@ -41,9 +41,9 @@ export const VerticalRecommended = () => { layout={{ ...ItemList.layout, layout: "vertical" }} fetchMore={false} nested - > - {(x, i) => } - + Render={({ item }) => } + Loader={() => } + /> ); }; diff --git a/front/packages/ui/src/home/watchlist.tsx b/front/packages/ui/src/home/watchlist.tsx index fa2e695e..460f906f 100644 --- a/front/packages/ui/src/home/watchlist.tsx +++ b/front/packages/ui/src/home/watchlist.tsx @@ -39,55 +39,10 @@ export const WatchlistList = () => { const { css } = useYoshiki(); const account = useAccount(); - return ( - <> -
- {account ? ( - - (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) ? ( - - ) : ( - - ); - }} - - ) : ( + if (!account) { + return ( + <> +

{t("home.watchlistLogin")}