refactor: update Next.js and React.js
This commit is contained in:
@@ -166,10 +166,9 @@ const CollectionDetails = ({ collection }: CollectionDetailsProps) => {
|
||||
<Link
|
||||
href={`/discover/movies/genre/${genreId}`}
|
||||
key={`genre-${genreId}`}
|
||||
className="hover:underline"
|
||||
>
|
||||
<a className="hover:underline">
|
||||
{genres.find((g) => g.id === genreId)?.name}
|
||||
</a>
|
||||
{genres.find((g) => g.id === genreId)?.name}
|
||||
</Link>
|
||||
))
|
||||
.reduce((prev, curr) => (
|
||||
|
||||
@@ -93,13 +93,12 @@ const Badge = (
|
||||
);
|
||||
} else if (href) {
|
||||
return (
|
||||
<Link href={href}>
|
||||
<a
|
||||
className={badgeStyle.join(' ')}
|
||||
ref={ref as React.Ref<HTMLAnchorElement>}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
<Link
|
||||
href={href}
|
||||
className={badgeStyle.join(' ')}
|
||||
ref={ref as React.Ref<HTMLAnchorElement>}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import useSettings from '@app/hooks/useSettings';
|
||||
import type { ImageLoader, ImageProps } from 'next/image';
|
||||
import Image from 'next/image';
|
||||
import type { ImageLoader, ImageProps } from 'next/legacy/image';
|
||||
import Image from 'next/legacy/image';
|
||||
|
||||
const imageLoader: ImageLoader = ({ src }) => src;
|
||||
|
||||
|
||||
@@ -55,15 +55,14 @@ const SettingsLink = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Link href={route}>
|
||||
<a
|
||||
className={`${linkClasses} ${
|
||||
currentPath.match(regex) ? activeLinkColor : inactiveLinkColor
|
||||
}`}
|
||||
aria-current="page"
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
<Link
|
||||
href={route}
|
||||
className={`${linkClasses} ${
|
||||
currentPath.match(regex) ? activeLinkColor : inactiveLinkColor
|
||||
}`}
|
||||
aria-current="page"
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,40 +12,39 @@ const CompanyCard = ({ image, url, name }: CompanyCardProps) => {
|
||||
const [isHovered, setHovered] = useState(false);
|
||||
|
||||
return (
|
||||
<Link href={url}>
|
||||
<a
|
||||
className={`relative flex h-32 w-56 transform-gpu cursor-pointer items-center justify-center p-8 shadow ring-1 transition duration-300 ease-in-out sm:h-36 sm:w-72 ${
|
||||
isHovered
|
||||
? 'scale-105 bg-gray-700 ring-gray-500'
|
||||
: 'scale-100 bg-gray-800 ring-gray-700'
|
||||
} rounded-xl`}
|
||||
onMouseEnter={() => {
|
||||
<Link
|
||||
href={url}
|
||||
className={`relative flex h-32 w-56 transform-gpu cursor-pointer items-center justify-center p-8 shadow ring-1 transition duration-300 ease-in-out sm:h-36 sm:w-72 ${
|
||||
isHovered
|
||||
? 'scale-105 bg-gray-700 ring-gray-500'
|
||||
: 'scale-100 bg-gray-800 ring-gray-700'
|
||||
} rounded-xl`}
|
||||
onMouseEnter={() => {
|
||||
setHovered(true);
|
||||
}}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setHovered(true);
|
||||
}}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setHovered(true);
|
||||
}
|
||||
}}
|
||||
role="link"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className="relative h-full w-full">
|
||||
<CachedImage
|
||||
src={image}
|
||||
alt={name}
|
||||
className="relative z-40 h-full w-full"
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={`absolute bottom-0 left-0 right-0 z-0 h-12 rounded-b-xl bg-gradient-to-t ${
|
||||
isHovered ? 'from-gray-800' : 'from-gray-900'
|
||||
}`}
|
||||
}
|
||||
}}
|
||||
role="link"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className="relative h-full w-full">
|
||||
<CachedImage
|
||||
src={image}
|
||||
alt={name}
|
||||
className="relative z-40 h-full w-full"
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
className={`absolute bottom-0 left-0 right-0 z-0 h-12 rounded-b-xl bg-gradient-to-t ${
|
||||
isHovered ? 'from-gray-800' : 'from-gray-900'
|
||||
}`}
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -58,8 +58,8 @@ const DiscoverWatchlist = () => {
|
||||
<Header
|
||||
subtext={
|
||||
router.query.userId ? (
|
||||
<Link href={`/users/${user?.id}`}>
|
||||
<a className="hover:underline">{user?.displayName}</a>
|
||||
<Link href={`/users/${user?.id}`} className="hover:underline">
|
||||
{user?.displayName}
|
||||
</Link>
|
||||
) : (
|
||||
''
|
||||
|
||||
@@ -25,11 +25,9 @@ const MovieGenreSlider = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="slider-header">
|
||||
<Link href="/discover/movies/genres">
|
||||
<a className="slider-title">
|
||||
<span>{intl.formatMessage(messages.moviegenres)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</a>
|
||||
<Link href="/discover/movies/genres" className="slider-title">
|
||||
<span>{intl.formatMessage(messages.moviegenres)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</Link>
|
||||
</div>
|
||||
<Slider
|
||||
|
||||
@@ -39,11 +39,9 @@ const PlexWatchlistSlider = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="slider-header">
|
||||
<Link href="/discover/watchlist">
|
||||
<a className="slider-title">
|
||||
<span>{intl.formatMessage(messages.plexwatchlist)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</a>
|
||||
<Link href="/discover/watchlist" className="slider-title">
|
||||
<span>{intl.formatMessage(messages.plexwatchlist)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</Link>
|
||||
</div>
|
||||
<Slider
|
||||
|
||||
@@ -24,11 +24,9 @@ const RecentRequestsSlider = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="slider-header">
|
||||
<Link href="/requests?filter=all">
|
||||
<a className="slider-title">
|
||||
<span>{intl.formatMessage(sliderTitles.recentrequests)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</a>
|
||||
<Link href="/requests?filter=all" className="slider-title">
|
||||
<span>{intl.formatMessage(sliderTitles.recentrequests)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</Link>
|
||||
</div>
|
||||
<Slider
|
||||
|
||||
@@ -25,11 +25,9 @@ const TvGenreSlider = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="slider-header">
|
||||
<Link href="/discover/tv/genres">
|
||||
<a className="slider-title">
|
||||
<span>{intl.formatMessage(messages.tvgenres)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</a>
|
||||
<Link href="/discover/tv/genres" className="slider-title">
|
||||
<span>{intl.formatMessage(messages.tvgenres)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</Link>
|
||||
</div>
|
||||
<Slider
|
||||
|
||||
@@ -14,37 +14,36 @@ const GenreCard = ({ image, url, name, canExpand = false }: GenreCardProps) => {
|
||||
const [isHovered, setHovered] = useState(false);
|
||||
|
||||
return (
|
||||
<Link href={url}>
|
||||
<a
|
||||
className={`relative flex h-32 items-center justify-center sm:h-36 ${
|
||||
canExpand ? 'w-full' : 'w-56 sm:w-72'
|
||||
} transform-gpu cursor-pointer p-8 shadow ring-1 transition duration-300 ease-in-out ${
|
||||
isHovered
|
||||
? 'scale-105 bg-gray-700 bg-opacity-100 ring-gray-500'
|
||||
: 'scale-100 bg-gray-800 bg-opacity-80 ring-gray-700'
|
||||
} overflow-hidden rounded-xl bg-cover bg-center`}
|
||||
onMouseEnter={() => {
|
||||
<Link
|
||||
href={url}
|
||||
className={`relative flex h-32 items-center justify-center sm:h-36 ${
|
||||
canExpand ? 'w-full' : 'w-56 sm:w-72'
|
||||
} transform-gpu cursor-pointer p-8 shadow ring-1 transition duration-300 ease-in-out ${
|
||||
isHovered
|
||||
? 'scale-105 bg-gray-700 bg-opacity-100 ring-gray-500'
|
||||
: 'scale-100 bg-gray-800 bg-opacity-80 ring-gray-700'
|
||||
} overflow-hidden rounded-xl bg-cover bg-center`}
|
||||
onMouseEnter={() => {
|
||||
setHovered(true);
|
||||
}}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setHovered(true);
|
||||
}}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setHovered(true);
|
||||
}
|
||||
}}
|
||||
role="link"
|
||||
tabIndex={0}
|
||||
>
|
||||
<CachedImage src={image} alt="" layout="fill" objectFit="cover" />
|
||||
<div
|
||||
className={`absolute inset-0 z-10 h-full w-full bg-gray-800 transition duration-300 ${
|
||||
isHovered ? 'bg-opacity-10' : 'bg-opacity-30'
|
||||
}`}
|
||||
/>
|
||||
<div className="relative z-20 w-full truncate whitespace-normal text-center text-2xl font-bold text-white sm:text-3xl">
|
||||
{name}
|
||||
</div>
|
||||
</a>
|
||||
}
|
||||
}}
|
||||
role="link"
|
||||
tabIndex={0}
|
||||
>
|
||||
<CachedImage src={image} alt="" layout="fill" objectFit="cover" />
|
||||
<div
|
||||
className={`absolute inset-0 z-10 h-full w-full bg-gray-800 transition duration-300 ${
|
||||
isHovered ? 'bg-opacity-10' : 'bg-opacity-30'
|
||||
}`}
|
||||
/>
|
||||
<div className="relative z-20 w-full truncate whitespace-normal text-center text-2xl font-bold text-white sm:text-3xl">
|
||||
{name}
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -45,10 +45,9 @@ const IssueBlock = ({ issue }: IssueBlockProps) => {
|
||||
? '/profile'
|
||||
: `/users/${issue.createdBy.id}`
|
||||
}
|
||||
className="font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline"
|
||||
>
|
||||
<a className="font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline">
|
||||
{issue.createdBy.displayName}
|
||||
</a>
|
||||
{issue.createdBy.displayName}
|
||||
</Link>
|
||||
</span>
|
||||
</div>
|
||||
@@ -64,7 +63,7 @@ const IssueBlock = ({ issue }: IssueBlockProps) => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-2 flex flex-shrink-0 flex-wrap">
|
||||
<Link href={`/issues/${issue.id}`} passHref>
|
||||
<Link href={`/issues/${issue.id}`} passHref legacyBehavior>
|
||||
<Button buttonType="primary" as="a">
|
||||
<EyeIcon />
|
||||
</Button>
|
||||
|
||||
@@ -84,13 +84,11 @@ const IssueComment = ({
|
||||
</Modal>
|
||||
</Transition>
|
||||
<Link href={isActiveUser ? '/profile' : `/users/${comment.user.id}`}>
|
||||
<a>
|
||||
<img
|
||||
src={comment.user.avatar}
|
||||
alt=""
|
||||
className="h-10 w-10 scale-100 transform-gpu rounded-full object-cover ring-1 ring-gray-500 transition duration-300 hover:scale-105"
|
||||
/>
|
||||
</a>
|
||||
<img
|
||||
src={comment.user.avatar}
|
||||
alt=""
|
||||
className="h-10 w-10 scale-100 transform-gpu rounded-full object-cover ring-1 ring-gray-500 transition duration-300 hover:scale-105"
|
||||
/>
|
||||
</Link>
|
||||
<div className="relative flex-1">
|
||||
<div className="w-full rounded-md shadow ring-1 ring-gray-500">
|
||||
@@ -242,10 +240,9 @@ const IssueComment = ({
|
||||
href={
|
||||
isActiveUser ? '/profile' : `/users/${comment.user.id}`
|
||||
}
|
||||
className="font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline"
|
||||
>
|
||||
<a className="font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline">
|
||||
{comment.user.displayName}
|
||||
</a>
|
||||
{comment.user.displayName}
|
||||
</Link>
|
||||
),
|
||||
relativeTime: (
|
||||
|
||||
@@ -256,8 +256,9 @@ const IssueDetails = () => {
|
||||
href={`/${
|
||||
issueData.media.mediaType === MediaType.MOVIE ? 'movie' : 'tv'
|
||||
}/${data.id}`}
|
||||
className="hover:underline"
|
||||
>
|
||||
<a className="hover:underline">{title}</a>
|
||||
{title}
|
||||
</Link>{' '}
|
||||
{releaseYear && (
|
||||
<span className="media-year">({releaseYear.slice(0, 4)})</span>
|
||||
@@ -273,17 +274,16 @@ const IssueDetails = () => {
|
||||
? '/profile'
|
||||
: `/users/${issueData.createdBy.id}`
|
||||
}
|
||||
className="group ml-1 inline-flex h-full items-center xl:ml-1.5"
|
||||
>
|
||||
<a className="group ml-1 inline-flex h-full items-center xl:ml-1.5">
|
||||
<img
|
||||
className="mr-0.5 h-5 w-5 scale-100 transform-gpu rounded-full object-cover transition duration-300 group-hover:scale-105 xl:mr-1 xl:h-6 xl:w-6"
|
||||
src={issueData.createdBy.avatar}
|
||||
alt=""
|
||||
/>
|
||||
<span className="font-semibold text-gray-100 transition duration-300 group-hover:text-white group-hover:underline">
|
||||
{issueData.createdBy.displayName}
|
||||
</span>
|
||||
</a>
|
||||
<img
|
||||
className="mr-0.5 h-5 w-5 scale-100 transform-gpu rounded-full object-cover transition duration-300 group-hover:scale-105 xl:mr-1 xl:h-6 xl:w-6"
|
||||
src={issueData.createdBy.avatar}
|
||||
alt=""
|
||||
/>
|
||||
<span className="font-semibold text-gray-100 transition duration-300 group-hover:text-white group-hover:underline">
|
||||
{issueData.createdBy.displayName}
|
||||
</span>
|
||||
</Link>
|
||||
),
|
||||
relativeTime: (
|
||||
|
||||
@@ -133,21 +133,20 @@ const IssueItem = ({ issue }: IssueItemProps) => {
|
||||
? `/movie/${issue.media.tmdbId}`
|
||||
: `/tv/${issue.media.tmdbId}`
|
||||
}
|
||||
className="relative h-auto w-12 flex-shrink-0 scale-100 transform-gpu overflow-hidden rounded-md transition duration-300 hover:scale-105"
|
||||
>
|
||||
<a className="relative h-auto w-12 flex-shrink-0 scale-100 transform-gpu overflow-hidden rounded-md transition duration-300 hover:scale-105">
|
||||
<CachedImage
|
||||
src={
|
||||
title.posterPath
|
||||
? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${title.posterPath}`
|
||||
: '/images/overseerr_poster_not_found.png'
|
||||
}
|
||||
alt=""
|
||||
layout="responsive"
|
||||
width={600}
|
||||
height={900}
|
||||
objectFit="cover"
|
||||
/>
|
||||
</a>
|
||||
<CachedImage
|
||||
src={
|
||||
title.posterPath
|
||||
? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${title.posterPath}`
|
||||
: '/images/overseerr_poster_not_found.png'
|
||||
}
|
||||
alt=""
|
||||
layout="responsive"
|
||||
width={600}
|
||||
height={900}
|
||||
objectFit="cover"
|
||||
/>
|
||||
</Link>
|
||||
<div className="flex flex-col justify-center overflow-hidden pl-2 xl:pl-4">
|
||||
<div className="pt-0.5 text-xs text-white sm:pt-1">
|
||||
@@ -162,10 +161,9 @@ const IssueItem = ({ issue }: IssueItemProps) => {
|
||||
? `/movie/${issue.media.tmdbId}`
|
||||
: `/tv/${issue.media.tmdbId}`
|
||||
}
|
||||
className="mr-2 min-w-0 truncate text-lg font-bold text-white hover:underline xl:text-xl"
|
||||
>
|
||||
<a className="mr-2 min-w-0 truncate text-lg font-bold text-white hover:underline xl:text-xl">
|
||||
{isMovie(title) ? title.title : title.name}
|
||||
</a>
|
||||
{isMovie(title) ? title.title : title.name}
|
||||
</Link>
|
||||
{problemSeasonEpisodeLine.length > 0 && (
|
||||
<div className="card-field">
|
||||
@@ -222,17 +220,18 @@ const IssueItem = ({ issue }: IssueItemProps) => {
|
||||
/>
|
||||
),
|
||||
user: (
|
||||
<Link href={`/users/${issue.createdBy.id}`}>
|
||||
<a className="group flex items-center truncate">
|
||||
<img
|
||||
src={issue.createdBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm ml-1.5 object-cover"
|
||||
/>
|
||||
<span className="truncate text-sm font-semibold group-hover:text-white group-hover:underline">
|
||||
{issue.createdBy.displayName}
|
||||
</span>
|
||||
</a>
|
||||
<Link
|
||||
href={`/users/${issue.createdBy.id}`}
|
||||
className="group flex items-center truncate"
|
||||
>
|
||||
<img
|
||||
src={issue.createdBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm ml-1.5 object-cover"
|
||||
/>
|
||||
<span className="truncate text-sm font-semibold group-hover:text-white group-hover:underline">
|
||||
{issue.createdBy.displayName}
|
||||
</span>
|
||||
</Link>
|
||||
),
|
||||
})}
|
||||
@@ -259,7 +258,7 @@ const IssueItem = ({ issue }: IssueItemProps) => {
|
||||
</div>
|
||||
<div className="z-10 mt-4 flex w-full flex-col justify-center pl-4 pr-4 xl:mt-0 xl:w-96 xl:items-end xl:pl-0">
|
||||
<span className="w-full">
|
||||
<Link href={`/issues/${issue.id}`} passHref>
|
||||
<Link href={`/issues/${issue.id}`} passHref legacyBehavior>
|
||||
<Button as="a" className="w-full" buttonType="primary">
|
||||
<EyeIcon />
|
||||
<span>{intl.formatMessage(messages.viewissue)}</span>
|
||||
|
||||
@@ -118,7 +118,7 @@ const CreateIssueModal = ({
|
||||
strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
|
||||
})}
|
||||
</div>
|
||||
<Link href={`/issues/${newIssue.data.id}`}>
|
||||
<Link href={`/issues/${newIssue.data.id}`} legacyBehavior>
|
||||
<Button as="a" className="mt-4">
|
||||
<span>{intl.formatMessage(messages.toastviewissue)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
|
||||
@@ -142,25 +142,25 @@ const MobileMenu = () => {
|
||||
{filteredLinks.map((link) => {
|
||||
const isActive = router.pathname.match(link.activeRegExp);
|
||||
return (
|
||||
<Link key={`mobile-menu-link-${link.href}`} href={link.href}>
|
||||
<a
|
||||
className={`flex items-center space-x-2 ${
|
||||
isActive ? 'text-indigo-500' : ''
|
||||
}`}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setIsOpen(false);
|
||||
}
|
||||
}}
|
||||
onClick={() => setIsOpen(false)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
{cloneElement(isActive ? link.svgIconSelected : link.svgIcon, {
|
||||
className: 'h-5 w-5',
|
||||
})}
|
||||
<span>{link.content}</span>
|
||||
</a>
|
||||
<Link
|
||||
key={`mobile-menu-link-${link.href}`}
|
||||
href={link.href}
|
||||
className={`flex items-center space-x-2 ${
|
||||
isActive ? 'text-indigo-500' : ''
|
||||
}`}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setIsOpen(false);
|
||||
}
|
||||
}}
|
||||
onClick={() => setIsOpen(false)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
{cloneElement(isActive ? link.svgIconSelected : link.svgIcon, {
|
||||
className: 'h-5 w-5',
|
||||
})}
|
||||
<span>{link.content}</span>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
@@ -173,19 +173,19 @@ const MobileMenu = () => {
|
||||
const isActive =
|
||||
router.pathname.match(link.activeRegExp) && !isOpen;
|
||||
return (
|
||||
<Link key={`mobile-menu-link-${link.href}`} href={link.href}>
|
||||
<a
|
||||
className={`flex flex-col items-center space-y-1 ${
|
||||
isActive ? 'text-indigo-500' : ''
|
||||
}`}
|
||||
>
|
||||
{cloneElement(
|
||||
isActive ? link.svgIconSelected : link.svgIcon,
|
||||
{
|
||||
className: 'h-6 w-6',
|
||||
}
|
||||
)}
|
||||
</a>
|
||||
<Link
|
||||
key={`mobile-menu-link-${link.href}`}
|
||||
href={link.href}
|
||||
className={`flex flex-col items-center space-y-1 ${
|
||||
isActive ? 'text-indigo-500' : ''
|
||||
}`}
|
||||
>
|
||||
{cloneElement(
|
||||
isActive ? link.svgIconSelected : link.svgIcon,
|
||||
{
|
||||
className: 'h-6 w-6',
|
||||
}
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -168,32 +168,27 @@ const Sidebar = ({ open, setClosed }: SidebarProps) => {
|
||||
key={`mobile-${sidebarLink.messagesKey}`}
|
||||
href={sidebarLink.href}
|
||||
as={sidebarLink.as}
|
||||
onClick={() => setClosed()}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setClosed();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={`flex items-center rounded-md px-2 py-2 text-base font-medium leading-6 text-white transition duration-150 ease-in-out focus:outline-none
|
||||
${
|
||||
router.pathname.match(sidebarLink.activeRegExp)
|
||||
? 'bg-gradient-to-br from-indigo-600 to-purple-600 hover:from-indigo-500 hover:to-purple-500'
|
||||
: 'hover:bg-gray-700 focus:bg-gray-700'
|
||||
}
|
||||
`}
|
||||
data-testid={`${sidebarLink.dataTestId}-mobile`}
|
||||
>
|
||||
<a
|
||||
onClick={() => setClosed()}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setClosed();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={`flex items-center rounded-md px-2 py-2 text-base font-medium leading-6 text-white transition duration-150 ease-in-out focus:outline-none
|
||||
${
|
||||
router.pathname.match(
|
||||
sidebarLink.activeRegExp
|
||||
)
|
||||
? 'bg-gradient-to-br from-indigo-600 to-purple-600 hover:from-indigo-500 hover:to-purple-500'
|
||||
: 'hover:bg-gray-700 focus:bg-gray-700'
|
||||
}
|
||||
`}
|
||||
data-testid={`${sidebarLink.dataTestId}-mobile`}
|
||||
>
|
||||
{sidebarLink.svgIcon}
|
||||
{intl.formatMessage(
|
||||
menuMessages[sidebarLink.messagesKey]
|
||||
)}
|
||||
</a>
|
||||
{sidebarLink.svgIcon}
|
||||
{intl.formatMessage(
|
||||
menuMessages[sidebarLink.messagesKey]
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
@@ -242,24 +237,19 @@ const Sidebar = ({ open, setClosed }: SidebarProps) => {
|
||||
key={`desktop-${sidebarLink.messagesKey}`}
|
||||
href={sidebarLink.href}
|
||||
as={sidebarLink.as}
|
||||
className={`group flex items-center rounded-md px-2 py-2 text-lg font-medium leading-6 text-white transition duration-150 ease-in-out focus:outline-none
|
||||
${
|
||||
router.pathname.match(sidebarLink.activeRegExp)
|
||||
? 'bg-gradient-to-br from-indigo-600 to-purple-600 hover:from-indigo-500 hover:to-purple-500'
|
||||
: 'hover:bg-gray-700 focus:bg-gray-700'
|
||||
}
|
||||
`}
|
||||
data-testid={sidebarLink.dataTestId}
|
||||
>
|
||||
<a
|
||||
className={`group flex items-center rounded-md px-2 py-2 text-lg font-medium leading-6 text-white transition duration-150 ease-in-out focus:outline-none
|
||||
${
|
||||
router.pathname.match(
|
||||
sidebarLink.activeRegExp
|
||||
)
|
||||
? 'bg-gradient-to-br from-indigo-600 to-purple-600 hover:from-indigo-500 hover:to-purple-500'
|
||||
: 'hover:bg-gray-700 focus:bg-gray-700'
|
||||
}
|
||||
`}
|
||||
data-testid={sidebarLink.dataTestId}
|
||||
>
|
||||
{sidebarLink.svgIcon}
|
||||
{intl.formatMessage(
|
||||
menuMessages[sidebarLink.messagesKey]
|
||||
)}
|
||||
</a>
|
||||
{sidebarLink.svgIcon}
|
||||
{intl.formatMessage(
|
||||
menuMessages[sidebarLink.messagesKey]
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -24,10 +24,8 @@ const ForwardedLink = forwardRef<
|
||||
LinkProps & React.ComponentPropsWithoutRef<'a'>
|
||||
>(({ href, children, ...rest }, ref) => {
|
||||
return (
|
||||
<Link href={href}>
|
||||
<a ref={ref} {...rest}>
|
||||
{children}
|
||||
</a>
|
||||
<Link href={href} ref={ref} {...rest}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -37,24 +37,23 @@ const UserWarnings: React.FC<UserWarningsProps> = ({ onClick }) => {
|
||||
}
|
||||
|
||||
res = (
|
||||
<Link href={link}>
|
||||
<a
|
||||
onClick={onClick}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && onClick) {
|
||||
onClick();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className="mx-2 mb-2 flex items-center rounded-lg bg-yellow-500 p-2 text-xs text-white ring-1 ring-gray-700 transition duration-300 hover:bg-yellow-400"
|
||||
>
|
||||
<ExclamationTriangleIcon className="h-6 w-6" />
|
||||
<div className="flex min-w-0 flex-1 flex-col truncate px-2 last:pr-0">
|
||||
<span className="font-bold">{warningTitle}</span>
|
||||
<span className="truncate">{warningText}</span>
|
||||
</div>
|
||||
</a>
|
||||
<Link
|
||||
href={link}
|
||||
onClick={onClick}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && onClick) {
|
||||
onClick();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className="mx-2 mb-2 flex items-center rounded-lg bg-yellow-500 p-2 text-xs text-white ring-1 ring-gray-700 transition duration-300 hover:bg-yellow-400"
|
||||
>
|
||||
<ExclamationTriangleIcon className="h-6 w-6" />
|
||||
<div className="flex min-w-0 flex-1 flex-col truncate px-2 last:pr-0">
|
||||
<span className="font-bold">{warningTitle}</span>
|
||||
<span className="truncate">{warningText}</span>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -39,49 +39,48 @@ const VersionStatus = ({ onClick }: VersionStatusProps) => {
|
||||
: intl.formatMessage(messages.streamstable);
|
||||
|
||||
return (
|
||||
<Link href="/settings/about">
|
||||
<a
|
||||
onClick={onClick}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && onClick) {
|
||||
onClick();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={`mx-2 flex items-center rounded-lg p-2 text-xs ring-1 ring-gray-700 transition duration-300 ${
|
||||
data.updateAvailable
|
||||
? 'bg-yellow-500 text-white hover:bg-yellow-400'
|
||||
: 'bg-gray-900 text-gray-300 hover:bg-gray-800'
|
||||
}`}
|
||||
>
|
||||
{data.commitTag === 'local' ? (
|
||||
<CodeBracketIcon className="h-6 w-6" />
|
||||
) : data.version.startsWith('develop-') ? (
|
||||
<BeakerIcon className="h-6 w-6" />
|
||||
) : (
|
||||
<ServerIcon className="h-6 w-6" />
|
||||
)}
|
||||
<div className="flex min-w-0 flex-1 flex-col truncate px-2 last:pr-0">
|
||||
<span className="font-bold">{versionStream}</span>
|
||||
<span className="truncate">
|
||||
{data.commitTag === 'local' ? (
|
||||
'(⌐■_■)'
|
||||
) : data.commitsBehind > 0 ? (
|
||||
intl.formatMessage(messages.commitsbehind, {
|
||||
commitsBehind: data.commitsBehind,
|
||||
})
|
||||
) : data.commitsBehind === -1 ? (
|
||||
intl.formatMessage(messages.outofdate)
|
||||
) : (
|
||||
<code className="bg-transparent p-0">
|
||||
{data.version.replace('develop-', '')}
|
||||
</code>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{data.updateAvailable && <ArrowUpCircleIcon className="h-6 w-6" />}
|
||||
</a>
|
||||
<Link
|
||||
href="/settings/about"
|
||||
onClick={onClick}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && onClick) {
|
||||
onClick();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={`mx-2 flex items-center rounded-lg p-2 text-xs ring-1 ring-gray-700 transition duration-300 ${
|
||||
data.updateAvailable
|
||||
? 'bg-yellow-500 text-white hover:bg-yellow-400'
|
||||
: 'bg-gray-900 text-gray-300 hover:bg-gray-800'
|
||||
}`}
|
||||
>
|
||||
{data.commitTag === 'local' ? (
|
||||
<CodeBracketIcon className="h-6 w-6" />
|
||||
) : data.version.startsWith('develop-') ? (
|
||||
<BeakerIcon className="h-6 w-6" />
|
||||
) : (
|
||||
<ServerIcon className="h-6 w-6" />
|
||||
)}
|
||||
<div className="flex min-w-0 flex-1 flex-col truncate px-2 last:pr-0">
|
||||
<span className="font-bold">{versionStream}</span>
|
||||
<span className="truncate">
|
||||
{data.commitTag === 'local' ? (
|
||||
'(⌐■_■)'
|
||||
) : data.commitsBehind > 0 ? (
|
||||
intl.formatMessage(messages.commitsbehind, {
|
||||
commitsBehind: data.commitsBehind,
|
||||
})
|
||||
) : data.commitsBehind === -1 ? (
|
||||
intl.formatMessage(messages.outofdate)
|
||||
) : (
|
||||
<code className="bg-transparent p-0">
|
||||
{data.version.replace('develop-', '')}
|
||||
</code>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{data.updateAvailable && <ArrowUpCircleIcon className="h-6 w-6" />}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -137,7 +137,7 @@ const LocalLogin = ({ revalidate }: LocalLoginProps) => {
|
||||
</span>
|
||||
{passwordResetEnabled && (
|
||||
<span className="inline-flex rounded-md shadow-sm">
|
||||
<Link href="/resetpassword" passHref>
|
||||
<Link href="/resetpassword" passHref legacyBehavior>
|
||||
<Button as="a" buttonType="ghost">
|
||||
<LifebuoyIcon />
|
||||
<span>
|
||||
|
||||
@@ -328,19 +328,18 @@ const ManageSlideOver = ({
|
||||
: `/users/${user.id}`
|
||||
}
|
||||
key={`watch-user-${user.id}`}
|
||||
className="z-0 mb-1 -mr-2 shrink-0 hover:z-50"
|
||||
>
|
||||
<a className="z-0 mb-1 -mr-2 shrink-0 hover:z-50">
|
||||
<Tooltip
|
||||
key={`watch-user-${user.id}`}
|
||||
content={user.displayName}
|
||||
>
|
||||
<img
|
||||
src={user.avatar}
|
||||
alt={user.displayName}
|
||||
className="h-8 w-8 scale-100 transform-gpu rounded-full object-cover ring-1 ring-gray-500 transition duration-300 hover:scale-105"
|
||||
/>
|
||||
</Tooltip>
|
||||
</a>
|
||||
<Tooltip
|
||||
key={`watch-user-${user.id}`}
|
||||
content={user.displayName}
|
||||
>
|
||||
<img
|
||||
src={user.avatar}
|
||||
alt={user.displayName}
|
||||
className="h-8 w-8 scale-100 transform-gpu rounded-full object-cover ring-1 ring-gray-500 transition duration-300 hover:scale-105"
|
||||
/>
|
||||
</Tooltip>
|
||||
</Link>
|
||||
))}
|
||||
</span>
|
||||
@@ -488,19 +487,18 @@ const ManageSlideOver = ({
|
||||
: `/users/${user.id}`
|
||||
}
|
||||
key={`watch-user-${user.id}`}
|
||||
className="z-0 mb-1 -mr-2 shrink-0 hover:z-50"
|
||||
>
|
||||
<a className="z-0 mb-1 -mr-2 shrink-0 hover:z-50">
|
||||
<Tooltip
|
||||
key={`watch-user-${user.id}`}
|
||||
content={user.displayName}
|
||||
>
|
||||
<img
|
||||
src={user.avatar}
|
||||
alt={user.displayName}
|
||||
className="h-8 w-8 scale-100 transform-gpu rounded-full object-cover ring-1 ring-gray-500 transition duration-300 hover:scale-105"
|
||||
/>
|
||||
</Tooltip>
|
||||
</a>
|
||||
<Tooltip
|
||||
key={`watch-user-${user.id}`}
|
||||
content={user.displayName}
|
||||
>
|
||||
<img
|
||||
src={user.avatar}
|
||||
alt={user.displayName}
|
||||
className="h-8 w-8 scale-100 transform-gpu rounded-full object-cover ring-1 ring-gray-500 transition duration-300 hover:scale-105"
|
||||
/>
|
||||
</Tooltip>
|
||||
</Link>
|
||||
))}
|
||||
</span>
|
||||
|
||||
@@ -30,79 +30,78 @@ const ShowMoreCard = ({ url, posters }: ShowMoreCardProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Link href={url}>
|
||||
<a
|
||||
className={'w-36 sm:w-36 md:w-44'}
|
||||
onMouseEnter={() => {
|
||||
<Link
|
||||
href={url}
|
||||
className={'w-36 sm:w-36 md:w-44'}
|
||||
onMouseEnter={() => {
|
||||
setHovered(true);
|
||||
}}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setHovered(true);
|
||||
}}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setHovered(true);
|
||||
}
|
||||
}}
|
||||
role="link"
|
||||
tabIndex={0}
|
||||
}
|
||||
}}
|
||||
role="link"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div
|
||||
className={`relative w-36 transform-gpu cursor-pointer
|
||||
overflow-hidden rounded-xl text-white shadow-lg ring-1 transition duration-150 ease-in-out sm:w-36 md:w-44 ${
|
||||
isHovered
|
||||
? 'scale-105 bg-gray-600 ring-gray-500'
|
||||
: 'scale-100 bg-gray-800 ring-gray-700'
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`relative w-36 transform-gpu cursor-pointer
|
||||
overflow-hidden rounded-xl text-white shadow-lg ring-1 transition duration-150 ease-in-out sm:w-36 md:w-44 ${
|
||||
isHovered
|
||||
? 'scale-105 bg-gray-600 ring-gray-500'
|
||||
: 'scale-100 bg-gray-800 ring-gray-700'
|
||||
}`}
|
||||
>
|
||||
<div style={{ paddingBottom: '150%' }}>
|
||||
<div className="absolute inset-0 flex h-full w-full flex-col items-center p-2">
|
||||
<div className="relative z-10 flex h-full flex-wrap items-center justify-center opacity-30">
|
||||
{posters[0] && (
|
||||
<div className="w-1/2 p-1">
|
||||
<img
|
||||
src={`//image.tmdb.org/t/p/w300_and_h450_face${posters[0]}`}
|
||||
alt=""
|
||||
className="w-full rounded-md"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{posters[1] && (
|
||||
<div className="w-1/2 p-1">
|
||||
<img
|
||||
src={`//image.tmdb.org/t/p/w300_and_h450_face${posters[1]}`}
|
||||
alt=""
|
||||
className="w-full rounded-md"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{posters[2] && (
|
||||
<div className="w-1/2 p-1">
|
||||
<img
|
||||
src={`//image.tmdb.org/t/p/w300_and_h450_face${posters[2]}`}
|
||||
alt=""
|
||||
className="w-full rounded-md"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{posters[3] && (
|
||||
<div className="w-1/2 p-1">
|
||||
<img
|
||||
src={`//image.tmdb.org/t/p/w300_and_h450_face${posters[3]}`}
|
||||
alt=""
|
||||
className="w-full rounded-md"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="absolute inset-0 z-20 flex flex-col items-center justify-center text-white">
|
||||
<ArrowRightCircleIcon className="w-14" />
|
||||
<div className="mt-2 font-extrabold">
|
||||
{intl.formatMessage(messages.seemore)}
|
||||
<div style={{ paddingBottom: '150%' }}>
|
||||
<div className="absolute inset-0 flex h-full w-full flex-col items-center p-2">
|
||||
<div className="relative z-10 flex h-full flex-wrap items-center justify-center opacity-30">
|
||||
{posters[0] && (
|
||||
<div className="w-1/2 p-1">
|
||||
<img
|
||||
src={`//image.tmdb.org/t/p/w300_and_h450_face${posters[0]}`}
|
||||
alt=""
|
||||
className="w-full rounded-md"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{posters[1] && (
|
||||
<div className="w-1/2 p-1">
|
||||
<img
|
||||
src={`//image.tmdb.org/t/p/w300_and_h450_face${posters[1]}`}
|
||||
alt=""
|
||||
className="w-full rounded-md"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{posters[2] && (
|
||||
<div className="w-1/2 p-1">
|
||||
<img
|
||||
src={`//image.tmdb.org/t/p/w300_and_h450_face${posters[2]}`}
|
||||
alt=""
|
||||
className="w-full rounded-md"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{posters[3] && (
|
||||
<div className="w-1/2 p-1">
|
||||
<img
|
||||
src={`//image.tmdb.org/t/p/w300_and_h450_face${posters[3]}`}
|
||||
alt=""
|
||||
className="w-full rounded-md"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="absolute inset-0 z-20 flex flex-col items-center justify-center text-white">
|
||||
<ArrowRightCircleIcon className="w-14" />
|
||||
<div className="mt-2 font-extrabold">
|
||||
{intl.formatMessage(messages.seemore)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -152,11 +152,9 @@ const MediaSlider = ({
|
||||
<>
|
||||
<div className="slider-header">
|
||||
{linkUrl ? (
|
||||
<Link href={linkUrl}>
|
||||
<a className="slider-title min-w-0 pr-16">
|
||||
<span className="truncate">{title}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</a>
|
||||
<Link href={linkUrl} className="slider-title min-w-0 pr-16">
|
||||
<span className="truncate">{title}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</Link>
|
||||
) : (
|
||||
<div className="slider-title">
|
||||
|
||||
@@ -34,8 +34,8 @@ const MovieCast = () => {
|
||||
<div className="mt-1 mb-5">
|
||||
<Header
|
||||
subtext={
|
||||
<Link href={`/movie/${data.id}`}>
|
||||
<a className="hover:underline">{data.title}</a>
|
||||
<Link href={`/movie/${data.id}`} className="hover:underline">
|
||||
{data.title}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -34,8 +34,8 @@ const MovieCrew = () => {
|
||||
<div className="mt-1 mb-5">
|
||||
<Header
|
||||
subtext={
|
||||
<Link href={`/movie/${data.id}`}>
|
||||
<a className="hover:underline">{data.title}</a>
|
||||
<Link href={`/movie/${data.id}`} className="hover:underline">
|
||||
{data.title}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -44,8 +44,8 @@ const MovieRecommendations = () => {
|
||||
<div className="mt-1 mb-5">
|
||||
<Header
|
||||
subtext={
|
||||
<Link href={`/movie/${movieData?.id}`}>
|
||||
<a className="hover:underline">{movieData?.title}</a>
|
||||
<Link href={`/movie/${movieData?.id}`} className="hover:underline">
|
||||
{movieData?.title}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -42,8 +42,8 @@ const MovieSimilar = () => {
|
||||
<div className="mt-1 mb-5">
|
||||
<Header
|
||||
subtext={
|
||||
<Link href={`/movie/${movieData?.id}`}>
|
||||
<a className="hover:underline">{movieData?.title}</a>
|
||||
<Link href={`/movie/${movieData?.id}`} className="hover:underline">
|
||||
{movieData?.title}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -239,8 +239,12 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
||||
movieAttributes.push(
|
||||
data.genres
|
||||
.map((g) => (
|
||||
<Link href={`/discover/movies?genre=${g.id}`} key={`genre-${g.id}`}>
|
||||
<a className="hover:underline">{g.name}</a>
|
||||
<Link
|
||||
href={`/discover/movies?genre=${g.id}`}
|
||||
key={`genre-${g.id}`}
|
||||
className="hover:underline"
|
||||
>
|
||||
{g.name}
|
||||
</Link>
|
||||
))
|
||||
.reduce((prev, curr) => (
|
||||
@@ -483,18 +487,19 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
||||
{sortedCrew.slice(0, 6).map((person) => (
|
||||
<li key={`crew-${person.job}-${person.id}`}>
|
||||
<span>{person.job}</span>
|
||||
<Link href={`/person/${person.id}`}>
|
||||
<a className="crew-name">{person.name}</a>
|
||||
<Link href={`/person/${person.id}`} className="crew-name">
|
||||
{person.name}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="mt-4 flex justify-end">
|
||||
<Link href={`/movie/${data.id}/crew`}>
|
||||
<a className="flex items-center text-gray-400 transition duration-300 hover:text-gray-100">
|
||||
<span>{intl.formatMessage(messages.viewfullcrew)}</span>
|
||||
<ArrowRightCircleIcon className="ml-1.5 inline-block h-5 w-5" />
|
||||
</a>
|
||||
<Link
|
||||
href={`/movie/${data.id}/crew`}
|
||||
className="flex items-center text-gray-400 transition duration-300 hover:text-gray-100"
|
||||
>
|
||||
<span>{intl.formatMessage(messages.viewfullcrew)}</span>
|
||||
<ArrowRightCircleIcon className="ml-1.5 inline-block h-5 w-5" />
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
@@ -505,10 +510,9 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
||||
<Link
|
||||
href={`/discover/movies?keywords=${keyword.id}`}
|
||||
key={`keyword-id-${keyword.id}`}
|
||||
className="mb-2 mr-2 inline-flex last:mr-0"
|
||||
>
|
||||
<a className="mb-2 mr-2 inline-flex last:mr-0">
|
||||
<Tag>{keyword.name}</Tag>
|
||||
</a>
|
||||
<Tag>{keyword.name}</Tag>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
@@ -518,31 +522,29 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
||||
{data.collection && (
|
||||
<div className="mb-6">
|
||||
<Link href={`/collection/${data.collection.id}`}>
|
||||
<a>
|
||||
<div className="group relative z-0 scale-100 transform-gpu cursor-pointer overflow-hidden rounded-lg bg-gray-800 bg-cover bg-center shadow-md ring-1 ring-gray-700 transition duration-300 hover:scale-105 hover:ring-gray-500">
|
||||
<div className="absolute inset-0 z-0">
|
||||
<CachedImage
|
||||
src={`https://image.tmdb.org/t/p/w1440_and_h320_multi_faces/${data.collection.backdropPath}`}
|
||||
alt=""
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'linear-gradient(180deg, rgba(31, 41, 55, 0.47) 0%, rgba(31, 41, 55, 0.80) 100%)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative z-10 flex h-14 items-center justify-between p-4 text-gray-200 transition duration-300 group-hover:text-white">
|
||||
<div>{data.collection.name}</div>
|
||||
<Button buttonSize="sm">
|
||||
{intl.formatMessage(globalMessages.view)}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="group relative z-0 scale-100 transform-gpu cursor-pointer overflow-hidden rounded-lg bg-gray-800 bg-cover bg-center shadow-md ring-1 ring-gray-700 transition duration-300 hover:scale-105 hover:ring-gray-500">
|
||||
<div className="absolute inset-0 z-0">
|
||||
<CachedImage
|
||||
src={`https://image.tmdb.org/t/p/w1440_and_h320_multi_faces/${data.collection.backdropPath}`}
|
||||
alt=""
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'linear-gradient(180deg, rgba(31, 41, 55, 0.47) 0%, rgba(31, 41, 55, 0.80) 100%)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
<div className="relative z-10 flex h-14 items-center justify-between p-4 text-gray-200 transition duration-300 group-hover:text-white">
|
||||
<div>{data.collection.name}</div>
|
||||
<Button buttonSize="sm">
|
||||
{intl.formatMessage(globalMessages.view)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
@@ -739,15 +741,13 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
||||
<Link
|
||||
href={`/discover/movies/language/${data.originalLanguage}`}
|
||||
>
|
||||
<a>
|
||||
{intl.formatDisplayName(data.originalLanguage, {
|
||||
type: 'language',
|
||||
fallback: 'none',
|
||||
}) ??
|
||||
data.spokenLanguages.find(
|
||||
(lng) => lng.iso_639_1 === data.originalLanguage
|
||||
)?.name}
|
||||
</a>
|
||||
{intl.formatDisplayName(data.originalLanguage, {
|
||||
type: 'language',
|
||||
fallback: 'none',
|
||||
}) ??
|
||||
data.spokenLanguages.find(
|
||||
(lng) => lng.iso_639_1 === data.originalLanguage
|
||||
)?.name}
|
||||
</Link>
|
||||
</span>
|
||||
</div>
|
||||
@@ -803,8 +803,9 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
||||
<Link
|
||||
href={`/discover/movies/studio/${s.id}`}
|
||||
key={`studio-${s.id}`}
|
||||
className="block"
|
||||
>
|
||||
<a className="block">{s.name}</a>
|
||||
{s.name}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
@@ -864,11 +865,13 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
||||
{data.credits.cast.length > 0 && (
|
||||
<>
|
||||
<div className="slider-header">
|
||||
<Link href="/movie/[movieId]/cast" as={`/movie/${data.id}/cast`}>
|
||||
<a className="slider-title">
|
||||
<span>{intl.formatMessage(messages.cast)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</a>
|
||||
<Link
|
||||
href="/movie/[movieId]/cast"
|
||||
as={`/movie/${data.id}/cast`}
|
||||
className="slider-title"
|
||||
>
|
||||
<span>{intl.formatMessage(messages.cast)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</Link>
|
||||
</div>
|
||||
<Slider
|
||||
|
||||
@@ -21,71 +21,68 @@ const PersonCard = ({
|
||||
const [isHovered, setHovered] = useState(false);
|
||||
|
||||
return (
|
||||
<Link href={`/person/${personId}`}>
|
||||
<a
|
||||
className={canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'}
|
||||
onMouseEnter={() => {
|
||||
<Link
|
||||
href={`/person/${personId}`}
|
||||
className={canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'}
|
||||
onMouseEnter={() => {
|
||||
setHovered(true);
|
||||
}}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setHovered(true);
|
||||
}}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setHovered(true);
|
||||
}
|
||||
}}
|
||||
role="link"
|
||||
tabIndex={0}
|
||||
}
|
||||
}}
|
||||
role="link"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div
|
||||
className={`relative ${
|
||||
canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'
|
||||
} transform-gpu cursor-pointer rounded-xl text-white shadow ring-1 transition duration-150 ease-in-out ${
|
||||
isHovered
|
||||
? 'scale-105 bg-gray-700 ring-gray-500'
|
||||
: 'scale-100 bg-gray-800 ring-gray-700'
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`relative ${
|
||||
canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'
|
||||
} transform-gpu cursor-pointer rounded-xl text-white shadow ring-1 transition duration-150 ease-in-out ${
|
||||
isHovered
|
||||
? 'scale-105 bg-gray-700 ring-gray-500'
|
||||
: 'scale-100 bg-gray-800 ring-gray-700'
|
||||
}`}
|
||||
>
|
||||
<div style={{ paddingBottom: '150%' }}>
|
||||
<div className="absolute inset-0 flex h-full w-full flex-col items-center p-2">
|
||||
<div className="relative mt-2 mb-4 flex h-1/2 w-full justify-center">
|
||||
{profilePath ? (
|
||||
<div className="relative h-full w-3/4 overflow-hidden rounded-full ring-1 ring-gray-700">
|
||||
<CachedImage
|
||||
src={`https://image.tmdb.org/t/p/w600_and_h900_bestv2${profilePath}`}
|
||||
alt=""
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<UserCircleIcon className="h-full" />
|
||||
)}
|
||||
</div>
|
||||
<div className="w-full truncate text-center font-bold">
|
||||
{name}
|
||||
</div>
|
||||
{subName && (
|
||||
<div
|
||||
className="overflow-hidden whitespace-normal text-center text-sm text-gray-300"
|
||||
style={{
|
||||
WebkitLineClamp: 2,
|
||||
display: '-webkit-box',
|
||||
overflow: 'hidden',
|
||||
WebkitBoxOrient: 'vertical',
|
||||
}}
|
||||
>
|
||||
{subName}
|
||||
<div style={{ paddingBottom: '150%' }}>
|
||||
<div className="absolute inset-0 flex h-full w-full flex-col items-center p-2">
|
||||
<div className="relative mt-2 mb-4 flex h-1/2 w-full justify-center">
|
||||
{profilePath ? (
|
||||
<div className="relative h-full w-3/4 overflow-hidden rounded-full ring-1 ring-gray-700">
|
||||
<CachedImage
|
||||
src={`https://image.tmdb.org/t/p/w600_and_h900_bestv2${profilePath}`}
|
||||
alt=""
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<UserCircleIcon className="h-full" />
|
||||
)}
|
||||
<div
|
||||
className={`absolute bottom-0 left-0 right-0 h-12 rounded-b-xl bg-gradient-to-t ${
|
||||
isHovered ? 'from-gray-800' : 'from-gray-900'
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full truncate text-center font-bold">{name}</div>
|
||||
{subName && (
|
||||
<div
|
||||
className="overflow-hidden whitespace-normal text-center text-sm text-gray-300"
|
||||
style={{
|
||||
WebkitLineClamp: 2,
|
||||
display: '-webkit-box',
|
||||
overflow: 'hidden',
|
||||
WebkitBoxOrient: 'vertical',
|
||||
}}
|
||||
>
|
||||
{subName}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={`absolute bottom-0 left-0 right-0 h-12 rounded-b-xl bg-gradient-to-t ${
|
||||
isHovered ? 'from-gray-800' : 'from-gray-900'
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -101,10 +101,9 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
|
||||
? '/profile'
|
||||
: `/users/${request.requestedBy.id}`
|
||||
}
|
||||
className="font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline"
|
||||
>
|
||||
<a className="font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline">
|
||||
{request.requestedBy.displayName}
|
||||
</a>
|
||||
{request.requestedBy.displayName}
|
||||
</Link>
|
||||
</span>
|
||||
</div>
|
||||
@@ -120,10 +119,9 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
|
||||
? '/profile'
|
||||
: `/users/${request.modifiedBy.id}`
|
||||
}
|
||||
className="font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline"
|
||||
>
|
||||
<a className="font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline">
|
||||
{request.modifiedBy.displayName}
|
||||
</a>
|
||||
{request.modifiedBy.displayName}
|
||||
</Link>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -106,17 +106,18 @@ const RequestCardError = ({ requestData }: RequestCardErrorProps) => {
|
||||
{ type: 'or' }
|
||||
) && (
|
||||
<div className="card-field !hidden sm:!block">
|
||||
<Link href={`/users/${requestData.requestedBy.id}`}>
|
||||
<a className="group flex items-center">
|
||||
<img
|
||||
src={requestData.requestedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm"
|
||||
/>
|
||||
<span className="truncate group-hover:underline">
|
||||
{requestData.requestedBy.displayName}
|
||||
</span>
|
||||
</a>
|
||||
<Link
|
||||
href={`/users/${requestData.requestedBy.id}`}
|
||||
className="group flex items-center"
|
||||
>
|
||||
<img
|
||||
src={requestData.requestedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm"
|
||||
/>
|
||||
<span className="truncate group-hover:underline">
|
||||
{requestData.requestedBy.displayName}
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
@@ -352,27 +353,27 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
|
||||
? `/movie/${requestData.media.tmdbId}`
|
||||
: `/tv/${requestData.media.tmdbId}`
|
||||
}
|
||||
className="overflow-hidden overflow-ellipsis whitespace-nowrap text-base font-bold text-white hover:underline sm:text-lg"
|
||||
>
|
||||
<a className="overflow-hidden overflow-ellipsis whitespace-nowrap text-base font-bold text-white hover:underline sm:text-lg">
|
||||
{isMovie(title) ? title.title : title.name}
|
||||
</a>
|
||||
{isMovie(title) ? title.title : title.name}
|
||||
</Link>
|
||||
{hasPermission(
|
||||
[Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],
|
||||
{ type: 'or' }
|
||||
) && (
|
||||
<div className="card-field">
|
||||
<Link href={`/users/${requestData.requestedBy.id}`}>
|
||||
<a className="group flex items-center">
|
||||
<img
|
||||
src={requestData.requestedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm object-cover"
|
||||
/>
|
||||
<span className="truncate font-semibold group-hover:text-white group-hover:underline">
|
||||
{requestData.requestedBy.displayName}
|
||||
</span>
|
||||
</a>
|
||||
<Link
|
||||
href={`/users/${requestData.requestedBy.id}`}
|
||||
className="group flex items-center"
|
||||
>
|
||||
<img
|
||||
src={requestData.requestedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm object-cover"
|
||||
/>
|
||||
<span className="truncate font-semibold group-hover:text-white group-hover:underline">
|
||||
{requestData.requestedBy.displayName}
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
@@ -572,20 +573,19 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
|
||||
? `/movie/${requestData.media.tmdbId}`
|
||||
: `/tv/${requestData.media.tmdbId}`
|
||||
}
|
||||
className="w-20 flex-shrink-0 scale-100 transform-gpu cursor-pointer overflow-hidden rounded-md shadow-sm transition duration-300 hover:scale-105 hover:shadow-md sm:w-28"
|
||||
>
|
||||
<a className="w-20 flex-shrink-0 scale-100 transform-gpu cursor-pointer overflow-hidden rounded-md shadow-sm transition duration-300 hover:scale-105 hover:shadow-md sm:w-28">
|
||||
<CachedImage
|
||||
src={
|
||||
title.posterPath
|
||||
? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${title.posterPath}`
|
||||
: '/images/overseerr_poster_not_found.png'
|
||||
}
|
||||
alt=""
|
||||
layout="responsive"
|
||||
width={600}
|
||||
height={900}
|
||||
/>
|
||||
</a>
|
||||
<CachedImage
|
||||
src={
|
||||
title.posterPath
|
||||
? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${title.posterPath}`
|
||||
: '/images/overseerr_poster_not_found.png'
|
||||
}
|
||||
alt=""
|
||||
layout="responsive"
|
||||
width={600}
|
||||
height={900}
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -179,17 +179,18 @@ const RequestItemError = ({
|
||||
/>
|
||||
),
|
||||
user: (
|
||||
<Link href={`/users/${requestData.requestedBy.id}`}>
|
||||
<a className="group flex items-center truncate">
|
||||
<img
|
||||
src={requestData.requestedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm ml-1.5"
|
||||
/>
|
||||
<span className="truncate text-sm group-hover:underline">
|
||||
{requestData.requestedBy.displayName}
|
||||
</span>
|
||||
</a>
|
||||
<Link
|
||||
href={`/users/${requestData.requestedBy.id}`}
|
||||
className="group flex items-center truncate"
|
||||
>
|
||||
<img
|
||||
src={requestData.requestedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm ml-1.5"
|
||||
/>
|
||||
<span className="truncate text-sm group-hover:underline">
|
||||
{requestData.requestedBy.displayName}
|
||||
</span>
|
||||
</Link>
|
||||
),
|
||||
})}
|
||||
@@ -233,17 +234,18 @@ const RequestItemError = ({
|
||||
/>
|
||||
),
|
||||
user: (
|
||||
<Link href={`/users/${requestData.modifiedBy.id}`}>
|
||||
<a className="group flex items-center truncate">
|
||||
<img
|
||||
src={requestData.modifiedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm ml-1.5"
|
||||
/>
|
||||
<span className="truncate text-sm group-hover:underline">
|
||||
{requestData.modifiedBy.displayName}
|
||||
</span>
|
||||
</a>
|
||||
<Link
|
||||
href={`/users/${requestData.modifiedBy.id}`}
|
||||
className="group flex items-center truncate"
|
||||
>
|
||||
<img
|
||||
src={requestData.modifiedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm ml-1.5"
|
||||
/>
|
||||
<span className="truncate text-sm group-hover:underline">
|
||||
{requestData.modifiedBy.displayName}
|
||||
</span>
|
||||
</Link>
|
||||
),
|
||||
})}
|
||||
@@ -401,21 +403,20 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
|
||||
? `/movie/${requestData.media.tmdbId}`
|
||||
: `/tv/${requestData.media.tmdbId}`
|
||||
}
|
||||
className="relative h-auto w-12 flex-shrink-0 scale-100 transform-gpu overflow-hidden rounded-md transition duration-300 hover:scale-105"
|
||||
>
|
||||
<a className="relative h-auto w-12 flex-shrink-0 scale-100 transform-gpu overflow-hidden rounded-md transition duration-300 hover:scale-105">
|
||||
<CachedImage
|
||||
src={
|
||||
title.posterPath
|
||||
? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${title.posterPath}`
|
||||
: '/images/overseerr_poster_not_found.png'
|
||||
}
|
||||
alt=""
|
||||
layout="responsive"
|
||||
width={600}
|
||||
height={900}
|
||||
objectFit="cover"
|
||||
/>
|
||||
</a>
|
||||
<CachedImage
|
||||
src={
|
||||
title.posterPath
|
||||
? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${title.posterPath}`
|
||||
: '/images/overseerr_poster_not_found.png'
|
||||
}
|
||||
alt=""
|
||||
layout="responsive"
|
||||
width={600}
|
||||
height={900}
|
||||
objectFit="cover"
|
||||
/>
|
||||
</Link>
|
||||
<div className="flex flex-col justify-center overflow-hidden pl-2 xl:pl-4">
|
||||
<div className="pt-0.5 text-xs font-medium text-white sm:pt-1">
|
||||
@@ -430,10 +431,9 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
|
||||
? `/movie/${requestData.media.tmdbId}`
|
||||
: `/tv/${requestData.media.tmdbId}`
|
||||
}
|
||||
className="mr-2 min-w-0 truncate text-lg font-bold text-white hover:underline xl:text-xl"
|
||||
>
|
||||
<a className="mr-2 min-w-0 truncate text-lg font-bold text-white hover:underline xl:text-xl">
|
||||
{isMovie(title) ? title.title : title.name}
|
||||
</a>
|
||||
{isMovie(title) ? title.title : title.name}
|
||||
</Link>
|
||||
{!isMovie(title) && request.seasons.length > 0 && (
|
||||
<div className="card-field">
|
||||
@@ -527,17 +527,18 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
|
||||
/>
|
||||
),
|
||||
user: (
|
||||
<Link href={`/users/${requestData.requestedBy.id}`}>
|
||||
<a className="group flex items-center truncate">
|
||||
<img
|
||||
src={requestData.requestedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm ml-1.5 object-cover"
|
||||
/>
|
||||
<span className="truncate text-sm font-semibold group-hover:text-white group-hover:underline">
|
||||
{requestData.requestedBy.displayName}
|
||||
</span>
|
||||
</a>
|
||||
<Link
|
||||
href={`/users/${requestData.requestedBy.id}`}
|
||||
className="group flex items-center truncate"
|
||||
>
|
||||
<img
|
||||
src={requestData.requestedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm ml-1.5 object-cover"
|
||||
/>
|
||||
<span className="truncate text-sm font-semibold group-hover:text-white group-hover:underline">
|
||||
{requestData.requestedBy.displayName}
|
||||
</span>
|
||||
</Link>
|
||||
),
|
||||
})}
|
||||
@@ -581,17 +582,18 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
|
||||
/>
|
||||
),
|
||||
user: (
|
||||
<Link href={`/users/${requestData.modifiedBy.id}`}>
|
||||
<a className="group flex items-center truncate">
|
||||
<img
|
||||
src={requestData.modifiedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm ml-1.5 object-cover"
|
||||
/>
|
||||
<span className="truncate text-sm font-semibold group-hover:text-white group-hover:underline">
|
||||
{requestData.modifiedBy.displayName}
|
||||
</span>
|
||||
</a>
|
||||
<Link
|
||||
href={`/users/${requestData.modifiedBy.id}`}
|
||||
className="group flex items-center truncate"
|
||||
>
|
||||
<img
|
||||
src={requestData.modifiedBy.avatar}
|
||||
alt=""
|
||||
className="avatar-sm ml-1.5 object-cover"
|
||||
/>
|
||||
<span className="truncate text-sm font-semibold group-hover:text-white group-hover:underline">
|
||||
{requestData.modifiedBy.displayName}
|
||||
</span>
|
||||
</Link>
|
||||
),
|
||||
})}
|
||||
|
||||
@@ -122,12 +122,12 @@ const RequestList = () => {
|
||||
<Header
|
||||
subtext={
|
||||
router.pathname.startsWith('/profile') ? (
|
||||
<Link href={`/profile`}>
|
||||
<a className="hover:underline">{currentUser?.displayName}</a>
|
||||
<Link href={`/profile`} className="hover:underline">
|
||||
{currentUser?.displayName}
|
||||
</Link>
|
||||
) : router.query.userId ? (
|
||||
<Link href={`/users/${user?.id}`}>
|
||||
<a className="hover:underline">{user?.displayName}</a>
|
||||
<Link href={`/users/${user?.id}`} className="hover:underline">
|
||||
{user?.displayName}
|
||||
</Link>
|
||||
) : (
|
||||
''
|
||||
|
||||
@@ -131,10 +131,9 @@ const QuotaDisplay = ({
|
||||
ProfileLink: (msg: React.ReactNode) => (
|
||||
<Link
|
||||
href={userOverride ? `/users/${userOverride}` : '/profile'}
|
||||
className="text-white transition duration-300 hover:underline"
|
||||
>
|
||||
<a className="text-white transition duration-300 hover:underline">
|
||||
{msg}
|
||||
</a>
|
||||
{msg}
|
||||
</Link>
|
||||
),
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ const ResetPassword = () => {
|
||||
{intl.formatMessage(messages.requestresetlinksuccessmessage)}
|
||||
</p>
|
||||
<span className="mt-4 flex justify-center rounded-md shadow-sm">
|
||||
<Link href="/login" passHref>
|
||||
<Link href="/login" passHref legacyBehavior>
|
||||
<Button as="a" buttonType="ghost">
|
||||
<ArrowLeftIcon />
|
||||
<span>{intl.formatMessage(messages.gobacklogin)}</span>
|
||||
|
||||
@@ -81,7 +81,7 @@ const ResetPassword = () => {
|
||||
{intl.formatMessage(messages.resetpasswordsuccessmessage)}
|
||||
</p>
|
||||
<span className="mt-4 flex justify-center rounded-md shadow-sm">
|
||||
<Link href="/login" passHref>
|
||||
<Link href="/login" passHref legacyBehavior>
|
||||
<Button as="a" buttonType="ghost">
|
||||
{intl.formatMessage(messages.gobacklogin)}
|
||||
</Button>
|
||||
|
||||
@@ -309,6 +309,7 @@ const NotificationsWebhook = () => {
|
||||
<Link
|
||||
href="https://docs.overseerr.dev/using-overseerr/notifications/webhooks#template-variables"
|
||||
passHref
|
||||
legacyBehavior
|
||||
>
|
||||
<Button
|
||||
as="a"
|
||||
|
||||
@@ -306,60 +306,55 @@ const TitleCard = ({
|
||||
? `/collection/${id}`
|
||||
: `/tv/${id}`
|
||||
}
|
||||
className="absolute inset-0 h-full w-full cursor-pointer overflow-hidden text-left"
|
||||
style={{
|
||||
background:
|
||||
'linear-gradient(180deg, rgba(45, 55, 72, 0.4) 0%, rgba(45, 55, 72, 0.9) 100%)',
|
||||
}}
|
||||
>
|
||||
<a
|
||||
className="absolute inset-0 h-full w-full cursor-pointer overflow-hidden text-left"
|
||||
style={{
|
||||
background:
|
||||
'linear-gradient(180deg, rgba(45, 55, 72, 0.4) 0%, rgba(45, 55, 72, 0.9) 100%)',
|
||||
}}
|
||||
>
|
||||
<div className="flex h-full w-full items-end">
|
||||
<div
|
||||
className={`px-2 text-white ${
|
||||
!showRequestButton ||
|
||||
(currentStatus && currentStatus !== MediaStatus.UNKNOWN)
|
||||
? 'pb-2'
|
||||
: 'pb-11'
|
||||
}`}
|
||||
>
|
||||
{year && (
|
||||
<div className="text-sm font-medium">{year}</div>
|
||||
)}
|
||||
<div className="flex h-full w-full items-end">
|
||||
<div
|
||||
className={`px-2 text-white ${
|
||||
!showRequestButton ||
|
||||
(currentStatus && currentStatus !== MediaStatus.UNKNOWN)
|
||||
? 'pb-2'
|
||||
: 'pb-11'
|
||||
}`}
|
||||
>
|
||||
{year && <div className="text-sm font-medium">{year}</div>}
|
||||
|
||||
<h1
|
||||
className="whitespace-normal text-xl font-bold leading-tight"
|
||||
style={{
|
||||
WebkitLineClamp: 3,
|
||||
display: '-webkit-box',
|
||||
overflow: 'hidden',
|
||||
WebkitBoxOrient: 'vertical',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
data-testid="title-card-title"
|
||||
>
|
||||
{title}
|
||||
</h1>
|
||||
<div
|
||||
className="whitespace-normal text-xs"
|
||||
style={{
|
||||
WebkitLineClamp:
|
||||
!showRequestButton ||
|
||||
(currentStatus &&
|
||||
currentStatus !== MediaStatus.UNKNOWN)
|
||||
? 5
|
||||
: 3,
|
||||
display: '-webkit-box',
|
||||
overflow: 'hidden',
|
||||
WebkitBoxOrient: 'vertical',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{summary}
|
||||
</div>
|
||||
<h1
|
||||
className="whitespace-normal text-xl font-bold leading-tight"
|
||||
style={{
|
||||
WebkitLineClamp: 3,
|
||||
display: '-webkit-box',
|
||||
overflow: 'hidden',
|
||||
WebkitBoxOrient: 'vertical',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
data-testid="title-card-title"
|
||||
>
|
||||
{title}
|
||||
</h1>
|
||||
<div
|
||||
className="whitespace-normal text-xs"
|
||||
style={{
|
||||
WebkitLineClamp:
|
||||
!showRequestButton ||
|
||||
(currentStatus &&
|
||||
currentStatus !== MediaStatus.UNKNOWN)
|
||||
? 5
|
||||
: 3,
|
||||
display: '-webkit-box',
|
||||
overflow: 'hidden',
|
||||
WebkitBoxOrient: 'vertical',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{summary}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
<div className="absolute bottom-0 left-0 right-0 flex justify-between px-2 py-2">
|
||||
|
||||
@@ -34,8 +34,8 @@ const TvCast = () => {
|
||||
<div className="mt-1 mb-5">
|
||||
<Header
|
||||
subtext={
|
||||
<Link href={`/tv/${data.id}`}>
|
||||
<a className="hover:underline">{data.name}</a>
|
||||
<Link href={`/tv/${data.id}`} className="hover:underline">
|
||||
{data.name}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -34,8 +34,8 @@ const TvCrew = () => {
|
||||
<div className="mt-1 mb-5">
|
||||
<Header
|
||||
subtext={
|
||||
<Link href={`/tv/${data.id}`}>
|
||||
<a className="hover:underline">{data.name}</a>
|
||||
<Link href={`/tv/${data.id}`} className="hover:underline">
|
||||
{data.name}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -40,8 +40,8 @@ const TvRecommendations = () => {
|
||||
<div className="mt-1 mb-5">
|
||||
<Header
|
||||
subtext={
|
||||
<Link href={`/tv/${tvData?.id}`}>
|
||||
<a className="hover:underline">{tvData?.name}</a>
|
||||
<Link href={`/tv/${tvData?.id}`} className="hover:underline">
|
||||
{tvData?.name}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -38,8 +38,8 @@ const TvSimilar = () => {
|
||||
<div className="mt-1 mb-5">
|
||||
<Header
|
||||
subtext={
|
||||
<Link href={`/tv/${tvData?.id}`}>
|
||||
<a className="hover:underline">{tvData?.name}</a>
|
||||
<Link href={`/tv/${tvData?.id}`} className="hover:underline">
|
||||
{tvData?.name}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -222,8 +222,12 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
||||
seriesAttributes.push(
|
||||
data.genres
|
||||
.map((g) => (
|
||||
<Link href={`/discover/tv?genre=${g.id}`} key={`genre-${g.id}`}>
|
||||
<a className="hover:underline">{g.name}</a>
|
||||
<Link
|
||||
href={`/discover/tv?genre=${g.id}`}
|
||||
key={`genre-${g.id}`}
|
||||
className="hover:underline"
|
||||
>
|
||||
{g.name}
|
||||
</Link>
|
||||
))
|
||||
.reduce((prev, curr) => (
|
||||
@@ -519,18 +523,19 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
||||
.map((person) => (
|
||||
<li key={`crew-${person.job}-${person.id}`}>
|
||||
<span>{person.job}</span>
|
||||
<Link href={`/person/${person.id}`}>
|
||||
<a className="crew-name">{person.name}</a>
|
||||
<Link href={`/person/${person.id}`} className="crew-name">
|
||||
{person.name}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="mt-4 flex justify-end">
|
||||
<Link href={`/tv/${data.id}/crew`}>
|
||||
<a className="flex items-center text-gray-400 transition duration-300 hover:text-gray-100">
|
||||
<span>{intl.formatMessage(messages.viewfullcrew)}</span>
|
||||
<ArrowRightCircleIcon className="ml-1.5 inline-block h-5 w-5" />
|
||||
</a>
|
||||
<Link
|
||||
href={`/tv/${data.id}/crew`}
|
||||
className="flex items-center text-gray-400 transition duration-300 hover:text-gray-100"
|
||||
>
|
||||
<span>{intl.formatMessage(messages.viewfullcrew)}</span>
|
||||
<ArrowRightCircleIcon className="ml-1.5 inline-block h-5 w-5" />
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
@@ -541,10 +546,9 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
||||
<Link
|
||||
href={`/discover/tv?keywords=${keyword.id}`}
|
||||
key={`keyword-id-${keyword.id}`}
|
||||
className="mb-2 mr-2 inline-flex last:mr-0"
|
||||
>
|
||||
<a className="mb-2 mr-2 inline-flex last:mr-0">
|
||||
<Tag>{keyword.name}</Tag>
|
||||
</a>
|
||||
<Tag>{keyword.name}</Tag>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
@@ -919,15 +923,13 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
||||
<span>{intl.formatMessage(messages.originallanguage)}</span>
|
||||
<span className="media-fact-value">
|
||||
<Link href={`/discover/tv/language/${data.originalLanguage}`}>
|
||||
<a>
|
||||
{intl.formatDisplayName(data.originalLanguage, {
|
||||
type: 'language',
|
||||
fallback: 'none',
|
||||
}) ??
|
||||
data.spokenLanguages.find(
|
||||
(lng) => lng.iso_639_1 === data.originalLanguage
|
||||
)?.name}
|
||||
</a>
|
||||
{intl.formatDisplayName(data.originalLanguage, {
|
||||
type: 'language',
|
||||
fallback: 'none',
|
||||
}) ??
|
||||
data.spokenLanguages.find(
|
||||
(lng) => lng.iso_639_1 === data.originalLanguage
|
||||
)?.name}
|
||||
</Link>
|
||||
</span>
|
||||
</div>
|
||||
@@ -977,7 +979,7 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
||||
href={`/discover/tv/network/${n.id}`}
|
||||
key={`network-${n.id}`}
|
||||
>
|
||||
<a>{n.name}</a>
|
||||
{n.name}
|
||||
</Link>
|
||||
))
|
||||
.reduce((prev, curr) => (
|
||||
@@ -1021,11 +1023,13 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
||||
{data.credits.cast.length > 0 && (
|
||||
<>
|
||||
<div className="slider-header">
|
||||
<Link href="/tv/[tvId]/cast" as={`/tv/${data.id}/cast`}>
|
||||
<a className="slider-title">
|
||||
<span>{intl.formatMessage(messages.cast)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</a>
|
||||
<Link
|
||||
href="/tv/[tvId]/cast"
|
||||
as={`/tv/${data.id}/cast`}
|
||||
className="slider-title"
|
||||
>
|
||||
<span>{intl.formatMessage(messages.cast)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</Link>
|
||||
</div>
|
||||
<Slider
|
||||
|
||||
@@ -609,23 +609,23 @@ const UserList = () => {
|
||||
</Table.TD>
|
||||
<Table.TD>
|
||||
<div className="flex items-center">
|
||||
<Link href={`/users/${user.id}`}>
|
||||
<a className="h-10 w-10 flex-shrink-0">
|
||||
<img
|
||||
className="h-10 w-10 rounded-full object-cover"
|
||||
src={user.avatar}
|
||||
alt=""
|
||||
/>
|
||||
</a>
|
||||
<Link
|
||||
href={`/users/${user.id}`}
|
||||
className="h-10 w-10 flex-shrink-0"
|
||||
>
|
||||
<img
|
||||
className="h-10 w-10 rounded-full object-cover"
|
||||
src={user.avatar}
|
||||
alt=""
|
||||
/>
|
||||
</Link>
|
||||
<div className="ml-4">
|
||||
<Link href={`/users/${user.id}`}>
|
||||
<a
|
||||
className="text-base font-bold leading-5 transition duration-300 hover:underline"
|
||||
data-testid="user-list-username-link"
|
||||
>
|
||||
{user.displayName}
|
||||
</a>
|
||||
<Link
|
||||
href={`/users/${user.id}`}
|
||||
className="text-base font-bold leading-5 transition duration-300 hover:underline"
|
||||
data-testid="user-list-username-link"
|
||||
>
|
||||
{user.displayName}
|
||||
</Link>
|
||||
{user.displayName.toLowerCase() !== user.email && (
|
||||
<div className="text-sm leading-5 text-gray-300">
|
||||
@@ -641,10 +641,11 @@ const UserList = () => {
|
||||
[Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],
|
||||
{ type: 'or' }
|
||||
) ? (
|
||||
<Link href={`/users/${user.id}/requests`}>
|
||||
<a className="text-sm leading-5 transition duration-300 hover:underline">
|
||||
{user.requestCount}
|
||||
</a>
|
||||
<Link
|
||||
href={`/users/${user.id}/requests`}
|
||||
className="text-sm leading-5 transition duration-300 hover:underline"
|
||||
>
|
||||
{user.requestCount}
|
||||
</Link>
|
||||
) : (
|
||||
user.requestCount
|
||||
|
||||
@@ -57,10 +57,9 @@ const ProfileHeader = ({ user, isSettingsPage }: ProfileHeaderProps) => {
|
||||
href={
|
||||
user.id === loggedInUser?.id ? '/profile' : `/users/${user.id}`
|
||||
}
|
||||
className="text-overseerr text-lg font-bold hover:to-purple-200 sm:text-2xl"
|
||||
>
|
||||
<a className="text-overseerr text-lg font-bold hover:to-purple-200 sm:text-2xl">
|
||||
{user.displayName}
|
||||
</a>
|
||||
{user.displayName}
|
||||
</Link>
|
||||
{user.email && user.displayName.toLowerCase() !== user.email && (
|
||||
<span className="text-sm text-gray-400 sm:ml-2 sm:text-lg">
|
||||
@@ -88,6 +87,7 @@ const ProfileHeader = ({ user, isSettingsPage }: ProfileHeaderProps) => {
|
||||
: `/users/${user.id}/settings`
|
||||
}
|
||||
passHref
|
||||
legacyBehavior
|
||||
>
|
||||
<Button as="a">
|
||||
<CogIcon />
|
||||
@@ -101,6 +101,7 @@ const ProfileHeader = ({ user, isSettingsPage }: ProfileHeaderProps) => {
|
||||
loggedInUser?.id === user.id ? `/profile` : `/users/${user.id}`
|
||||
}
|
||||
passHref
|
||||
legacyBehavior
|
||||
>
|
||||
<Button as="a">
|
||||
<UserIcon />
|
||||
|
||||
@@ -164,7 +164,7 @@ const UserProfile = () => {
|
||||
: `/users/${user?.id}/requests?filter=all`
|
||||
}
|
||||
>
|
||||
<a>{intl.formatNumber(user.requestCount)}</a>
|
||||
{intl.formatNumber(user.requestCount)}
|
||||
</Link>
|
||||
</dd>
|
||||
</div>
|
||||
@@ -296,11 +296,10 @@ const UserProfile = () => {
|
||||
? '/profile/requests?filter=all'
|
||||
: `/users/${user?.id}/requests?filter=all`
|
||||
}
|
||||
className="slider-title"
|
||||
>
|
||||
<a className="slider-title">
|
||||
<span>{intl.formatMessage(messages.recentrequests)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</a>
|
||||
<span>{intl.formatMessage(messages.recentrequests)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</Link>
|
||||
</div>
|
||||
<Slider
|
||||
@@ -336,11 +335,10 @@ const UserProfile = () => {
|
||||
? '/profile/watchlist'
|
||||
: `/users/${user.id}/watchlist`
|
||||
}
|
||||
className="slider-title"
|
||||
>
|
||||
<a className="slider-title">
|
||||
<span>{watchlistSliderTitle}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</a>
|
||||
<span>{watchlistSliderTitle}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
</Link>
|
||||
</div>
|
||||
<Slider
|
||||
|
||||
Reference in New Issue
Block a user