diff --git a/front/apps/mobile/package.json b/front/apps/mobile/package.json index 31aa7031..bae2835f 100644 --- a/front/apps/mobile/package.json +++ b/front/apps/mobile/package.json @@ -31,7 +31,7 @@ "react-native-safe-area-context": "4.4.1", "react-native-screens": "~3.18.0", "react-native-svg": "13.4.0", - "yoshiki": "0.2.11" + "yoshiki": "0.3.1" }, "devDependencies": { "@babel/core": "^7.19.3", diff --git a/front/apps/web/package.json b/front/apps/web/package.json index decc5b87..7b19a513 100644 --- a/front/apps/web/package.json +++ b/front/apps/web/package.json @@ -41,7 +41,7 @@ "react-native-web": "^0.18.10", "solito": "^2.0.5", "superjson": "^1.11.0", - "yoshiki": "0.2.11", + "yoshiki": "0.3.1", "zod": "^3.19.1" }, "devDependencies": { diff --git a/front/packages/primitives/src/container.tsx b/front/packages/primitives/src/container.tsx index b7064bb6..4a4dbbbe 100644 --- a/front/packages/primitives/src/container.tsx +++ b/front/packages/primitives/src/container.tsx @@ -19,7 +19,7 @@ */ import { View, ViewProps } from "react-native"; -import { useYoshiki } from "yoshiki/native"; +import { percent, px, useYoshiki } from "yoshiki/native"; export const Container = (props: ViewProps) => { const { css } = useYoshiki(); @@ -29,12 +29,13 @@ export const Container = (props: ViewProps) => { {...css( { display: "flex", - paddingHorizontal: "15px", + paddingHorizontal: px(15), marginHorizontal: "auto", width: { - sm: "540px", - md: "880px", - lg: "1170px", + xs: percent(100), + sm: px(540), + md: px(880), + lg: px(1170), }, }, props, diff --git a/front/packages/primitives/src/divider.tsx b/front/packages/primitives/src/divider.tsx new file mode 100644 index 00000000..6878226c --- /dev/null +++ b/front/packages/primitives/src/divider.tsx @@ -0,0 +1,56 @@ +/* + * 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 { HR as EHR } from "@expo/html-elements"; +import { percent, px, Stylable, useYoshiki } from "yoshiki/native"; +import { alpha, ts } from "."; + +export const HR = ({ + orientation, + ...props +}: { orientation: "vertical" | "horizontal" } & Stylable) => { + const { css } = useYoshiki(); + + return ( + alpha(theme.overlay0, 0.7), + borderWidth: 0, + }, + orientation === "vertical" && { + width: px(1), + height: "auto", + marginVertical: ts(1), + marginHorizontal: ts(2), + }, + orientation === "horizontal" && { + height: px(1), + width: "auto", + marginHorizontal: ts(1), + marginVertical: ts(2), + }, + ], + props, + )} + /> + ); +}; diff --git a/front/packages/primitives/src/index.ts b/front/packages/primitives/src/index.ts index 38bba259..8e4f47d4 100644 --- a/front/packages/primitives/src/index.ts +++ b/front/packages/primitives/src/index.ts @@ -18,7 +18,7 @@ * along with Kyoo. If not, see . */ -export { Header, Main, Nav, Footer } from "@expo/html-elements"; +export { Header, Main, Nav, Footer, UL } from "@expo/html-elements"; export * from "./text"; export * from "./themes"; export * from "./icons"; @@ -28,11 +28,13 @@ export * from "./image"; export * from "./skeleton"; export * from "./tooltip"; export * from "./container"; +export * from "./divider"; export * from "./animated"; export * from "./utils/breakpoints"; export * from "./utils/nojs"; +export * from "./utils/head"; import { px } from "yoshiki/native"; diff --git a/front/packages/primitives/src/links.tsx b/front/packages/primitives/src/links.tsx index ca7c9135..41ddda46 100644 --- a/front/packages/primitives/src/links.tsx +++ b/front/packages/primitives/src/links.tsx @@ -43,10 +43,13 @@ export const A = ({ textProps={css( { // TODO: use a real font here. - fontFamily: Platform.OS === "web" ? theme.fonts.paragraph : undefined, - color: theme.paragraph, + // fontFamily: theme.fonts.paragraph, + color: theme.link, + }, + { + selectable: true, + ...props, }, - props, )} > {children} @@ -83,8 +86,8 @@ export const Link = ({ })} > {Platform.select({ - android: {children}, - ios: {children}, + android: {children}, + ios: {children}, default: children, })} diff --git a/front/packages/primitives/src/skeleton.tsx b/front/packages/primitives/src/skeleton.tsx index 2fef683b..7d019b93 100644 --- a/front/packages/primitives/src/skeleton.tsx +++ b/front/packages/primitives/src/skeleton.tsx @@ -46,11 +46,13 @@ export const SkeletonCss = () => ( export const Skeleton = ({ children, show: forcedShow, + lines = 1, variant = "text", ...props }: Omit & { children?: JSX.Element | JSX.Element[] | boolean | null; show?: boolean; + lines?: number; variant?: "text" | "round" | "custom"; }) => { const { css, theme } = useYoshiki(); @@ -65,13 +67,14 @@ export const Skeleton = ({ [ { position: "relative", - overflow: "hidden", - borderRadius: px(6), - }, - variant === "text" && { - width: percent(75), - height: rem(1.2), }, + lines === 1 && { overflow: "hidden", borderRadius: px(6) }, + variant === "text" && + lines === 1 && { + width: percent(75), + height: rem(1.2), + marginBottom: rem(0.5), + }, variant === "round" && { borderRadius: 9999999, }, @@ -81,56 +84,68 @@ export const Skeleton = ({ > {children} - {(forcedShow || !children || children === true) && ( - setWidth(e.nativeEvent.layout.width)} - {...css( - { - bg: (theme) => theme.overlay0, - position: "absolute", - top: 0, - bottom: 0, - left: 0, - right: 0, - }, - hiddenIfNoJs, - )} - > - - - )} + {(forcedShow || !children || children === true) && + [...Array(lines)].map((_, i) => ( + setWidth(e.nativeEvent.layout.width)} + {...css( + [ + { + bg: (theme) => theme.overlay0, + }, + lines === 1 && { + position: "absolute", + top: 0, + bottom: 0, + left: 0, + right: 0, + }, + lines !== 1 && { + width: i === lines - 1 ? percent(40) : percent(100), + height: rem(1.2), + marginBottom: rem(0.5), + overflow: "hidden", + borderRadius: px(6), + }, + ], + hiddenIfNoJs, + )} + > + + + ))} ); diff --git a/front/packages/primitives/src/text.tsx b/front/packages/primitives/src/text.tsx index e1d5fc2b..db40edb0 100644 --- a/front/packages/primitives/src/text.tsx +++ b/front/packages/primitives/src/text.tsx @@ -19,8 +19,8 @@ */ import { ComponentType, ComponentProps } from "react"; -import { Platform, TextProps } from "react-native"; -import { rem, useYoshiki } from "yoshiki/native"; +import { Platform, Text, TextProps, TextStyle } from "react-native"; +import { percent, px, rem, useYoshiki } from "yoshiki/native"; import { H1 as EH1, H2 as EH2, @@ -29,11 +29,14 @@ import { H5 as EH5, H6 as EH6, P as EP, + LI as ELI, } from "@expo/html-elements"; +import { ts } from "."; const styleText = ( Component: ComponentType>, type?: "header" | "sub", + custom?: TextStyle, ) => { const Text = (props: ComponentProps) => { const { css, theme } = useYoshiki(); @@ -43,16 +46,13 @@ const styleText = ( {...css( [ { - // TODO: use custom fonts on mobile also. - fontFamily: - Platform.OS === "web" - ? type === "header" - ? theme.fonts.heading - : theme.fonts.paragraph - : undefined, + marginTop: 0, + marginBottom: rem(0.5), + // fontFamily: type === "header" ? theme.fonts.heading : theme.fonts.paragraph, color: type === "header" ? theme.heading : theme.paragraph, }, type === "sub" && { fontWeight: "300", opacity: 0.8, fontSize: rem(0.8) }, + custom, ], props as TextProps, )} @@ -62,12 +62,31 @@ const styleText = ( return Text; }; -export const H1 = styleText(EH1, "header"); -export const H2 = styleText(EH2, "header"); +export const H1 = styleText(EH1, "header", { fontSize: rem(3) }); +export const H2 = styleText(EH2, "header", { fontSize: rem(2) }); export const H3 = styleText(EH3, "header"); export const H4 = styleText(EH4, "header"); export const H5 = styleText(EH5, "header"); export const H6 = styleText(EH6, "header"); export const Heading = styleText(EP, "header"); -export const P = styleText(EP); +export const P = styleText(EP, undefined, { fontSize: rem(1) }); export const SubP = styleText(EP, "sub"); + +export const LI = ({ children, ...props }: TextProps) => { + const { css } = useYoshiki(); + + return ( +

+ + {String.fromCharCode(0x2022)} + + {children} +

+ ); +}; diff --git a/front/packages/primitives/src/themes/catppuccin.ts b/front/packages/primitives/src/themes/catppuccin.ts index 99108b1c..7c025a7e 100644 --- a/front/packages/primitives/src/themes/catppuccin.ts +++ b/front/packages/primitives/src/themes/catppuccin.ts @@ -31,6 +31,7 @@ export const catppuccin: ThemeBuilder = { appbar: "#e64553", overlay0: "#9ca0b0", overlay1: "#7c7f93", + link: "#1e66f5", default: { background: "#eff1f5", accent: "#ea76cb", @@ -61,6 +62,7 @@ export const catppuccin: ThemeBuilder = { appbar: "#94e2d5", overlay0: "#6c7086", overlay1: "#9399b2", + link: "#89b4fa", default: { background: "#1e1e2e", accent: "#f5c2e7", diff --git a/front/packages/primitives/src/themes/theme.tsx b/front/packages/primitives/src/themes/theme.tsx index 399b0dca..a7c3ab51 100644 --- a/front/packages/primitives/src/themes/theme.tsx +++ b/front/packages/primitives/src/themes/theme.tsx @@ -37,6 +37,7 @@ type Mode = { appbar: Property.Color; overlay0: Property.Color; overlay1: Property.Color; + link: Property.Color; variant: Variant; colors: { red: Property.Color; @@ -64,13 +65,13 @@ declare module "yoshiki" { user: Mode & Variant; } } -// declare module "yoshiki/native" { -// export interface Theme extends ThemeSettings, Mode, Variant { -// light: Mode & Variant; -// dark: Mode & Variant; -// user: Mode & Variant; -// } -// } +declare module "yoshiki/native" { + export interface Theme extends ThemeSettings, Mode, Variant { + light: Mode & Variant; + dark: Mode & Variant; + user: Mode & Variant; + } +} export type { Theme } from "yoshiki"; export type ThemeBuilder = ThemeSettings & { @@ -158,5 +159,5 @@ export const ContrastArea = ({ }; export const alpha = (color: Property.Color, alpha: number) => { - return color + (alpha * 255).toString(16); + return color + Math.round(alpha * 255).toString(16); }; diff --git a/front/packages/primitives/src/utils/head.tsx b/front/packages/primitives/src/utils/head.tsx new file mode 100644 index 00000000..0764f690 --- /dev/null +++ b/front/packages/primitives/src/utils/head.tsx @@ -0,0 +1,23 @@ +/* + * 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 . + */ + +export const Head = ({ title, description }: { title?: string | null; description?: string | null }) => { + return null; +}; diff --git a/front/packages/primitives/src/utils/head.web.tsx b/front/packages/primitives/src/utils/head.web.tsx new file mode 100644 index 00000000..ec8a2714 --- /dev/null +++ b/front/packages/primitives/src/utils/head.web.tsx @@ -0,0 +1,30 @@ +/* + * 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 NextHead from "next/head"; + +export const Head = ({ title, description }: { title?: string | null; description?: string | null }) => { + return ( + + {title && {title + "- Kyoo"}} + {description && } + + ); +}; diff --git a/front/packages/ui/src/details/header.tsx b/front/packages/ui/src/details/header.tsx index aefcb5d3..00e76cab 100644 --- a/front/packages/ui/src/details/header.tsx +++ b/front/packages/ui/src/details/header.tsx @@ -18,7 +18,7 @@ * along with Kyoo. If not, see . */ -import { Movie, QueryIdentifier, Show, getDisplayDate } from "@kyoo/models"; +import { Movie, QueryIdentifier, Show, getDisplayDate, Genre, Studio } from "@kyoo/models"; import { Container, H1, @@ -31,43 +31,40 @@ import { Link, IconButton, IconFab, + Head, + HR, + H2, + UL, + LI, + A, + ts, } from "@kyoo/primitives"; import { useTranslation } from "react-i18next"; -import { Platform, StyleSheet, View } from "react-native"; -import { em, percent, rem, vh, useYoshiki, Stylable } from "yoshiki/native"; -import { Fetch, WithLoading } from "../fetch"; +import { StyleSheet, View } from "react-native"; +import { + Theme, + sm, + md, + px, + min, + max, + em, + percent, + rem, + vh, + useYoshiki, + Stylable, +} from "yoshiki/native"; +import { Fetch } from "../fetch"; import { Navbar } from "../navbar"; -// const StudioText = ({ -// studio, -// loading = false, -// sx, -// }: { -// studio?: Studio | null; -// loading?: boolean; -// sx?: SxProps; -// }) => { -// const { t } = useTranslation("browse"); - -// if (!loading && !studio) return null; -// return ( -// -// {t("show.studio")}:{" "} -// {loading ? ( -// -// ) : ( -// {studio!.name} -// )} -// -// ); -// }; - const TitleLine = ({ isLoading, slug, name, date, poster, + studio, ...props }: { isLoading: boolean; @@ -75,6 +72,7 @@ const TitleLine = ({ name?: string; date?: string; poster?: string | null; + studio?: Studio | null; } & Stylable) => { const { css, theme } = useYoshiki(); const { t } = useTranslation(); @@ -83,162 +81,197 @@ const TitleLine = ({ - - - {isLoading || ( -

({ xs: theme.user.heading, md: theme.heading }), - })} - > - {name} -

- )} -
- {(isLoading || date) && ( - + + + {isLoading || ( -

({ xs: theme.user.heading, md: theme.heading }), + fontWeight: { md: "900" }, + textAlign: { xs: "center", sm: "left" }, + color: (theme: Theme) => ({ xs: theme.user.heading, md: theme.heading }), })} > - {date} -

+ {name} + )}
- )} - *": { m: ".3rem !important" } }} */> - - + {(isLoading || date) && ( + + {isLoading || ( +

({ xs: theme.user.heading, md: theme.heading }), + })} + > + {date} +

+ )} +
+ )} + + + +
- {/* */} - {/* {(isLoading || logo || true) && ( */} - {/* */} - {/* )} */} - {/* {/1* *1/} */} - {/* */} + +

