diff --git a/front/packages/models/src/utils.ts b/front/packages/models/src/utils.ts
index 6d3557de..51678098 100644
--- a/front/packages/models/src/utils.ts
+++ b/front/packages/models/src/utils.ts
@@ -42,6 +42,7 @@ export const getDisplayDate = (data: Show | Movie) => {
if (airDate) {
return airDate.getFullYear().toString();
}
+ return null;
};
export const useLocalSetting = (setting: string, def: string) => {
diff --git a/front/packages/primitives/src/image/image.tsx b/front/packages/primitives/src/image/image.tsx
index a117d76d..288a892f 100644
--- a/front/packages/primitives/src/image/image.tsx
+++ b/front/packages/primitives/src/image/image.tsx
@@ -93,3 +93,10 @@ export const Image = ({
);
};
+
+Image.Loader = ({ layout, ...props }: { layout: ImageLayout }) => {
+ const { css } = useYoshiki();
+ const border = { borderRadius: 6, overflow: "hidden" } satisfies ViewStyle;
+
+ return ;
+};
diff --git a/front/packages/primitives/src/image/image.web.tsx b/front/packages/primitives/src/image/image.web.tsx
index 3c5f6514..7a459e55 100644
--- a/front/packages/primitives/src/image/image.web.tsx
+++ b/front/packages/primitives/src/image/image.web.tsx
@@ -73,3 +73,10 @@ export const Image = ({
);
};
+
+Image.Loader = ({ layout, ...props }: { layout: ImageLayout }) => {
+ const { css } = useYoshiki();
+ const border = { borderRadius: 6, overflow: "hidden" } satisfies ViewStyle;
+
+ return ;
+};
diff --git a/front/packages/primitives/src/image/index.tsx b/front/packages/primitives/src/image/index.tsx
index daffe995..ca793d31 100644
--- a/front/packages/primitives/src/image/index.tsx
+++ b/front/packages/primitives/src/image/index.tsx
@@ -39,6 +39,13 @@ export const Poster = ({
layout: YoshikiEnhanced<{ width: ImageStyle["width"] } | { height: ImageStyle["height"] }>;
}) => ;
+Poster.Loader = ({
+ layout,
+ ...props
+}: {
+ layout: YoshikiEnhanced<{ width: ImageStyle["width"] } | { height: ImageStyle["height"] }>;
+}) => ;
+
export const PosterBackground = ({
alt,
layout,
diff --git a/front/packages/ui/src/browse/grid.tsx b/front/packages/ui/src/browse/grid.tsx
index cf708683..10c23a9d 100644
--- a/front/packages/ui/src/browse/grid.tsx
+++ b/front/packages/ui/src/browse/grid.tsx
@@ -23,6 +23,7 @@ import {
Icon,
Link,
P,
+ Poster,
PosterBackground,
Skeleton,
SubP,
@@ -35,7 +36,7 @@ import { useState } from "react";
import { type ImageStyle, Platform, View } from "react-native";
import { type Stylable, type Theme, max, percent, px, rem, useYoshiki } from "yoshiki/native";
import { ItemContext } from "../components/context-menus";
-import type { Layout, WithLoading } from "../fetch";
+import type { Layout } from "../fetch";
export const ItemWatchStatus = ({
watchStatus,
@@ -113,23 +114,21 @@ export const ItemGrid = ({
type,
subtitle,
poster,
- isLoading,
watchStatus,
watchPercent,
unseenEpisodesCount,
...props
-}: WithLoading<{
+}: {
href: string;
slug: string;
name: string;
- subtitle?: string;
- poster?: KyooImage | null;
+ subtitle: string | null;
+ poster: KyooImage | null;
watchStatus: WatchStatusV | null;
watchPercent: number | null;
type: "movie" | "show" | "collection";
unseenEpisodesCount: number | null;
-}> &
- Stylable<"text">) => {
+} & Stylable<"text">) => {
const [moreOpened, setMoreOpened] = useState(false);
const { css } = useYoshiki("grid");
@@ -172,13 +171,12 @@ export const ItemGrid = ({
src={poster}
alt={name}
quality="low"
- forcedLoading={isLoading}
layout={{ width: percent(100) }}
{...(css("poster") as { style: ImageStyle })}
>
{type === "movie" && watchPercent && }
- {slug && watchStatus !== undefined && type && type !== "collection" && (
+ {type !== "collection" && (
)}
-
- {isLoading || (
-
- {name}
-
- )}
-
- {(isLoading || subtitle) && (
-
- {isLoading || (
-
- {subtitle}
-
- )}
-
+
+ {name}
+
+ {subtitle && (
+
+ {subtitle}
+
)}
);
};
+ItemGrid.Loader = (props: Stylable) => {
+ const { css } = useYoshiki();
+
+ return (
+
+ theme.background,
+ borderWidth: ts(0.5),
+ borderStyle: "solid",
+ })}
+ />
+
+
+
+ );
+};
+
ItemGrid.layout = {
size: px(150),
numColumns: { xs: 3, sm: 4, md: 5, lg: 6, xl: 8 },
diff --git a/front/packages/ui/src/browse/index.tsx b/front/packages/ui/src/browse/index.tsx
index 9b038f69..9863657e 100644
--- a/front/packages/ui/src/browse/index.tsx
+++ b/front/packages/ui/src/browse/index.tsx
@@ -27,7 +27,6 @@ import {
} from "@kyoo/models";
import { type ComponentProps, useState } from "react";
import { createParam } from "solito";
-import type { WithLoading } from "../fetch";
import { InfiniteFetch } from "../fetch-infinite";
import { DefaultLayout } from "../layout";
import { ItemGrid } from "./grid";
@@ -38,25 +37,20 @@ import { Layout, SortBy, SortOrd } from "./types";
const { useParam } = createParam<{ sortBy?: string }>();
export const itemMap = (
- item: WithLoading,
-): WithLoading & ComponentProps> => {
- if (item.isLoading) return item as any;
-
- return {
- isLoading: item.isLoading,
- slug: item.slug,
- name: item.name,
- subtitle: item.kind !== "collection" ? getDisplayDate(item) : undefined,
- href: item.href,
- poster: item.poster,
- thumbnail: item.thumbnail,
- watchStatus: item.kind !== "collection" ? item.watchStatus?.status ?? null : null,
- type: item.kind,
- watchPercent: item.kind !== "collection" ? item.watchStatus?.watchedPercent ?? null : null,
- unseenEpisodesCount:
- item.kind === "show" ? item.watchStatus?.unseenEpisodesCount ?? item.episodesCount! : null,
- };
-};
+ item: LibraryItem,
+): ComponentProps & ComponentProps => ({
+ slug: item.slug,
+ name: item.name,
+ subtitle: item.kind !== "collection" ? getDisplayDate(item) : null,
+ href: item.href,
+ poster: item.poster,
+ thumbnail: item.thumbnail,
+ watchStatus: item.kind !== "collection" ? item.watchStatus?.status ?? null : null,
+ type: item.kind,
+ watchPercent: item.kind !== "collection" ? item.watchStatus?.watchedPercent ?? null : null,
+ unseenEpisodesCount:
+ item.kind === "show" ? item.watchStatus?.unseenEpisodesCount ?? item.episodesCount! : null,
+});
const query = (sortKey?: SortBy, sortOrd?: SortOrd): QueryIdentifier => ({
parser: LibraryItemP,
@@ -92,9 +86,9 @@ export const BrowsePage: QueryPage = () => {
setLayout={setLayout}
/>
}
- >
- {(item) => }
-
+ Render={({ item }) => }
+ Loader={() => }
+ />
);
};
diff --git a/front/packages/ui/src/browse/list.tsx b/front/packages/ui/src/browse/list.tsx
index 699d1868..889afacf 100644
--- a/front/packages/ui/src/browse/list.tsx
+++ b/front/packages/ui/src/browse/list.tsx
@@ -24,6 +24,7 @@ import {
ImageBackground,
Link,
P,
+ Poster,
PosterBackground,
Skeleton,
imageBorderRadius,
@@ -34,8 +35,9 @@ import { useState } from "react";
import { Platform, View } from "react-native";
import { percent, px, rem, useYoshiki } from "yoshiki/native";
import { ItemContext } from "../components/context-menus";
-import type { Layout, WithLoading } from "../fetch";
+import type { Layout } from "../fetch";
import { ItemWatchStatus } from "./grid";
+import { Stylable } from "yoshiki";
export const ItemList = ({
href,
@@ -45,22 +47,21 @@ export const ItemList = ({
subtitle,
thumbnail,
poster,
- isLoading,
watchStatus,
unseenEpisodesCount,
...props
-}: WithLoading<{
+}: {
href: string;
slug: string;
type: "movie" | "show" | "collection";
name: string;
- subtitle?: string;
- poster?: KyooImage | null;
- thumbnail?: KyooImage | null;
+ subtitle: string | null;
+ poster: KyooImage | null;
+ thumbnail: KyooImage | null;
watchStatus: WatchStatusV | null;
unseenEpisodesCount: number | null;
-}>) => {
- const { css } = useYoshiki();
+}) => {
+ const { css } = useYoshiki("line");
const [moreOpened, setMoreOpened] = useState(false);
return (
@@ -114,25 +115,21 @@ export const ItemList = ({
justifyContent: "center",
})}
>
-
- {isLoading || (
-
- {name}
-
- )}
-
- {slug && watchStatus !== undefined && type && type !== "collection" && (
+
+ {name}
+
+ {type !== "collection" && (
)}
- {(isLoading || subtitle) && (
-
- {isLoading || (
-
- {subtitle}
-
- )}
-
+ {subtitle && (
+
+ {subtitle}
+
)}
-
+
);
};
+ItemList.Loader = (props: Stylable) => {
+ const { css } = useYoshiki();
+
+ return (
+ theme.dark.background,
+ marginX: ItemList.layout.gap,
+ },
+ props,
+ )}
+ >
+
+
+
+
+
+
+ );
+};
+
ItemList.layout = { numColumns: 1, size: 300, layout: "vertical", gap: ts(2) } satisfies Layout;