refactor: update Next.js and React.js

This commit is contained in:
Gauthier
2024-06-14 00:42:51 +02:00
parent 38ad875dd7
commit 9ab5fa5972
52 changed files with 1927 additions and 1000 deletions

View File

@@ -63,7 +63,7 @@
"gravatar-url": "3.1.0",
"intl": "1.2.5",
"lodash": "4.17.21",
"next": "12.3.4",
"next": "^14.2.4",
"node-cache": "5.1.2",
"node-gyp": "9.3.1",
"node-schedule": "2.1.1",
@@ -71,11 +71,11 @@
"openpgp": "5.7.0",
"plex-api": "5.3.2",
"pug": "3.0.2",
"react": "18.2.0",
"react": "^18.3.1",
"react-ace": "10.1.0",
"react-animate-height": "2.1.2",
"react-aria": "3.23.0",
"react-dom": "18.2.0",
"react-dom": "^18.3.1",
"react-intersection-observer": "9.4.3",
"react-intl": "6.2.10",
"react-markdown": "8.0.5",
@@ -123,8 +123,8 @@
"@types/node": "17.0.36",
"@types/node-schedule": "2.1.0",
"@types/nodemailer": "6.4.7",
"@types/react": "18.0.28",
"@types/react-dom": "18.0.11",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/react-transition-group": "4.4.5",
"@types/secure-random-password": "0.2.1",
"@types/semver": "7.3.13",
@@ -144,7 +144,7 @@
"cypress": "12.7.0",
"cz-conventional-changelog": "3.3.0",
"eslint": "8.35.0",
"eslint-config-next": "12.3.4",
"eslint-config-next": "^14.2.4",
"eslint-config-prettier": "8.6.0",
"eslint-plugin-formatjs": "4.9.0",
"eslint-plugin-jsx-a11y": "6.7.1",

View File

@@ -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) => (

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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>
);
};

View File

@@ -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>
);
};

View File

@@ -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>
) : (
''

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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>
);
};

View File

@@ -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>

View File

@@ -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: (

View File

@@ -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: (

View File

@@ -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>

View File

@@ -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 />

View File

@@ -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>
);
})}

View File

@@ -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>
);
})}

View File

@@ -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>
);
});

View File

@@ -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>
);
});

View File

@@ -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>
);
};

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>
);
};

View File

@@ -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">

View File

@@ -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>
}
>

View File

@@ -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>
}
>

View File

@@ -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>
}
>

View File

@@ -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>
}
>

View File

@@ -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

View File

@@ -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>
);
};

View File

@@ -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>

View File

@@ -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>
</>

View File

@@ -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>
),
})}

View File

@@ -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>
) : (
''

View File

@@ -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>
),
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -309,6 +309,7 @@ const NotificationsWebhook = () => {
<Link
href="https://docs.overseerr.dev/using-overseerr/notifications/webhooks#template-variables"
passHref
legacyBehavior
>
<Button
as="a"

View File

@@ -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">

View File

@@ -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>
}
>

View File

@@ -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>
}
>

View File

@@ -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>
}
>

View File

@@ -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>
}
>

View File

@@ -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

View File

@@ -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

View File

@@ -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 />

View File

@@ -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

View File

@@ -21,11 +21,9 @@ const Custom404 = () => {
error: intl.formatMessage(messages.pagenotfound),
})}
</div>
<Link href="/">
<a className="mt-2 flex">
{intl.formatMessage(messages.returnHome)}
<ArrowRightCircleIcon className="ml-2 h-6 w-6" />
</a>
<Link href="/" className="mt-2 flex">
{intl.formatMessage(messages.returnHome)}
<ArrowRightCircleIcon className="ml-2 h-6 w-6" />
</Link>
</div>
);

View File

@@ -44,11 +44,9 @@ const Error: NextPage<ErrorProps> = ({ statusCode }) => {
})
: getErrorMessage(statusCode)}
</div>
<Link href="/">
<a className="mt-2 flex">
{intl.formatMessage(messages.returnHome)}
<ArrowRightCircleIcon className="ml-2 h-6 w-6" />
</a>
<Link href="/" className="mt-2 flex">
{intl.formatMessage(messages.returnHome)}
<ArrowRightCircleIcon className="ml-2 h-6 w-6" />
</Link>
</div>
);

1453
yarn.lock

File diff suppressed because it is too large Load Diff