mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Add tags on shows and movies
This commit is contained in:
parent
be3724c6b1
commit
fd3c2e5f9b
@ -22,17 +22,24 @@ import { rem, Stylable, Theme, useYoshiki } from "yoshiki/native";
|
|||||||
import { P } from "./text";
|
import { P } from "./text";
|
||||||
import { ts } from "./utils";
|
import { ts } from "./utils";
|
||||||
|
|
||||||
export const Chip = ({ label, color, ...props }: { label: string; color?: string } & Stylable) => {
|
export const Chip = ({
|
||||||
|
label,
|
||||||
|
color,
|
||||||
|
size = "medium",
|
||||||
|
...props
|
||||||
|
}: { label: string; color?: string; size?: "small" | "medium" | "large" } & Stylable) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
|
|
||||||
|
const sizeMult = size == "medium" ? 1 : size == "small" ? 0.75 : 1.25;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<P
|
<P
|
||||||
{...css(
|
{...css(
|
||||||
{
|
{
|
||||||
pY: ts(1),
|
pY: ts(1 * sizeMult),
|
||||||
pX: ts(1.5),
|
pX: ts(1.5 * sizeMult),
|
||||||
borderRadius: ts(3),
|
borderRadius: ts(3),
|
||||||
fontSize: rem(.8),
|
fontSize: rem(0.8),
|
||||||
color: (theme: Theme) => theme.contrast,
|
color: (theme: Theme) => theme.contrast,
|
||||||
bg: color ?? ((theme: Theme) => theme.accent),
|
bg: color ?? ((theme: Theme) => theme.accent),
|
||||||
},
|
},
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ComponentType, ComponentProps } from "react";
|
import { ComponentType, ComponentProps, ReactNode } from "react";
|
||||||
import { Platform, Text, TextProps, TextStyle, StyleProp } from "react-native";
|
import { Platform, Text, TextProps, TextStyle, StyleProp } from "react-native";
|
||||||
import { percent, rem, useYoshiki } from "yoshiki/native";
|
import { percent, rem, useYoshiki } from "yoshiki/native";
|
||||||
import {
|
import {
|
||||||
@ -37,7 +37,7 @@ const styleText = (
|
|||||||
type?: "header" | "sub",
|
type?: "header" | "sub",
|
||||||
custom?: TextStyle,
|
custom?: TextStyle,
|
||||||
) => {
|
) => {
|
||||||
const Text = (props: Omit<ComponentProps<typeof EP>, "style"> & { style?: StyleProp<TextStyle> }) => {
|
const Text = (props: Omit<ComponentProps<typeof EP>, "style"> & { style?: StyleProp<TextStyle>, children?: TextProps["children"] }) => {
|
||||||
const { css, theme } = useYoshiki();
|
const { css, theme } = useYoshiki();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Movie, QueryIdentifier, Show, getDisplayDate, Genre, Studio } from "@kyoo/models";
|
import { Movie, QueryIdentifier, Show, getDisplayDate, Genre, Studio, KyooImage } from "@kyoo/models";
|
||||||
import {
|
import {
|
||||||
Container,
|
Container,
|
||||||
H1,
|
H1,
|
||||||
@ -37,11 +37,11 @@ import {
|
|||||||
LI,
|
LI,
|
||||||
A,
|
A,
|
||||||
ts,
|
ts,
|
||||||
Button,
|
Chip,
|
||||||
} from "@kyoo/primitives";
|
} from "@kyoo/primitives";
|
||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Platform, Pressable, PressableProps, View } from "react-native";
|
import { Platform, View } from "react-native";
|
||||||
import {
|
import {
|
||||||
Theme,
|
Theme,
|
||||||
md,
|
md,
|
||||||
@ -73,7 +73,7 @@ const TitleLine = ({
|
|||||||
slug: string;
|
slug: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
date?: string;
|
date?: string;
|
||||||
poster?: string | null;
|
poster?: KyooImage | null;
|
||||||
studio?: Studio | null;
|
studio?: Studio | null;
|
||||||
trailerUrl?: string | null;
|
trailerUrl?: string | null;
|
||||||
} & Stylable) => {
|
} & Stylable) => {
|
||||||
@ -99,12 +99,13 @@ const TitleLine = ({
|
|||||||
<Poster
|
<Poster
|
||||||
src={poster}
|
src={poster}
|
||||||
alt={name}
|
alt={name}
|
||||||
|
quality="high"
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
layout={{
|
layout={{
|
||||||
width: { xs: percent(50), md: percent(25) },
|
width: { xs: percent(50), md: percent(25) },
|
||||||
}}
|
}}
|
||||||
{...css({
|
{...css({
|
||||||
maxWidth: { xs: px(175), sm: Platform.OS === "web" ? "unset" : 99999999 },
|
maxWidth: { xs: px(175), sm: Platform.OS === "web" ? "unset" as any : 99999999 },
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@ -227,11 +228,13 @@ const TitleLine = ({
|
|||||||
const Description = ({
|
const Description = ({
|
||||||
isLoading,
|
isLoading,
|
||||||
overview,
|
overview,
|
||||||
|
tags,
|
||||||
genres,
|
genres,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
overview?: string | null;
|
overview?: string | null;
|
||||||
|
tags?: string[];
|
||||||
genres?: Genre[];
|
genres?: Genre[];
|
||||||
} & Stylable) => {
|
} & Stylable) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -249,40 +252,40 @@ const Description = ({
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{t("show.genre")}:{" "}
|
{t("show.genre")}:{" "}
|
||||||
{(isLoading ? [...Array(3)] : genres!).map((genre, i) => (
|
{(isLoading ? [...Array<Genre>(3)] : genres!).map((genre, i) => (
|
||||||
<Fragment key={genre?.slug ?? i.toString()}>
|
<Fragment key={genre ?? i.toString()}>
|
||||||
<P {...css({ m: 0 })}>{i !== 0 && ", "}</P>
|
<P {...css({ m: 0 })}>{i !== 0 && ", "}</P>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<Skeleton {...css({ width: rem(5) })} />
|
<Skeleton {...css({ width: rem(5) })} />
|
||||||
) : (
|
) : (
|
||||||
<A href={`/genres/${genre.slug}`}>{genre.name}</A>
|
<A href={`/genres/${genre.toLowerCase()}`}>{genre}</A>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</P>
|
</P>
|
||||||
|
|
||||||
<Skeleton
|
<View {...css({
|
||||||
lines={4}
|
flexDirection: "column",
|
||||||
{...css({
|
flexGrow: 1,
|
||||||
width: percent(100),
|
flexBasis: { sm: 0 },
|
||||||
flexBasis: 0,
|
paddingTop: ts(4),
|
||||||
flexGrow: 1,
|
})}>
|
||||||
paddingTop: ts(4),
|
<Skeleton lines={4} >
|
||||||
})}
|
{isLoading || (
|
||||||
>
|
<P
|
||||||
{isLoading || (
|
{...css({ textAlign: "justify", })}
|
||||||
<P
|
>
|
||||||
{...css({
|
{overview ?? t("show.noOverview")}
|
||||||
flexBasis: 0,
|
</P>
|
||||||
flexGrow: 1,
|
)}
|
||||||
textAlign: "justify",
|
</Skeleton>
|
||||||
paddingTop: ts(4),
|
<View {...css({ flexWrap: "wrap", flexDirection: "row", marginTop: ts(.5) })}>
|
||||||
})}
|
<P {...css({ marginRight: ts(.5) })}>{t("show.tags")}:</P>
|
||||||
>
|
{(isLoading ? [...Array<string>(3)] : tags!).map((tag, i) => (
|
||||||
{overview ?? t("show.noOverview")}
|
<Chip key={tag ?? i} label={tag} size="small" {...css({ m: ts(.5) })} />
|
||||||
</P>
|
))}
|
||||||
)}
|
</View>
|
||||||
</Skeleton>
|
</View>
|
||||||
<HR
|
<HR
|
||||||
orientation="vertical"
|
orientation="vertical"
|
||||||
{...css({ marginX: ts(2), display: { xs: "none", sm: "flex" } })}
|
{...css({ marginX: ts(2), display: { xs: "none", sm: "flex" } })}
|
||||||
@ -291,12 +294,12 @@ const Description = ({
|
|||||||
<H2>{t("show.genre")}</H2>
|
<H2>{t("show.genre")}</H2>
|
||||||
{isLoading || genres?.length ? (
|
{isLoading || genres?.length ? (
|
||||||
<UL>
|
<UL>
|
||||||
{(isLoading ? [...Array(3)] : genres!).map((genre, i) => (
|
{(isLoading ? [...Array<Genre>(3)] : genres!).map((genre, i) => (
|
||||||
<LI key={genre?.id ?? i}>
|
<LI key={genre ?? i}>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<Skeleton {...css({ marginBottom: 0 })} />
|
<Skeleton {...css({ marginBottom: 0 })} />
|
||||||
) : (
|
) : (
|
||||||
<A href={`/genres/${genre.slug}`}>{genre.name}</A>
|
<A href={`/genres/${genre.toLowerCase()}`}>{genre}</A>
|
||||||
)}
|
)}
|
||||||
</LI>
|
</LI>
|
||||||
))}
|
))}
|
||||||
@ -352,6 +355,7 @@ export const Header = ({ query, slug }: { query: QueryIdentifier<Show | Movie>;
|
|||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
overview={data?.overview}
|
overview={data?.overview}
|
||||||
genres={data?.genres}
|
genres={data?.genres}
|
||||||
|
tags={data?.tags}
|
||||||
{...css({ paddingTop: { xs: 0, md: ts(2) } })}
|
{...css({ paddingTop: { xs: 0, md: ts(2) } })}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -26,9 +26,9 @@ import { Header } from "./header";
|
|||||||
|
|
||||||
const query = (slug: string): QueryIdentifier<Movie> => ({
|
const query = (slug: string): QueryIdentifier<Movie> => ({
|
||||||
parser: MovieP,
|
parser: MovieP,
|
||||||
path: ["shows", slug],
|
path: ["movies", slug],
|
||||||
params: {
|
params: {
|
||||||
fields: ["genres", "studio"],
|
fields: ["studio"],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ const query = (slug: string): QueryIdentifier<Show> => ({
|
|||||||
parser: ShowP,
|
parser: ShowP,
|
||||||
path: ["shows", slug],
|
path: ["shows", slug],
|
||||||
params: {
|
params: {
|
||||||
fields: ["genres", "studio"],
|
fields: ["studio"],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
"staff-none": "The staff is unknown",
|
"staff-none": "The staff is unknown",
|
||||||
"noOverview": "No overview available",
|
"noOverview": "No overview available",
|
||||||
"episode-none": "There is no episodes in this season",
|
"episode-none": "There is no episodes in this season",
|
||||||
"episodeNoMetadata": "No metadata available"
|
"episodeNoMetadata": "No metadata available",
|
||||||
|
"tags": "Tags"
|
||||||
},
|
},
|
||||||
"browse": {
|
"browse": {
|
||||||
"sortby": "Sort by {{key}}",
|
"sortby": "Sort by {{key}}",
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
"staff-none": "Aucun membre du staff connu",
|
"staff-none": "Aucun membre du staff connu",
|
||||||
"noOverview": "Aucune description disponible",
|
"noOverview": "Aucune description disponible",
|
||||||
"episode-none": "Il n'y a pas d'épisodes dans cette saison",
|
"episode-none": "Il n'y a pas d'épisodes dans cette saison",
|
||||||
"episodeNoMetadata": "Aucune metadonnée disponible"
|
"episodeNoMetadata": "Aucune metadonnée disponible",
|
||||||
|
"tags": "Tags"
|
||||||
},
|
},
|
||||||
"browse": {
|
"browse": {
|
||||||
"sortby": "Trier par {{key}}",
|
"sortby": "Trier par {{key}}",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user