theme.user.paragraph, + })} + > + {t("show.studio")}:{" "} + {isLoading ? ( + + ) : ( + theme.user.link })}> + {studio!.name} + + )} +

+
); }; -// const Tata = () => { -// return ( -// -// -// {data -// ? data.overview ?? t("show.noOverview") -// : [...Array(4)].map((_, i) => )} -// -// -// -// +const Description = ({ + isLoading, + overview, + genres, + ...props +}: { + isLoading: boolean; + overview?: string | null; + genres?: Genre[]; +} & Stylable) => { + const { t } = useTranslation(); + const { css } = useYoshiki(); -// -// {t("show.genre")} -// -// {!data || data.genres?.length ? ( -//
    -// {(data ? data.genres! : [...Array(3)]).map((genre, i) => ( -//
  • -// -// {genre ? {genre.name} : } -// -//
  • -// ))} -//
-// ) : ( -// {t("show.genre-none")} -// )} -//
-//
-// ); -// }; + return ( + +

theme.user.paragraph, + })} + > + {t("show.genre")}:{" "} + {(isLoading ? [...Array(3)] : genres!).map((genre, i) => ( + <> + {i !== 0 && ", "} + {isLoading ? ( + + ) : ( + + {genre.name} + + )} + + ))} +

-const min = Platform.OS === "web" - ? (...values: number[]): number => `min(${values.join(", ")})` as unknown as number - : (...values: number[]): number => Math.min(...values); -const max = Platform.OS === "web" - ? (...values: number[]): number => `max(${values.join(", ")})` as unknown as number - : (...values: number[]): number => Math.max(...values); -const px = Platform.OS === "web" - ? (value: number): number => `${value}px` as unknown as number - : (value: number): number => value; + + {isLoading || ( +

+ {overview ?? t("show.noOverview")} +

+ )} +
+
+ +

