fix: use links instead of buttons for external links in movie/tv details page (#923)
Previously, the "Play on Jellyfin" or "Watch Trailers" buttons used the onClick event and window.open to open links, instead of using 'a' elements with a href.
This commit is contained in:
@@ -2,7 +2,11 @@ import useClickOutside from '@app/hooks/useClickOutside';
|
|||||||
import { withProperties } from '@app/utils/typeHelpers';
|
import { withProperties } from '@app/utils/typeHelpers';
|
||||||
import { Transition } from '@headlessui/react';
|
import { Transition } from '@headlessui/react';
|
||||||
import { ChevronDownIcon } from '@heroicons/react/24/solid';
|
import { ChevronDownIcon } from '@heroicons/react/24/solid';
|
||||||
import type { AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react';
|
import type {
|
||||||
|
AnchorHTMLAttributes,
|
||||||
|
ButtonHTMLAttributes,
|
||||||
|
RefObject,
|
||||||
|
} from 'react';
|
||||||
import { Fragment, useRef, useState } from 'react';
|
import { Fragment, useRef, useState } from 'react';
|
||||||
|
|
||||||
interface DropdownItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
interface DropdownItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
||||||
@@ -35,23 +39,33 @@ const DropdownItem = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ButtonWithDropdownProps
|
interface ButtonWithDropdownProps {
|
||||||
extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
||||||
text: React.ReactNode;
|
text: React.ReactNode;
|
||||||
dropdownIcon?: React.ReactNode;
|
dropdownIcon?: React.ReactNode;
|
||||||
buttonType?: 'primary' | 'ghost';
|
buttonType?: 'primary' | 'ghost';
|
||||||
}
|
}
|
||||||
|
interface ButtonProps
|
||||||
|
extends ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
|
ButtonWithDropdownProps {
|
||||||
|
as?: 'button';
|
||||||
|
}
|
||||||
|
interface AnchorProps
|
||||||
|
extends AnchorHTMLAttributes<HTMLAnchorElement>,
|
||||||
|
ButtonWithDropdownProps {
|
||||||
|
as: 'a';
|
||||||
|
}
|
||||||
|
|
||||||
const ButtonWithDropdown = ({
|
const ButtonWithDropdown = ({
|
||||||
|
as,
|
||||||
text,
|
text,
|
||||||
children,
|
children,
|
||||||
dropdownIcon,
|
dropdownIcon,
|
||||||
className,
|
className,
|
||||||
buttonType = 'primary',
|
buttonType = 'primary',
|
||||||
...props
|
...props
|
||||||
}: ButtonWithDropdownProps) => {
|
}: ButtonProps | AnchorProps) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
const buttonRef = useRef<HTMLButtonElement | HTMLAnchorElement>(null);
|
||||||
useClickOutside(buttonRef, () => setIsOpen(false));
|
useClickOutside(buttonRef, () => setIsOpen(false));
|
||||||
|
|
||||||
const styleClasses = {
|
const styleClasses = {
|
||||||
@@ -78,16 +92,28 @@ const ButtonWithDropdown = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="relative inline-flex h-full rounded-md shadow-sm">
|
<span className="relative inline-flex h-full rounded-md shadow-sm">
|
||||||
<button
|
{as === 'a' ? (
|
||||||
type="button"
|
<a
|
||||||
className={`relative z-10 inline-flex h-full items-center px-4 py-2 text-sm font-medium leading-5 transition duration-150 ease-in-out hover:z-20 focus:z-20 focus:outline-none ${
|
className={`relative z-10 inline-flex h-full items-center px-4 py-2 text-sm font-medium leading-5 transition duration-150 ease-in-out hover:z-20 focus:z-20 focus:outline-none ${
|
||||||
styleClasses.mainButtonClasses
|
styleClasses.mainButtonClasses
|
||||||
} ${children ? 'rounded-l-md' : 'rounded-md'} ${className}`}
|
} ${children ? 'rounded-l-md' : 'rounded-md'} ${className}`}
|
||||||
ref={buttonRef}
|
ref={buttonRef as RefObject<HTMLAnchorElement>}
|
||||||
{...props}
|
{...(props as AnchorHTMLAttributes<HTMLAnchorElement>)}
|
||||||
>
|
>
|
||||||
{text}
|
{text}
|
||||||
</button>
|
</a>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`relative z-10 inline-flex h-full items-center px-4 py-2 text-sm font-medium leading-5 transition duration-150 ease-in-out hover:z-20 focus:z-20 focus:outline-none ${
|
||||||
|
styleClasses.mainButtonClasses
|
||||||
|
} ${children ? 'rounded-l-md' : 'rounded-md'} ${className}`}
|
||||||
|
ref={buttonRef as RefObject<HTMLButtonElement>}
|
||||||
|
{...(props as ButtonHTMLAttributes<HTMLButtonElement>)}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
{children && (
|
{children && (
|
||||||
<span className="relative -ml-px block">
|
<span className="relative -ml-px block">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const PlayButton = ({ links }: PlayButtonProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonWithDropdown
|
<ButtonWithDropdown
|
||||||
|
as="a"
|
||||||
buttonType="ghost"
|
buttonType="ghost"
|
||||||
text={
|
text={
|
||||||
<>
|
<>
|
||||||
@@ -24,19 +25,17 @@ const PlayButton = ({ links }: PlayButtonProps) => {
|
|||||||
<span>{links[0].text}</span>
|
<span>{links[0].text}</span>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
onClick={() => {
|
href={links[0].url}
|
||||||
window.open(links[0].url, '_blank');
|
target="_blank"
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{links.length > 1 &&
|
{links.length > 1 &&
|
||||||
links.slice(1).map((link, i) => {
|
links.slice(1).map((link, i) => {
|
||||||
return (
|
return (
|
||||||
<ButtonWithDropdown.Item
|
<ButtonWithDropdown.Item
|
||||||
key={`play-button-dropdown-item-${i}`}
|
key={`play-button-dropdown-item-${i}`}
|
||||||
onClick={() => {
|
|
||||||
window.open(link.url, '_blank');
|
|
||||||
}}
|
|
||||||
buttonType="ghost"
|
buttonType="ghost"
|
||||||
|
href={link.url}
|
||||||
|
target="_blank"
|
||||||
>
|
>
|
||||||
{link.svg}
|
{link.svg}
|
||||||
<span>{link.text}</span>
|
<span>{link.text}</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user