diff --git a/front/apps/mobile/package.json b/front/apps/mobile/package.json index 40a28354..cd32b8cf 100644 --- a/front/apps/mobile/package.json +++ b/front/apps/mobile/package.json @@ -20,6 +20,7 @@ "@material-symbols/svg-400": "^0.10.3", "@shopify/flash-list": "1.4.3", "@tanstack/react-query": "^4.32.6", + "array-shuffle": "^3.0.0", "babel-plugin-transform-inline-environment-variables": "^0.4.4", "expo": "^49.0.6", "expo-build-properties": "~0.8.3", diff --git a/front/apps/web/package.json b/front/apps/web/package.json index 1e77d0fc..6a452412 100644 --- a/front/apps/web/package.json +++ b/front/apps/web/package.json @@ -17,6 +17,7 @@ "@material-symbols/svg-400": "^0.10.3", "@radix-ui/react-dropdown-menu": "^2.0.5", "@tanstack/react-query": "^4.32.6", + "array-shuffle": "^3.0.0", "expo-linear-gradient": "^12.4.0", "expo-modules-core": "^1.5.9", "hls.js": "^1.4.10", diff --git a/front/apps/web/src/pages/_app.tsx b/front/apps/web/src/pages/_app.tsx index f4c1d7bc..b1014677 100755 --- a/front/apps/web/src/pages/_app.tsx +++ b/front/apps/web/src/pages/_app.tsx @@ -38,6 +38,7 @@ import { useTheme, useMobileHover, useStyleRegistry, StyleRegistryProvider } fro import superjson from "superjson"; import Head from "next/head"; import { withTranslations } from "../i18n"; +import arrayShuffle from "array-shuffle"; const font = Poppins({ weight: ["300", "400", "900"], subsets: ["latin"], display: "swap" }); @@ -102,7 +103,9 @@ const YoshikiDebug = ({ children }: { children: JSX.Element }) => { const App = ({ Component, pageProps }: AppProps) => { const [queryClient] = useState(() => createQueryClient()); - const { queryState, token, ...props } = superjson.deserialize(pageProps ?? { json: {} }); + const { queryState, token, randomItems, ...props } = superjson.deserialize( + pageProps ?? { json: {} }, + ); const layoutInfo = (Component as QueryPage).getLayout ?? (({ page }) => page); const { Layout, props: layoutProps } = typeof layoutInfo === "function" ? { Layout: layoutInfo, props: {} } : layoutInfo; @@ -122,7 +125,19 @@ const App = ({ Component, pageProps }: AppProps) => { - } {...layoutProps} /> + + } + randomItems={[]} + {...layoutProps} + /> @@ -148,6 +163,9 @@ App.getInitialProps = async (ctx: AppContext) => { const [authToken, token] = await getTokenWJ(ctx.ctx.req?.headers.cookie); appProps.pageProps.queryState = await fetchQuery(urls, authToken); appProps.pageProps.token = token; + appProps.pageProps.randomItems = { + [Component.displayName!]: arrayShuffle(Component.randomItems ?? []), + }; return { pageProps: superjson.serialize(appProps.pageProps) }; }; diff --git a/front/packages/models/src/query.tsx b/front/packages/models/src/query.tsx index 7f38c94f..5bfe7c30 100644 --- a/front/packages/models/src/query.tsx +++ b/front/packages/models/src/query.tsx @@ -162,11 +162,12 @@ export type QueryIdentifier = { getNext?: (item: unknown) => string | undefined; }; -export type QueryPage = ComponentType & { +export type QueryPage = ComponentType & { getFetchUrls?: (route: { [key: string]: string }) => QueryIdentifier[]; getLayout?: | QueryPage<{ page: ReactElement }> | { Layout: QueryPage<{ page: ReactElement }>; props: object }; + randomItems?: Items[] }; const toQueryKey = (query: QueryIdentifier) => { diff --git a/front/packages/ui/src/home/genre.tsx b/front/packages/ui/src/home/genre.tsx new file mode 100644 index 00000000..cf8bd8ee --- /dev/null +++ b/front/packages/ui/src/home/genre.tsx @@ -0,0 +1,86 @@ +/* + * 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 . + */ + +import { + Genre, + ItemKind, + LibraryItem, + LibraryItemP, + Page, + Paged, + QueryIdentifier, + getDisplayDate, +} from "@kyoo/models"; +import { H3, IconButton, ts } from "@kyoo/primitives"; +import { useRef } from "react"; +import { ScrollView, View } from "react-native"; +import { useYoshiki } from "yoshiki/native"; +import { Fetch } from "../fetch"; +import { ItemGrid } from "../browse/grid"; +import ChevronLeft from "@material-symbols/svg-400/rounded/chevron_left-fill.svg"; +import ChevronRight from "@material-symbols/svg-400/rounded/chevron_right-fill.svg"; + +export const GenreGrid = ({ genre }: { genre: Genre }) => { + const ref = useRef(null); + const { css } = useYoshiki(); + + return ( + + +

{genre}

+ + ref.current?.scrollTo({ x: 0, animated: true })} + /> + ref.current?.scrollTo({ x: 0, animated: true })} + /> + +
+ + + {(x, i) => ( + + )} + + +
+ ); +}; + +GenreGrid.query = (genre: Genre): QueryIdentifier> => ({ + parser: Paged(LibraryItemP) as any, + path: ["items"], + params: { + genres: genre, + sortBy: "random", + }, +}); diff --git a/front/packages/ui/src/home/index.tsx b/front/packages/ui/src/home/index.tsx index 8ce33a6b..cd578825 100644 --- a/front/packages/ui/src/home/index.tsx +++ b/front/packages/ui/src/home/index.tsx @@ -18,29 +18,41 @@ * along with Kyoo. If not, see . */ -import { ItemKind, QueryPage } from "@kyoo/models"; +import { Genre, ItemKind, QueryPage } from "@kyoo/models"; import { Fetch } from "../fetch"; import { Header } from "./header"; import { DefaultLayout } from "../layout"; +import { ScrollView, View } from "react-native"; +import { GenreGrid } from "./genre"; -export const HomePage: QueryPage = () => { +export const HomePage: QueryPage<{}, Genre> = ({ randomItems }) => { return ( - - {(x) => ( -
- )} - + + + {(x) => ( +
+ )} + + {randomItems.map((x) => ( + + ))} + ); }; +HomePage.randomItems = [...Object.values(Genre)]; + HomePage.getLayout = { Layout: DefaultLayout, props: { transparent: true } }; -HomePage.getFetchUrls = () => [Header.query()]; +HomePage.getFetchUrls = () => [ + Header.query(), + ...Object.values(Genre).map((x) => GenreGrid.query(x)), +]; diff --git a/front/yarn.lock b/front/yarn.lock index 61b4e246..62469afb 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -4746,6 +4746,13 @@ __metadata: languageName: node linkType: hard +"array-shuffle@npm:^3.0.0": + version: 3.0.0 + resolution: "array-shuffle@npm:3.0.0" + checksum: 003d813f10d6a57174d134d46d9465e0ca76a802a8c2d21c4b42513af914d4a25b3c51a3004c3d170c3a7b2caab356108c34455c327b21537978a6417cfde1d7 + languageName: node + linkType: hard + "array-union@npm:^2.1.0": version: 2.1.0 resolution: "array-union@npm:2.1.0" @@ -10198,6 +10205,7 @@ __metadata: "@shopify/flash-list": 1.4.3 "@tanstack/react-query": ^4.32.6 "@types/react": 18.2.0 + array-shuffle: ^3.0.0 babel-plugin-transform-inline-environment-variables: ^0.4.4 expo: ^49.0.6 expo-build-properties: ~0.8.3 @@ -13864,6 +13872,7 @@ __metadata: "@types/node": 20.4.8 "@types/react": 18.2.0 "@types/react-dom": 18.2.0 + array-shuffle: ^3.0.0 copy-webpack-plugin: ^11.0.0 eslint: ^8.46.0 eslint-config-next: 13.4.13