diff --git a/front/apps/mobile/package.json b/front/apps/mobile/package.json index 8848da02..40a28354 100644 --- a/front/apps/mobile/package.json +++ b/front/apps/mobile/package.json @@ -51,7 +51,7 @@ "react-native-svg": "13.9.0", "react-native-uuid": "^2.0.1", "react-native-video": "^6.0.0-alpha.7", - "yoshiki": "1.2.7" + "yoshiki": "1.2.9" }, "devDependencies": { "@babel/core": "^7.22.10", diff --git a/front/apps/web/package.json b/front/apps/web/package.json index 5a92d653..1e77d0fc 100644 --- a/front/apps/web/package.json +++ b/front/apps/web/package.json @@ -38,7 +38,7 @@ "srt-webvtt": "^2.0.0", "superjson": "^1.13.1", "sweetalert2": "^11.7.20", - "yoshiki": "1.2.7", + "yoshiki": "1.2.9", "zod": "^3.21.4" }, "devDependencies": { diff --git a/front/packages/primitives/src/avatar.tsx b/front/packages/primitives/src/avatar.tsx index 584a55d3..4953c785 100644 --- a/front/packages/primitives/src/avatar.tsx +++ b/front/packages/primitives/src/avatar.tsx @@ -24,7 +24,7 @@ import { useYoshiki, px, Stylable } from "yoshiki/native"; import { Icon } from "./icons"; import { P } from "./text"; import AccountCircle from "@material-symbols/svg-400/rounded/account_circle-fill.svg"; -import { YoshikiStyle } from "yoshiki/src/type"; +import { YoshikiStyle } from "yoshiki"; import { ComponentType, forwardRef, RefAttributes } from "react"; const stringToColor = (string: string) => { diff --git a/front/packages/primitives/src/utils/breakpoints.ts b/front/packages/primitives/src/utils/breakpoints.ts index 46b1c535..bcef3920 100644 --- a/front/packages/primitives/src/utils/breakpoints.ts +++ b/front/packages/primitives/src/utils/breakpoints.ts @@ -19,9 +19,7 @@ */ import { useWindowDimensions } from "react-native"; -import { Breakpoints as YoshikiBreakpoint } from "yoshiki/src/type"; -import { isBreakpoints } from "yoshiki/src/utils"; -import { breakpoints } from "yoshiki/native"; +import { Breakpoints as YoshikiBreakpoint, isBreakpoints, breakpoints } from "yoshiki/native"; type AtLeastOne }> = Partial & U[keyof U]; export type Breakpoint = T | AtLeastOne>; diff --git a/front/packages/ui/src/browse/grid.tsx b/front/packages/ui/src/browse/grid.tsx index e3c5ce18..d41f9d0b 100644 --- a/front/packages/ui/src/browse/grid.tsx +++ b/front/packages/ui/src/browse/grid.tsx @@ -21,7 +21,7 @@ import { KyooImage } from "@kyoo/models"; import { Link, Skeleton, Poster, ts, focusReset, P, SubP } from "@kyoo/primitives"; import { ImageStyle, Platform } from "react-native"; -import { percent, px, Stylable, useYoshiki } from "yoshiki/native"; +import { percent, px, Stylable, Theme, useYoshiki } from "yoshiki/native"; import { Layout, WithLoading } from "../fetch"; export const ItemGrid = ({ @@ -44,35 +44,27 @@ export const ItemGrid = ({ theme.background, - borderWidth: px(4), - borderStyle: "solid", - }, - }, - fover: { - self: focusReset, - poster: { - borderColor: (theme) => theme.accent, - }, - title: { - textDecorationLine: "underline", - }, + { + flexDirection: "column", + alignItems: "center", + width: percent(100), + child: { + poster: { + borderColor: (theme) => theme.background, + borderWidth: px(4), + borderStyle: "solid", }, }, - // We leave no width on native to fill the list's grid. - Platform.OS === "web" && { - width: { xs: percent(18), sm: percent(25) }, - minWidth: { xs: px(90), sm: px(120) }, - maxWidth: px(168), + fover: { + self: focusReset, + poster: { + borderColor: (theme: Theme) => theme.accent, + }, + title: { + textDecorationLine: "underline", + }, }, - ], + }, props, )} > @@ -111,5 +103,7 @@ export const ItemGrid = ({ ItemGrid.layout = { size: px(150), - numColumns: { xs: 3, sm: 5, xl: 7 }, + numColumns: { xs: 3, sm: 4, md: 5, lg: 6, xl: 8 }, + gap: { xs: ts(1), sm: ts(2), md: ts(4) }, + layout: "grid", } satisfies Layout; diff --git a/front/packages/ui/src/browse/list.tsx b/front/packages/ui/src/browse/list.tsx index f41c5b22..ffae63c7 100644 --- a/front/packages/ui/src/browse/list.tsx +++ b/front/packages/ui/src/browse/list.tsx @@ -65,7 +65,6 @@ export const ItemList = ({ flexDirection: "row", height: ItemList.layout.size, borderRadius: px(6), - m: ts(1), })} > ({ query, placeholderCount = 15, incremental = false, - horizontal = false, children, layout, empty, @@ -83,7 +82,7 @@ export const InfiniteFetch = ({ children({ isLoading: false, ...item } as any, index)} data={hasNextPage !== false ? [...(items || []), ...placeholders] : items} - horizontal={horizontal} + horizontal={layout.layout === "horizontal"} keyExtractor={(item: any) => item.id?.toString()} numColumns={numColumns} estimatedItemSize={size} diff --git a/front/packages/ui/src/fetch-infinite.web.tsx b/front/packages/ui/src/fetch-infinite.web.tsx index 372418b9..87da70b5 100644 --- a/front/packages/ui/src/fetch-infinite.web.tsx +++ b/front/packages/ui/src/fetch-infinite.web.tsx @@ -29,13 +29,13 @@ import { useEffect, useRef, } from "react"; -import { Stylable, useYoshiki } from "yoshiki"; +import { Stylable, useYoshiki, ysMap } from "yoshiki"; import { EmptyView, ErrorView, Layout, WithLoading } from "./fetch"; const InfiniteScroll = ({ children, loader, - layout = "vertical", + layout, loadMore, hasMore = true, isFetching, @@ -45,7 +45,7 @@ const InfiniteScroll = ({ }: { children?: ReactElement | (ReactElement | null)[] | null; loader?: (ReactElement | null)[]; - layout?: "vertical" | "horizontal" | "grid"; + layout: Layout; loadMore: () => void; hasMore: boolean; isFetching: boolean; @@ -58,10 +58,11 @@ const InfiniteScroll = ({ const onScroll = useCallback(() => { if (!ref.current || !hasMore || isFetching) return; const scroll = - layout === "horizontal" + layout.layout === "horizontal" ? ref.current.scrollWidth - ref.current.scrollLeft : ref.current.scrollHeight - ref.current.scrollTop; - const offset = layout === "horizontal" ? ref.current.offsetWidth : ref.current.offsetHeight; + const offset = + layout.layout === "horizontal" ? ref.current.offsetWidth : ref.current.offsetHeight; if (scroll <= offset * 1.2) loadMore(); }, [hasMore, isFetching, layout, loadMore]); @@ -78,22 +79,30 @@ const InfiniteScroll = ({ {...css( [ { - display: "flex", - alignItems: "flex-start", - overflowX: "hidden", + display: "grid", + gridAutoRows: "max-content", + // the as any is due to differencies between css types of native and web (already accounted for in yoshiki) + gridGap: layout.gap as any, + padding: layout.gap as any, + }, + layout.layout == "vertical" && { + gridTemplateColumns: "1fr", + alignItems: "stretch", overflowY: "auto", }, - layout == "vertical" && { - flexDirection: "column", + layout.layout == "horizontal" && { alignItems: "stretch", + overflowX: "auto", + overflowY: "hidden", + gridAutoFlow: "column", + gridAutoColumns: ysMap(layout.numColumns, (x) => `${100 / x}%`), + gridTemplateRows: "max-content", }, - layout == "horizontal" && { - flexDirection: "row", - alignItems: "stretch", - }, - layout === "grid" && { - flexWrap: "wrap", + layout.layout === "grid" && { + gridTemplateColumns: ysMap(layout.numColumns, (x) => `repeat(${x}, 1fr)`), justifyContent: "center", + alignItems: "flex-start", + overflowY: "auto", }, ], @@ -127,7 +136,6 @@ export const InfiniteFetch = ({ placeholderCount = 15, children, layout, - horizontal = false, empty, divider: Divider = false, Header, @@ -139,7 +147,6 @@ export const InfiniteFetch = ({ incremental?: boolean; placeholderCount?: number; layout: Layout; - horizontal?: boolean; children: ( item: Data extends Page ? WithLoading : WithLoading, i: number, @@ -156,8 +163,6 @@ export const InfiniteFetch = ({ const { items, error, fetchNextPage, hasNextPage, isFetching } = useInfiniteFetch(query, { useErrorBoundary: false, }); - const grid = layout.numColumns !== 1; - if (incremental && items) oldItems.current = items; if (error) return addHeader(Header, , headerProps); @@ -168,7 +173,7 @@ export const InfiniteFetch = ({ return ( ; size: Breakpoint }; +export type Layout = { + numColumns: Breakpoint; + size: Breakpoint; + gap: Breakpoint; + layout: "grid" | "horizontal" | "vertical"; +}; export type WithLoading = | (Item & { isLoading: false }) diff --git a/front/yarn.lock b/front/yarn.lock index 34d3ca4d..645745e0 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -10573,7 +10573,7 @@ __metadata: react-native-uuid: ^2.0.1 react-native-video: ^6.0.0-alpha.7 typescript: ^5.1.6 - yoshiki: 1.2.7 + yoshiki: 1.2.9 languageName: unknown linkType: soft @@ -14285,7 +14285,7 @@ __metadata: sweetalert2: ^11.7.20 typescript: ^5.1.6 webpack: ^5.88.2 - yoshiki: 1.2.7 + yoshiki: 1.2.9 zod: ^3.21.4 languageName: unknown linkType: soft @@ -14667,9 +14667,9 @@ __metadata: languageName: node linkType: hard -"yoshiki@npm:1.2.7": - version: 1.2.7 - resolution: "yoshiki@npm:1.2.7" +"yoshiki@npm:1.2.9": + version: 1.2.9 + resolution: "yoshiki@npm:1.2.9" dependencies: "@types/inline-style-prefixer": ^5.0.0 "@types/node": 18.x.x @@ -14684,7 +14684,7 @@ __metadata: optional: true react-native-web: optional: true - checksum: 2ebe15f481ad347a90fc8d6bc021d17ef03a8f982b31fa00b8700fa65d27e987044faa3d83d69159becb383ad9aa9ea5523eff3888965e25bc457affe147d361 + checksum: 1cd681cf9ba241f051c8e09a97b3a67ae5610fbba460ac506127c8d78bbcc069c07c727fb84a15a723a887ad58582bbcf57baba7020642ac6234d38d0c21116f languageName: node linkType: hard