From 082f3283f50fbe0d1663faf412d08bd543930b0a Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 15 Feb 2026 13:18:36 +0100 Subject: [PATCH] Fix home page horizontal bars --- front/bun.lock | 2 +- front/src/components/entries/entry-box.tsx | 9 +- front/src/components/items/context-menus.tsx | 4 +- front/src/components/items/item-details.tsx | 18 ++-- front/src/components/items/item-grid.tsx | 16 ++- front/src/components/items/item-list.tsx | 7 +- front/src/query/fetch-infinite.tsx | 3 +- front/src/ui/details/header.tsx | 1 - front/src/ui/empty-view.tsx | 2 +- front/src/ui/home/genre.tsx | 23 +---- front/src/ui/home/header.tsx | 97 +++++------------- front/src/ui/home/news.tsx | 29 +----- front/src/ui/home/recommended.tsx | 102 ++++++++++--------- front/src/ui/home/vertical.tsx | 26 ++--- front/src/ui/home/watchlist.tsx | 37 ++----- front/src/ui/info/index.tsx | 17 ++-- front/src/ui/navbar.tsx | 18 ++-- 17 files changed, 158 insertions(+), 253 deletions(-) diff --git a/front/bun.lock b/front/bun.lock index a85d45b0..3b81d2a7 100644 --- a/front/bun.lock +++ b/front/bun.lock @@ -442,7 +442,7 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@legendapp/list": ["@legendapp/list@github:zoriya/legend-list#d5d3344", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "*" } }, "zoriya-legend-list-d5d3344"], + "@legendapp/list": ["@legendapp/list@github:zoriya/legend-list#c36ff94", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "*" } }, "zoriya-legend-list-c36ff94"], "@material-symbols/svg-400": ["@material-symbols/svg-400@0.40.2", "", {}, "sha512-e2yEgZW/OveVT1sGaZW1kkRWTPVghjsJYWy+vIea3q08Fv2o7FCYv23PESMyr5D4AaAXdM5dKWkF1e6yIm4swA=="], diff --git a/front/src/components/entries/entry-box.tsx b/front/src/components/entries/entry-box.tsx index 30d0b87d..5df743f5 100644 --- a/front/src/components/entries/entry-box.tsx +++ b/front/src/components/entries/entry-box.tsx @@ -17,6 +17,7 @@ import { EntryContext } from "../items/context-menus"; import { ItemProgress } from "../items/item-grid"; export const EntryBox = ({ + kind, slug, serieSlug, name, @@ -27,6 +28,7 @@ export const EntryBox = ({ className, ...props }: { + kind: "movie" | "episode" | "special"; slug: string; // if serie slug is null, disable "Go to serie" in the context menu serieSlug: string | null; @@ -44,7 +46,7 @@ export const EntryBox = ({ setMoreOpened(true)} - className={cn("group w-[350px] items-center outline-0", className)} + className={cn("group w-[350px] items-center p-1 outline-0", className)} {...props} > { +EntryBox.Loader = (props: object) => { return ( - + diff --git a/front/src/components/items/context-menus.tsx b/front/src/components/items/context-menus.tsx index 708e4c18..8b4c5c8d 100644 --- a/front/src/components/items/context-menus.tsx +++ b/front/src/components/items/context-menus.tsx @@ -13,11 +13,13 @@ import { watchListIcon } from "./watchlist-info"; // import { useDownloader } from "../../packages/ui/src/downloads/ui/src/downloads"; export const EntryContext = ({ + kind, slug, serieSlug, className, ...props }: { + kind: "movie" | "episode" | "special"; serieSlug: string | null; slug: string; className?: string; @@ -38,7 +40,7 @@ export const EntryContext = ({ )} {/* { +} & ViewProps) => { const [moreOpened, setMoreOpened] = useState(false); const { t } = useTranslation(); @@ -82,8 +81,8 @@ export const ItemDetails = ({ seenCount={seenCount} /> - - + + {kind !== "collection" && ( {tagline}

}
- + {description ?? t("show.noOverview")} @@ -142,10 +141,13 @@ export const ItemDetails = ({ ); }; -ItemDetails.Loader = (props: object) => { +ItemDetails.Loader = ({ className, ...props }: ViewProps) => { return ( diff --git a/front/src/components/items/item-grid.tsx b/front/src/components/items/item-grid.tsx index 99abe57f..ff744a76 100644 --- a/front/src/components/items/item-grid.tsx +++ b/front/src/components/items/item-grid.tsx @@ -71,7 +71,6 @@ export const ItemGrid = ({ > { +ItemGrid.Loader = ({ + horizontal = false, + ...props +}: { + horizontal?: boolean; +}) => { return ( - + diff --git a/front/src/components/items/item-list.tsx b/front/src/components/items/item-list.tsx index f751e1cb..fb8e6533 100644 --- a/front/src/components/items/item-list.tsx +++ b/front/src/components/items/item-list.tsx @@ -49,7 +49,8 @@ export const ItemList = ({ href={moreOpened ? undefined : href} onLongPress={() => setMoreOpened(true)} className={cn( - "group h-80 w-full outline-0 ring-accent focus-within:ring-3 hover:ring-3", + "group m-1 mx-2 h-80 overflow-hidden rounded", + "outline-0 ring-accent focus-within:ring-3 hover:ring-3", className, )} {...props} @@ -57,7 +58,7 @@ export const ItemList = ({ @@ -111,7 +112,7 @@ export const ItemList = ({ ItemList.Loader = (props: object) => { return ( diff --git a/front/src/query/fetch-infinite.tsx b/front/src/query/fetch-infinite.tsx index b1fb3279..cd4d42e9 100644 --- a/front/src/query/fetch-infinite.tsx +++ b/front/src/query/fetch-infinite.tsx @@ -67,6 +67,8 @@ export const InfiniteFetch = ({ return isFetching ? [...items, ...placeholders] : items; }, [items, isFetching, placeholderCount, numColumns]); + if (!data.length && Empty) return Empty; + return ( ({ ItemSeparatorComponent={ Divider === true ? HR : (Divider as any) || undefined } - ListEmptyComponent={Empty} showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} contentContainerStyle={{ diff --git a/front/src/ui/details/header.tsx b/front/src/ui/details/header.tsx index 8a1fe486..a46fb7e0 100644 --- a/front/src/ui/details/header.tsx +++ b/front/src/ui/details/header.tsx @@ -166,7 +166,6 @@ export const TitleLine = ({ > diff --git a/front/src/ui/empty-view.tsx b/front/src/ui/empty-view.tsx index 82ad09e2..6dadce3e 100644 --- a/front/src/ui/empty-view.tsx +++ b/front/src/ui/empty-view.tsx @@ -10,7 +10,7 @@ export const EmptyView = ({ className?: string; }) => { return ( - +

{message}

); diff --git a/front/src/ui/home/genre.tsx b/front/src/ui/home/genre.tsx index 7e80815d..d8ce05e3 100644 --- a/front/src/ui/home/genre.tsx +++ b/front/src/ui/home/genre.tsx @@ -1,28 +1,12 @@ import { useTranslation } from "react-i18next"; -import { View } from "react-native"; -import { useYoshiki } from "yoshiki/native"; import { ItemGrid, itemMap } from "~/components/items"; import { type Genre, Show } from "~/models"; -import { H3, ts } from "~/primitives"; +import { H3 } from "~/primitives"; import { InfiniteFetch, type QueryIdentifier } from "~/query"; import { EmptyView } from "~/ui/empty-view"; export const Header = ({ title }: { title: string }) => { - const { css } = useYoshiki(); - - return ( - -

{title}

-
- ); + return

{title}

; }; export const GenreGrid = ({ genre }: { genre: Genre }) => { @@ -34,10 +18,9 @@ export const GenreGrid = ({ genre }: { genre: Genre }) => { } Render={({ item }) => } - Loader={ItemGrid.Loader} + Loader={() => } /> ); diff --git a/front/src/ui/home/header.tsx b/front/src/ui/home/header.tsx index 66fbda93..cbcf947a 100644 --- a/front/src/ui/home/header.tsx +++ b/front/src/ui/home/header.tsx @@ -1,13 +1,10 @@ import Info from "@material-symbols/svg-400/rounded/info.svg"; import PlayArrow from "@material-symbols/svg-400/rounded/play_arrow-fill.svg"; -import { LinearGradient } from "expo-linear-gradient"; import type { ComponentProps } from "react"; import { useTranslation } from "react-i18next"; import { View } from "react-native"; -import { min, percent, px, rem, vh } from "yoshiki/native"; import { type KImage, Show } from "~/models"; import { - ContrastArea, H1, H2, IconButton, @@ -17,7 +14,6 @@ import { P, Skeleton, tooltip, - ts, } from "~/primitives"; import type { QueryIdentifier } from "~/query"; import { cn } from "~/utils"; @@ -93,72 +89,35 @@ Header.Loader = () => { const { t } = useTranslation(); return ( - - {({ css, theme }) => ( - - - - - - - - - - - - + + > + + + + + + + + + + + ); }; diff --git a/front/src/ui/home/news.tsx b/front/src/ui/home/news.tsx index 66bf8288..f8241bc0 100644 --- a/front/src/ui/home/news.tsx +++ b/front/src/ui/home/news.tsx @@ -1,6 +1,5 @@ import { useTranslation } from "react-i18next"; import { EntryBox, entryDisplayNumber } from "~/components/entries"; -import { ItemGrid } from "~/components/items"; import { Entry } from "~/models"; import { InfiniteFetch, type QueryIdentifier } from "~/query"; import { EmptyView } from "~/ui/empty-view"; @@ -15,15 +14,11 @@ export const NewsList = () => { - // x?.kind === "movie" || (!x && i % 2) ? "movie" : "episode" - // } - // getItemSizeMult={(_, __, kind) => (kind === "episode" ? 2 : 1)} Empty={} Render={({ item }) => { - // if (item.kind === "episode" || item.kind === "special") { return ( { watchedPercent={item.progress.percent} /> ); - // } - // return ( - // - // ); }} - Loader={({ index }) => - index % 2 ? : - } + Loader={EntryBox.Loader} /> ); diff --git a/front/src/ui/home/recommended.tsx b/front/src/ui/home/recommended.tsx index 4ce634ba..7d55ce56 100644 --- a/front/src/ui/home/recommended.tsx +++ b/front/src/ui/home/recommended.tsx @@ -1,59 +1,67 @@ import { useTranslation } from "react-i18next"; import { View } from "react-native"; -import { useYoshiki } from "yoshiki/native"; -import { ItemGrid } from "~/components/items"; import { ItemDetails } from "~/components/items/item-details"; import { Show } from "~/models"; -import { H3 } from "~/primitives"; -import { InfiniteFetch, type QueryIdentifier } from "~/query"; +import { useBreakpointMap } from "~/primitives"; +import { type QueryIdentifier, useInfiniteFetch } from "~/query"; import { getDisplayDate } from "~/utils"; +import { Header } from "./genre"; + +const itemCount = 6; export const Recommended = () => { const { t } = useTranslation(); - const { css } = useYoshiki(); + const { numColumns, gap } = useBreakpointMap(ItemDetails.layout); + const { items } = useInfiniteFetch(Recommended.query()); return ( - -

{t("home.recommended")}

- ( - - )} - Loader={ItemDetails.Loader} - /> + +
+ + {[...Array(numColumns)].map((_, x) => ( + + {[...Array(itemCount / numColumns)].map((_, y) => { + if (!items) return ; + const item = items[x * (itemCount / numColumns) + y]; + return ( + + ); + })} + + ))} + ); }; @@ -64,7 +72,7 @@ Recommended.query = (): QueryIdentifier => ({ path: ["api", "shows"], params: { sort: "random", - limit: 6, + limit: itemCount, with: ["firstEntry"], }, }); diff --git a/front/src/ui/home/vertical.tsx b/front/src/ui/home/vertical.tsx index 6a9a6c39..0e19e3b8 100644 --- a/front/src/ui/home/vertical.tsx +++ b/front/src/ui/home/vertical.tsx @@ -1,26 +1,22 @@ import { useTranslation } from "react-i18next"; import { View } from "react-native"; -import { useYoshiki } from "yoshiki/native"; -import { ItemGrid, ItemList, itemMap } from "~/components/items"; +import { ItemList, itemMap } from "~/components/items"; import { Show } from "~/models"; -import { H3 } from "~/primitives"; -import { InfiniteFetch, type QueryIdentifier } from "~/query"; +import { type QueryIdentifier, useInfiniteFetch } from "~/query"; +import { Header } from "./genre"; export const VerticalRecommended = () => { const { t } = useTranslation(); - const { css } = useYoshiki(); + const { items } = useInfiniteFetch(VerticalRecommended.query()); return ( - -

{t("home.recommended")}

- } - Loader={() => } - /> + +
+ + {items + ? items.map((x) => ) + : [...Array(3)].map((_, i) => )} + ); }; diff --git a/front/src/ui/home/watchlist.tsx b/front/src/ui/home/watchlist.tsx index 52ed9fd7..241a7af5 100644 --- a/front/src/ui/home/watchlist.tsx +++ b/front/src/ui/home/watchlist.tsx @@ -1,32 +1,29 @@ import { useTranslation } from "react-i18next"; import { View } from "react-native"; -import { useYoshiki } from "yoshiki/native"; import { EntryBox, entryDisplayNumber } from "~/components/entries"; -import { ItemGrid } from "~/components/items"; +import { ItemGrid, itemMap } from "~/components/items"; import { Show } from "~/models"; -import { Button, Link, P, ts } from "~/primitives"; +import { Button, Link, P } from "~/primitives"; import { useAccount } from "~/providers/account-context"; import { InfiniteFetch, type QueryIdentifier } from "~/query"; import { EmptyView } from "~/ui/empty-view"; -import { getDisplayDate } from "~/utils"; import { Header } from "./genre"; export const WatchlistList = () => { const { t } = useTranslation(); - const { css } = useYoshiki(); const account = useAccount(); if (!account) { return ( <>
- +

{t("home.watchlistLogin")}