diff --git a/front/src/components/items/item-details.tsx b/front/src/components/items/item-details.tsx new file mode 100644 index 00000000..7015d2b5 --- /dev/null +++ b/front/src/components/items/item-details.tsx @@ -0,0 +1,176 @@ +import PlayArrow from "@material-symbols/svg-400/rounded/play_arrow-fill.svg"; +import { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { ScrollView, View } from "react-native"; +import { ItemContext } from "~/components/items/context-menus"; +import { ItemWatchStatus } from "~/components/items/item-helpers"; +import type { Genre, KImage, WatchStatusV } from "~/models"; +import { + Chip, + IconFab, + Link, + P, + PosterBackground, + Skeleton, + SubP, + tooltip, + ts, +} from "~/primitives"; +import type { Layout } from "~/query"; +import { cn } from "~/utils"; + +export const ItemDetails = ({ + slug, + kind, + name, + tagline, + subtitle, + description, + poster, + genres, + href, + playHref, + watchStatus, + availableCount, + seenCount, + className, + ...props +}: { + slug: string; + kind: "movie" | "serie" | "collection"; + name: string; + tagline: string | null; + subtitle: string | null; + poster: KImage | null; + genres: Genre[] | null; + description: string | null; + href: string; + playHref: string | null; + watchStatus: WatchStatusV | null; + availableCount?: number | null; + seenCount?: number | null; + className?: string; +}) => { + const [moreOpened, setMoreOpened] = useState(false); + const { t } = useTranslation(); + + return ( + + setMoreOpened(true)} + className={cn( + "h-full flex-row overflow-hidden rounded-xl bg-card", + "group outline-0 ring-accent focus-within:ring-3 hover:ring-3", + )} + > + + +

+ {name} +

+ {subtitle && {subtitle}} +
+ +
+ + + {kind !== "collection" && ( + setMoreOpened(v)} + /> + )} + {tagline &&

{tagline}

} +
+ + + {description ?? t("show.noOverview")} + + +
+ + + {/* This view needs to be out of the Link because nested are not allowed on the web */} + + {genres && ( + + {genres.map((x, i) => ( + + ))} + + )} + {playHref !== null && ( + + )} + +
+ ); +}; + +ItemDetails.Loader = (props: object) => { + return ( + + + + + + + + + + + + + + + + + + + ); +}; + +ItemDetails.layout = { + size: 288, + numColumns: { xs: 1, md: 2, xl: 3 }, + layout: "grid", + gap: { xs: ts(1), md: ts(8) }, +} satisfies Layout; diff --git a/front/src/components/items/item-helpers.tsx b/front/src/components/items/item-helpers.tsx index 501fff2e..7cf7c987 100644 --- a/front/src/components/items/item-helpers.tsx +++ b/front/src/components/items/item-helpers.tsx @@ -21,9 +21,9 @@ export const ItemWatchStatus = ({ {...props} > {watchStatus === "completed" ? ( - + ) : ( -

+

{seenCount ?? 0}/{availableCount}

)} diff --git a/front/src/primitives/chip.tsx b/front/src/primitives/chip.tsx index 245342c0..cbbe2c78 100644 --- a/front/src/primitives/chip.tsx +++ b/front/src/primitives/chip.tsx @@ -34,7 +34,7 @@ export const Chip = ({ size === "medium" && "px-5 py-2", size === "large" && "px-10 py-4", outline && "hover:bg-accent focus:bg-accent", - !outline && "bg-accent hover:bg-background focus:bg-background", + !outline && "bg-accent hover:bg-transparent focus:bg-transparent", className, )} {...props} diff --git a/front/src/ui/home/recommended.tsx b/front/src/ui/home/recommended.tsx index 32860ec4..4ce634ba 100644 --- a/front/src/ui/home/recommended.tsx +++ b/front/src/ui/home/recommended.tsx @@ -1,287 +1,13 @@ -import PlayArrow from "@material-symbols/svg-400/rounded/play_arrow-fill.svg"; -import { useState } from "react"; import { useTranslation } from "react-i18next"; -import { ScrollView, View } from "react-native"; -import { calc, percent, px, rem, type Theme, useYoshiki } from "yoshiki/native"; +import { View } from "react-native"; +import { useYoshiki } from "yoshiki/native"; import { ItemGrid } from "~/components/items"; -import { ItemContext } from "~/components/items/context-menus"; -import { ItemWatchStatus } from "~/components/items/item-helpers"; -import { type Genre, type KImage, Show, type WatchStatusV } from "~/models"; -import { - Chip, - focusReset, - H3, - IconFab, - Link, - P, - PosterBackground, - Skeleton, - SubP, - tooltip, - ts, -} from "~/primitives"; -import { InfiniteFetch, type Layout, type QueryIdentifier } from "~/query"; +import { ItemDetails } from "~/components/items/item-details"; +import { Show } from "~/models"; +import { H3 } from "~/primitives"; +import { InfiniteFetch, type QueryIdentifier } from "~/query"; import { getDisplayDate } from "~/utils"; -export const ItemDetails = ({ - slug, - kind, - name, - tagline, - subtitle, - description, - poster, - genres, - href, - playHref, - watchStatus, - availableCount, - seenCount, - ...props -}: { - slug: string; - kind: "movie" | "serie" | "collection"; - name: string; - tagline: string | null; - subtitle: string | null; - poster: KImage | null; - genres: Genre[] | null; - description: string | null; - href: string; - playHref: string | null; - watchStatus: WatchStatusV | null; - availableCount?: number | null; - seenCount?: number | null; -}) => { - const [moreOpened, setMoreOpened] = useState(false); - const { css } = useYoshiki("recommended-card"); - const { t } = useTranslation(); - - return ( - - setMoreOpened(true)} - {...css({ - position: "absolute", - top: 0, - left: 0, - right: 0, - bottom: 0, - flexDirection: "row", - bg: (theme) => theme.variant.background, - borderRadius: px(12), - overflow: "hidden", - borderColor: (theme) => theme.background, - borderWidth: ts(0.25), - borderStyle: "solid", - fover: { - self: { - ...focusReset, - borderColor: (theme: Theme) => theme.accent, - }, - title: { - textDecorationLine: "underline", - }, - }, - })} - > - - theme.darkOverlay, - position: "absolute", - left: 0, - right: 0, - bottom: 0, - p: ts(1), - })} - > -

