first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View File

@@ -0,0 +1,163 @@
import {useWatchPageVideo} from '@app/videos/requests/use-watch-page-video';
import {TitlePoster} from '@app/titles/title-poster/title-poster';
import {TitleLink} from '@app/titles/title-link';
import React, {Fragment, ReactNode, useState} from 'react';
import {Skeleton} from '@common/ui/skeleton/skeleton';
import {AnimatePresence, m} from 'framer-motion';
import {opacityAnimation} from '@common/ui/animation/opacity-animation';
import {ThumbButtons} from '@common/votes/thumb-buttons';
import {IconButton} from '@common/ui/buttons/icon-button';
import {ShareIcon} from '@common/icons/material/Share';
import {FlagIcon} from '@common/icons/material/Flag';
import {Tooltip} from '@common/ui/tooltip/tooltip';
import {Trans} from '@common/i18n/trans';
import {useSubmitReport} from '@common/reports/requests/use-submit-report';
import {useDeleteReport} from '@common/reports/requests/use-delete-report';
import {Video} from '@app/titles/models/video';
import {useIsStreamingMode} from '@app/videos/use-is-streaming-mode';
import {EpisodeLink} from '@app/episodes/episode-link';
import {CompactSeasonEpisode} from '@app/episodes/compact-season-episode';
import {ShareMenuTrigger} from '@app/sharing/share-menu-trigger';
import {getWatchLink} from '@app/videos/watch-page/get-watch-link';
export function WatchPageTitleDetails() {
const {data} = useWatchPageVideo();
const isStreamingMode = useIsStreamingMode();
const content = !data ? (
<Layout
key="skeleton"
poster={<Skeleton variant="rect" size="w-132 aspect-poster" />}
titleLink={<Skeleton className="max-w-144" />}
videoName={<Skeleton className="max-w-240" />}
description={
<Fragment>
<Skeleton />
<Skeleton />
</Fragment>
}
rate={
<div className="flex h-32 items-center gap-2">
<Skeleton variant="rect" size="w-56 h-24" className="mr-10" />
<Skeleton variant="rect" size="w-56 h-24" />
</div>
}
/>
) : (
<Layout
key="loaded"
poster={
<TitlePoster
size="w-132"
srcSize="md"
title={data.title}
showPlayButton
className="max-md:hidden"
/>
}
titleLink={<TitleLink title={data.title} />}
videoName={!isStreamingMode ? data.video.name : undefined}
episodeName={
data.episode ? (
<EpisodeLink title={data.title} episode={data.episode}>
{data.episode.name} (<CompactSeasonEpisode episode={data.episode} />
)
</EpisodeLink>
) : undefined
}
description={data.episode?.description || data.title.description}
rate={
<div className="flex items-center gap-2">
<ThumbButtons model={data.video} className="mr-auto" />
<ReportButton video={data.video} />
<ShareButton video={data.video} />
</div>
}
/>
);
return (
<AnimatePresence initial={false} mode="wait">
{content}
</AnimatePresence>
);
}
interface ShareButtonProps {
video: Video;
}
function ShareButton({video}: ShareButtonProps) {
const link = getWatchLink(video, {absolute: true});
return (
<ShareMenuTrigger link={link}>
<Tooltip label={<Trans message="Share" />}>
<IconButton>
<ShareIcon />
</IconButton>
</Tooltip>
</ShareMenuTrigger>
);
}
interface ReportButtonProps {
video: Video;
}
function ReportButton({video}: ReportButtonProps) {
const report = useSubmitReport(video);
const deleteReport = useDeleteReport(video);
const [isReported, setIsReported] = useState(video.current_user_reported);
return (
<Tooltip label={<Trans message="Report" />}>
<IconButton
onClick={() => {
if (isReported) {
deleteReport.mutate();
} else {
report.mutate({});
}
setIsReported(!isReported);
}}
>
<FlagIcon />
</IconButton>
</Tooltip>
);
}
interface LayoutProps {
poster?: ReactNode;
titleLink: ReactNode;
videoName: ReactNode;
episodeName?: ReactNode;
description: ReactNode;
rate?: ReactNode;
}
function Layout({
poster,
titleLink,
videoName,
episodeName,
description,
rate,
}: LayoutProps) {
return (
<m.div
className="flex items-start gap-16 overflow-hidden rounded pr-6"
{...opacityAnimation}
>
{poster}
<div className="flex-auto py-6">
<h1 className="mb-6 text-2xl font-medium">{titleLink}</h1>
{episodeName && (
<div className="text-base font-medium">{episodeName}</div>
)}
{videoName && <div className="text-base font-medium">{videoName}</div>}
<div className="my-12">{rate}</div>
{description && (
<p className="max-w-780 text-sm text-muted">{description}</p>
)}
</div>
</m.div>
);
}