{t("show.genre")}

+ {isLoading || genres?.length ? ( +
    + {(isLoading ? [...Array(3)] : genres!).map((genre, i) => ( +
  • + {isLoading ? ( + + ) : ( + {genre.name} + )} +
  • + ))} +
+ ) : ( +

{t("show.genre-none")}

+ )} +
+
+ ); +}; export const ShowHeader = ({ query, @@ -256,19 +289,22 @@ export const ShowHeader = ({ {({ isLoading, ...data }) => ( - <> - {/* TODO: HEAD element for SEO*/} +
+ {/* TODO: Add a shadow on navbar items */} {/* TODO: Put the navbar outside of the scrollbox */} - {/* */} - {/* */} - {/* */} - {/* {t("show.genre")} */} - {/* {": "} */} - {/* {!data ? ( */} - {/* */} - {/* ) : data?.genres && data.genres.length ? ( */} - {/* data.genres.map((genre, i) => [ */} - {/* i > 0 && ", ", */} - {/* */} - {/* {genre.name} */} - {/* , */} - {/* ]) */} - {/* ) : ( */} - {/* t("show.genre-none") */} - {/* )} */} - {/* */} - {/* */} - + +
)}
diff --git a/front/yarn.lock b/front/yarn.lock index 09120266..921d8e87 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -9682,7 +9682,7 @@ __metadata: react-native-screens: ~3.18.0 react-native-svg: 13.4.0 typescript: ^4.6.3 - yoshiki: 0.2.11 + yoshiki: 0.3.1 languageName: unknown linkType: soft @@ -13319,7 +13319,7 @@ __metadata: superjson: ^1.11.0 typescript: ^4.9.3 webpack: ^5.75.0 - yoshiki: 0.2.11 + yoshiki: 0.3.1 zod: ^3.19.1 languageName: unknown linkType: soft @@ -13644,9 +13644,9 @@ __metadata: languageName: node linkType: hard -"yoshiki@npm:0.2.11": - version: 0.2.11 - resolution: "yoshiki@npm:0.2.11" +"yoshiki@npm:0.3.1": + version: 0.3.1 + resolution: "yoshiki@npm:0.3.1" dependencies: "@types/node": 18.x.x "@types/react": 18.x.x @@ -13661,7 +13661,7 @@ __metadata: optional: true react-native-web: optional: true - checksum: 5a2bbb62b2270d3456f114cfbb24a84ad6b8a94b147687929ccffe2d179560ef40b46df1d4054eda91310d295a9a674bbb201765deb86dc96a2133bfd702235a + checksum: 9448b628b61bbcc4485af7aed667a1c0f8490a2066fa35953b4a02126f1d31d94f90e27a592797f8ecedc0ce2220976a7651ba989f4ff3c68513496b2f9fdd0b languageName: node linkType: hard