diff --git a/front/src/app/(app)/_layout.tsx b/front/src/app/(app)/_layout.tsx index eeafe777..e64491bd 100644 --- a/front/src/app/(app)/_layout.tsx +++ b/front/src/app/(app)/_layout.tsx @@ -28,17 +28,6 @@ export default function Layout() { }, headerTintColor: color as string, }} - > - - + /> ); } diff --git a/front/src/app/(app)/series/[slug].tsx b/front/src/app/(app)/series/[slug]/index.tsx similarity index 100% rename from front/src/app/(app)/series/[slug].tsx rename to front/src/app/(app)/series/[slug]/index.tsx diff --git a/front/src/app/(app)/series/[slug]/videos.tsx b/front/src/app/(app)/series/[slug]/videos.tsx new file mode 100644 index 00000000..757712ea --- /dev/null +++ b/front/src/app/(app)/series/[slug]/videos.tsx @@ -0,0 +1,3 @@ +import { VideosModal } from "~/ui/admin"; + +export default VideosModal; diff --git a/front/src/components/entries/index.ts b/front/src/components/entries/index.ts index aecb4df4..f472eb6b 100644 --- a/front/src/components/entries/index.ts +++ b/front/src/components/entries/index.ts @@ -3,7 +3,7 @@ import type { Entry } from "~/models"; export * from "./entry-box"; export * from "./entry-line"; -export const entryDisplayNumber = (entry: Entry) => { +export const entryDisplayNumber = (entry: Partial) => { switch (entry.kind) { case "episode": return `S${entry.seasonNumber}:E${entry.episodeNumber}`; diff --git a/front/src/models/video.ts b/front/src/models/video.ts index 50b81263..80fa5f3f 100644 --- a/front/src/models/video.ts +++ b/front/src/models/video.ts @@ -1,5 +1,5 @@ import { z } from "zod/v4"; -import { Entry } from "./entry"; +import { Entry, Episode, MovieEntry, Special } from "./entry"; import { Extra } from "./extra"; import { Show } from "./show"; import { zdate } from "./utils/utils"; @@ -37,14 +37,21 @@ export const Video = z.object({ }); export const FullVideo = Video.extend({ - slugs: z.array(z.string()), - progress: z.object({ - percent: z.int().min(0).max(100), - time: z.int().min(0), - playedDate: zdate().nullable(), - videoId: z.string().nullable(), - }), - entries: z.array(Entry), + entries: z.array( + z.discriminatedUnion("kind", [ + Episode.omit({ progress: true, videos: true }), + MovieEntry.omit({ progress: true, videos: true }), + Special.omit({ progress: true, videos: true }), + ]), + ), + progress: z.optional( + z.object({ + percent: z.int().min(0).max(100), + time: z.int().min(0), + playedDate: zdate().nullable(), + videoId: z.string().nullable(), + }), + ), previous: z.object({ video: z.string(), entry: Entry }).nullable().optional(), next: z.object({ video: z.string(), entry: Entry }).nullable().optional(), show: Show.optional(), diff --git a/front/src/primitives/modal.tsx b/front/src/primitives/modal.tsx index f7a3d912..0d8f7171 100644 --- a/front/src/primitives/modal.tsx +++ b/front/src/primitives/modal.tsx @@ -1,5 +1,5 @@ import Close from "@material-symbols/svg-400/rounded/close.svg"; -import { useRouter } from "expo-router"; +import { Stack, useRouter } from "expo-router"; import type { ReactNode } from "react"; import { Pressable, ScrollView, View } from "react-native"; import { cn } from "~/utils"; @@ -9,37 +9,50 @@ import { Heading } from "./text"; export const Modal = ({ title, children, + scroll = true, }: { title: string; children: ReactNode; + scroll?: boolean; }) => { const router = useRouter(); return ( - { - if (router.canGoBack()) router.back(); - }} - > + <> + e.stopPropagation()} + className="absolute inset-0 cursor-default! items-center justify-center bg-black/60 max-md:px-4" + onPress={() => { + if (router.canGoBack()) router.back(); + }} > - - {title} - { - if (router.canGoBack()) router.back(); - }} - /> - - {children} + e.preventDefault()} + > + + {title} + { + if (router.canGoBack()) router.back(); + }} + /> + + {scroll ? {children} : children} + - + ); }; diff --git a/front/src/ui/admin/index.tsx b/front/src/ui/admin/index.tsx new file mode 100644 index 00000000..d75d2289 --- /dev/null +++ b/front/src/ui/admin/index.tsx @@ -0,0 +1 @@ +export * from "./videos-modal"; diff --git a/front/src/ui/admin/videos-modal.tsx b/front/src/ui/admin/videos-modal.tsx new file mode 100644 index 00000000..7d1e5b3c --- /dev/null +++ b/front/src/ui/admin/videos-modal.tsx @@ -0,0 +1,40 @@ +import { View } from "react-native"; +import { entryDisplayNumber } from "~/components/entries"; +import { FullVideo } from "~/models"; +import { Modal, P, Select, Skeleton } from "~/primitives"; +import { InfiniteFetch, type QueryIdentifier } from "~/query"; +import { useQueryState } from "~/utils"; + +export const VideosModal = () => { + const [slug] = useQueryState("slug", undefined!); + + return ( + + ( + +

{item.path}

+