mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add random genres list to the home page
This commit is contained in:
parent
d21e4ffba2
commit
5a618a8db2
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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<any>(pageProps ?? { json: {} });
|
||||
const { queryState, token, randomItems, ...props } = superjson.deserialize<any>(
|
||||
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) => {
|
||||
<Hydrate state={queryState}>
|
||||
<ThemeSelector theme="auto" font={{ normal: "inherit" }}>
|
||||
<GlobalCssTheme />
|
||||
<Layout page={<Component {...props} />} {...layoutProps} />
|
||||
<Layout
|
||||
page={
|
||||
<Component
|
||||
randomItems={
|
||||
randomItems[Component.displayName!] ??
|
||||
arrayShuffle((Component as QueryPage).randomItems ?? [])
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
}
|
||||
randomItems={[]}
|
||||
{...layoutProps}
|
||||
/>
|
||||
</ThemeSelector>
|
||||
</Hydrate>
|
||||
</QueryClientProvider>
|
||||
@ -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) };
|
||||
};
|
||||
|
@ -162,11 +162,12 @@ export type QueryIdentifier<T = unknown, Ret = T> = {
|
||||
getNext?: (item: unknown) => string | undefined;
|
||||
};
|
||||
|
||||
export type QueryPage<Props = {}> = ComponentType<Props> & {
|
||||
export type QueryPage<Props = {}, Items = unknown> = ComponentType<Props & { randomItems: Items[]}> & {
|
||||
getFetchUrls?: (route: { [key: string]: string }) => QueryIdentifier<any>[];
|
||||
getLayout?:
|
||||
| QueryPage<{ page: ReactElement }>
|
||||
| { Layout: QueryPage<{ page: ReactElement }>; props: object };
|
||||
randomItems?: Items[]
|
||||
};
|
||||
|
||||
const toQueryKey = <Data, Ret>(query: QueryIdentifier<Data, Ret>) => {
|
||||
|
86
front/packages/ui/src/home/genre.tsx
Normal file
86
front/packages/ui/src/home/genre.tsx
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<ScrollView>(null);
|
||||
const { css } = useYoshiki();
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View {...css({ marginX: ts(1), flexDirection: "row", justifyContent: "space-between" })}>
|
||||
<H3>{genre}</H3>
|
||||
<View {...css({ flexDirection: "row" })}>
|
||||
<IconButton
|
||||
icon={ChevronLeft}
|
||||
onPress={() => ref.current?.scrollTo({ x: 0, animated: true })}
|
||||
/>
|
||||
<IconButton
|
||||
icon={ChevronRight}
|
||||
onPress={() => ref.current?.scrollTo({ x: 0, animated: true })}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<ScrollView ref={ref} horizontal>
|
||||
<Fetch query={GenreGrid.query(genre)}>
|
||||
{(x, i) => (
|
||||
<ItemGrid
|
||||
key={x.id ?? i}
|
||||
isLoading={x.isLoading as any}
|
||||
href={x.href}
|
||||
name={x.name}
|
||||
subtitle={
|
||||
x.kind !== ItemKind.Collection && !x.isLoading ? getDisplayDate(x) : undefined
|
||||
}
|
||||
poster={x.poster}
|
||||
/>
|
||||
)}
|
||||
</Fetch>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
GenreGrid.query = (genre: Genre): QueryIdentifier<Page<LibraryItem>> => ({
|
||||
parser: Paged(LibraryItemP) as any,
|
||||
path: ["items"],
|
||||
params: {
|
||||
genres: genre,
|
||||
sortBy: "random",
|
||||
},
|
||||
});
|
@ -18,29 +18,41 @@
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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 (
|
||||
<Fetch query={Header.query()}>
|
||||
{(x) => (
|
||||
<Header
|
||||
isLoading={x.isLoading as any}
|
||||
name={x.name}
|
||||
tagline={"tagline" in x ? x.tagline : null}
|
||||
overview={x.overview}
|
||||
thumbnail={x.thumbnail}
|
||||
link={x.kind === ItemKind.Show ? `/watch/${x.slug}-s1e1` : `/movie/${x.slug}/watch`}
|
||||
infoLink={x.href}
|
||||
/>
|
||||
)}
|
||||
</Fetch>
|
||||
<ScrollView>
|
||||
<Fetch query={Header.query()}>
|
||||
{(x) => (
|
||||
<Header
|
||||
isLoading={x.isLoading as any}
|
||||
name={x.name}
|
||||
tagline={"tagline" in x ? x.tagline : null}
|
||||
overview={x.overview}
|
||||
thumbnail={x.thumbnail}
|
||||
link={x.kind === ItemKind.Show ? `/watch/${x.slug}-s1e1` : `/movie/${x.slug}/watch`}
|
||||
infoLink={x.href}
|
||||
/>
|
||||
)}
|
||||
</Fetch>
|
||||
{randomItems.map((x) => (
|
||||
<GenreGrid key={x} genre={x} />
|
||||
))}
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
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)),
|
||||
];
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user