theme.colors.white }, - "title", - ])} - > - {name} -

- {subtitle && {subtitle}} -
- -
- - - {kind !== "collection" && ( - setMoreOpened(v)} - /> - )} - {tagline &&

{tagline}

} -
- - - {description ?? t("show.noOverview")} - - -
- - - {/* This view needs to be out of the Link because nested
are not allowed on the web */} - theme.themeOverlay, - flexDirection: "row", - pX: 4, - justifyContent: "flex-end", - height: px(50), - })} - > - {genres && ( - - {genres.map((x, i) => ( - - ))} - - )} - {playHref !== null && ( - - )} - - - ); -}; - -ItemDetails.Loader = (props: object) => { - const { css } = useYoshiki(); - - return ( - theme.variant.background, - borderRadius: px(12), - overflow: "hidden", - borderColor: (theme) => theme.background, - borderWidth: ts(0.25), - borderStyle: "solid", - }, - props, - )} - > - - theme.darkOverlay, - position: "absolute", - left: 0, - right: 0, - bottom: 0, - p: ts(1), - })} - > - - - - - - - - - - theme.themeOverlay, - pX: 4, - height: px(50), - flexDirection: "row", - alignItems: "center", - })} - > - - - - - - ); -}; - -ItemDetails.layout = { - size: ts(36), - numColumns: { xs: 1, md: 2, xl: 3 }, - layout: "grid", - gap: { xs: ts(1), md: ts(8) }, -} satisfies Layout; - export const Recommended = () => { const { t } = useTranslation(); const { css } = useYoshiki(); @@ -290,7 +16,7 @@ export const Recommended = () => { -

{t("home.recommended")}

+

{t("home.recommended")}

{ watchStatus={ (item.kind !== "collection" && item.watchStatus?.status) || null } - unseenEpisodesCount={ - item.kind === "serie" - ? item.availableCount - (item.watchStatus?.seenCount ?? 0) - : null + availableCount={item.kind === "serie" ? item.availableCount : null} + seenCount={ + item.kind === "serie" ? item.watchStatus?.seenCount : null } /> )}