mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-31 14:33:50 -04:00
Create a collection page
This commit is contained in:
parent
66fff153e1
commit
7622420f06
27
front/apps/mobile/app/collection/[slug]/index.tsx
Normal file
27
front/apps/mobile/app/collection/[slug]/index.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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 { CollectionPage } from "@kyoo/ui";
|
||||||
|
import { withRoute } from "../../../utils";
|
||||||
|
|
||||||
|
export default withRoute(CollectionPage, {
|
||||||
|
options: { headerTransparent: true, headerStyle: { backgroundColor: "transparent" } },
|
||||||
|
statusBar: { barStyle: "light-content" },
|
||||||
|
});
|
24
front/apps/web/src/pages/collection/[slug]/index.tsx
Normal file
24
front/apps/web/src/pages/collection/[slug]/index.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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 { CollectionPage } from "@kyoo/ui";
|
||||||
|
import { withRoute } from "~/router";
|
||||||
|
|
||||||
|
export default withRoute(CollectionPage);
|
171
front/packages/ui/src/collection/index.tsx
Normal file
171
front/packages/ui/src/collection/index.tsx
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
Collection,
|
||||||
|
CollectionP,
|
||||||
|
ItemKind,
|
||||||
|
LibraryItem,
|
||||||
|
LibraryItemP,
|
||||||
|
QueryIdentifier,
|
||||||
|
QueryPage,
|
||||||
|
getDisplayDate,
|
||||||
|
} from "@kyoo/models";
|
||||||
|
import { Header as ShowHeader, TitleLine } from "../details/header";
|
||||||
|
import { Container, ImageBackground, P, Skeleton, ts } from "@kyoo/primitives";
|
||||||
|
import { percent, px, useYoshiki } from "yoshiki/native";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { forwardRef } from "react";
|
||||||
|
import { Platform, View, ViewProps } from "react-native";
|
||||||
|
import { Fetch } from "../fetch";
|
||||||
|
import { InfiniteFetch } from "../fetch-infinite";
|
||||||
|
import { DefaultLayout } from "../layout";
|
||||||
|
import { ItemDetails } from "../home/recommanded";
|
||||||
|
import { SvgWave } from "../details/show";
|
||||||
|
|
||||||
|
const Header = ({ slug }: { slug: string }) => {
|
||||||
|
const { css } = useYoshiki();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fetch query={Header.query(slug)}>
|
||||||
|
{({ isLoading, ...data }) => (
|
||||||
|
<>
|
||||||
|
<ImageBackground
|
||||||
|
src={data?.thumbnail}
|
||||||
|
quality="high"
|
||||||
|
alt=""
|
||||||
|
containerStyle={ShowHeader.containerStyle}
|
||||||
|
>
|
||||||
|
<TitleLine
|
||||||
|
isLoading={isLoading}
|
||||||
|
type={"collection"}
|
||||||
|
playHref={null}
|
||||||
|
name={data?.name}
|
||||||
|
tagline={null}
|
||||||
|
date={null}
|
||||||
|
rating={null}
|
||||||
|
runtime={null}
|
||||||
|
poster={data?.poster}
|
||||||
|
trailerUrl={null}
|
||||||
|
studio={null}
|
||||||
|
{...css(ShowHeader.childStyle)}
|
||||||
|
/>
|
||||||
|
</ImageBackground>
|
||||||
|
|
||||||
|
<Container
|
||||||
|
{...css({
|
||||||
|
paddingTop: ts(4),
|
||||||
|
marginBottom: ts(4),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Skeleton lines={4}>
|
||||||
|
{isLoading || (
|
||||||
|
<P {...css({ textAlign: "justify" })}>{data.overview ?? t("show.noOverview")}</P>
|
||||||
|
)}
|
||||||
|
</Skeleton>
|
||||||
|
</Container>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Fetch>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Header.query = (slug: string): QueryIdentifier<Collection> => ({
|
||||||
|
parser: CollectionP,
|
||||||
|
path: ["collections", slug],
|
||||||
|
});
|
||||||
|
|
||||||
|
const CollectionHeader = forwardRef<View, ViewProps & { slug: string }>(function ShowHeader(
|
||||||
|
{ children, slug, ...props },
|
||||||
|
ref,
|
||||||
|
) {
|
||||||
|
const { css, theme } = useYoshiki();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
ref={ref}
|
||||||
|
{...css(
|
||||||
|
[
|
||||||
|
{ bg: (theme) => theme.variant.background },
|
||||||
|
Platform.OS === "web" && {
|
||||||
|
flexGrow: 1,
|
||||||
|
flexShrink: 1,
|
||||||
|
// @ts-ignore Web only property
|
||||||
|
overflowY: "auto" as any,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
props,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Header slug={slug} />
|
||||||
|
<SvgWave fill={theme.background} {...css({ flexShrink: 0, flexGrow: 1, display: "flex" })} />
|
||||||
|
<View {...css({ bg: theme.background, paddingTop: { xs: ts(8), md: 0 } })}>
|
||||||
|
<View
|
||||||
|
{...css({
|
||||||
|
maxWidth: { xs: percent(100), lg: px(1170) },
|
||||||
|
alignSelf: "center",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const query = (slug: string): QueryIdentifier<LibraryItem> => ({
|
||||||
|
parser: LibraryItemP,
|
||||||
|
path: ["collections", slug, "items"],
|
||||||
|
infinite: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CollectionPage: QueryPage<{ slug: string }> = ({ slug }) => {
|
||||||
|
const { css } = useYoshiki();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InfiniteFetch
|
||||||
|
query={query(slug)}
|
||||||
|
placeholderCount={15}
|
||||||
|
layout={{ ...ItemDetails.layout, numColumns: { xs: 1, md: 2 } }}
|
||||||
|
Header={CollectionHeader}
|
||||||
|
headerProps={{ slug }}
|
||||||
|
{...css({ padding: { xs: ts(1), sm: ts(8) } })}
|
||||||
|
>
|
||||||
|
{(x) => (
|
||||||
|
<ItemDetails
|
||||||
|
isLoading={x.isLoading as any}
|
||||||
|
name={x.name}
|
||||||
|
tagline={"tagline" in x ? x.tagline : null}
|
||||||
|
overview={x.overview}
|
||||||
|
poster={x.poster}
|
||||||
|
subtitle={x.kind !== ItemKind.Collection && !x.isLoading ? getDisplayDate(x) : undefined}
|
||||||
|
genres={"genres" in x ? x.genres : null}
|
||||||
|
href={x.href}
|
||||||
|
playHref={x.kind !== ItemKind.Collection && !x.isLoading ? x.playHref : undefined}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</InfiniteFetch>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
CollectionPage.getLayout = { Layout: DefaultLayout, props: { transparent: true } };
|
||||||
|
|
||||||
|
CollectionPage.getFetchUrls = ({ slug }) => [query(slug), Header.query(slug)];
|
@ -70,7 +70,7 @@ import Theaters from "@material-symbols/svg-400/rounded/theaters-fill.svg";
|
|||||||
import { Rating } from "../components/rating";
|
import { Rating } from "../components/rating";
|
||||||
import { displayRuntime } from "./episode";
|
import { displayRuntime } from "./episode";
|
||||||
|
|
||||||
const TitleLine = ({
|
export const TitleLine = ({
|
||||||
isLoading,
|
isLoading,
|
||||||
playHref,
|
playHref,
|
||||||
name,
|
name,
|
||||||
@ -89,12 +89,12 @@ const TitleLine = ({
|
|||||||
name?: string;
|
name?: string;
|
||||||
tagline?: string | null;
|
tagline?: string | null;
|
||||||
date?: string | null;
|
date?: string | null;
|
||||||
rating?: number;
|
rating?: number | null;
|
||||||
runtime?: number | null;
|
runtime?: number | null;
|
||||||
poster?: KyooImage | null;
|
poster?: KyooImage | null;
|
||||||
studio?: Studio | null;
|
studio?: Studio | null;
|
||||||
trailerUrl?: string | null;
|
trailerUrl?: string | null;
|
||||||
type: "movie" | "show";
|
type: "movie" | "show" | "collection";
|
||||||
} & Stylable) => {
|
} & Stylable) => {
|
||||||
const { css, theme } = useYoshiki();
|
const { css, theme } = useYoshiki();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -222,8 +222,12 @@ const TitleLine = ({
|
|||||||
{...tooltip(t("show.trailer"))}
|
{...tooltip(t("show.trailer"))}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<DottedSeparator />
|
{rating !== null && (
|
||||||
<Rating rating={rating} />
|
<>
|
||||||
|
<DottedSeparator />
|
||||||
|
<Rating rating={rating} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{runtime && (
|
{runtime && (
|
||||||
<>
|
<>
|
||||||
<DottedSeparator />
|
<DottedSeparator />
|
||||||
|
@ -28,7 +28,7 @@ import Svg, { Path, SvgProps } from "react-native-svg";
|
|||||||
import { Container } from "@kyoo/primitives";
|
import { Container } from "@kyoo/primitives";
|
||||||
import { forwardRef } from "react";
|
import { forwardRef } from "react";
|
||||||
|
|
||||||
const SvgWave = (props: SvgProps) => {
|
export const SvgWave = (props: SvgProps) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
const width = 612;
|
const width = 612;
|
||||||
const height = 52.771;
|
const height = 52.771;
|
||||||
@ -58,11 +58,7 @@ const ShowHeader = forwardRef<View, ViewProps & { slug: string }>(function ShowH
|
|||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
// @ts-ignore Web only property
|
// @ts-ignore Web only property
|
||||||
overflow: "auto" as any,
|
overflowY: "auto" as any,
|
||||||
// @ts-ignore Web only property
|
|
||||||
overflowX: "hidden",
|
|
||||||
// @ts-ignore Web only property
|
|
||||||
overflowY: "overlay",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
props,
|
props,
|
||||||
|
@ -176,7 +176,6 @@ export const Recommanded = () => {
|
|||||||
>
|
>
|
||||||
{(x, i) => (
|
{(x, i) => (
|
||||||
<ItemDetails
|
<ItemDetails
|
||||||
key={x.id ?? i}
|
|
||||||
isLoading={x.isLoading as any}
|
isLoading={x.isLoading as any}
|
||||||
name={x.name}
|
name={x.name}
|
||||||
tagline={"tagline" in x ? x.tagline : null}
|
tagline={"tagline" in x ? x.tagline : null}
|
||||||
|
@ -22,6 +22,7 @@ export * from "./navbar";
|
|||||||
export { HomePage } from "./home";
|
export { HomePage } from "./home";
|
||||||
export { BrowsePage } from "./browse";
|
export { BrowsePage } from "./browse";
|
||||||
export { MovieDetails, ShowDetails } from "./details";
|
export { MovieDetails, ShowDetails } from "./details";
|
||||||
|
export { CollectionPage } from "./collection";
|
||||||
export { Player } from "./player";
|
export { Player } from "./player";
|
||||||
export { SearchPage } from "./search";
|
export { SearchPage } from "./search";
|
||||||
export { LoginPage, RegisterPage } from "./login";
|
export { LoginPage, RegisterPage } from "./login";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user