Allow middle click to open new tab
This commit is contained in:
parent
c2c434eb80
commit
82c605086b
|
@ -24,5 +24,14 @@ module.exports = {
|
|||
hreflang: "ja",
|
||||
},
|
||||
],
|
||||
exclude: ["/en/*", "/fr/*", "/ja/*", "/es/*", "/pt-br/*", "/404", "/500", "/dev/*"],
|
||||
exclude: [
|
||||
"/en/*",
|
||||
"/fr/*",
|
||||
"/ja/*",
|
||||
"/es/*",
|
||||
"/pt-br/*",
|
||||
"/404",
|
||||
"/500",
|
||||
"/dev/*",
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#9c6644" />
|
||||
<meta name="apple-mobile-web-app-title" content="Accord's Library" />
|
||||
<meta name="application-name" content="Accord's Library" />
|
||||
<meta name="msapplication-TileColor" content="#feecd6" />
|
||||
<meta name="msapplication-TileImage" content="/mstile-144x144.png" />
|
||||
<meta name="theme-color" content="#feecd6" />
|
|
@ -1,4 +1,4 @@
|
|||
import Link from "next/link";
|
||||
import { Link } from "components/Inputs/Link";
|
||||
import { DatePickerFragment } from "graphql/generated";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
|
||||
|
@ -20,17 +20,14 @@ export const ChroniclePreview = ({
|
|||
title,
|
||||
isActive,
|
||||
}: Props): JSX.Element => (
|
||||
<Link href={url}>
|
||||
<div
|
||||
<Link
|
||||
href={url}
|
||||
className={cJoin(
|
||||
`flex w-full cursor-pointer gap-4 rounded-2xl py-4 px-5
|
||||
text-left align-top outline outline-2 outline-offset-[-2px] outline-mid transition-all
|
||||
hover:bg-mid hover:shadow-inner-sm hover:shadow-shade
|
||||
hover:outline-[transparent] hover:active:shadow-inner hover:active:shadow-shade`,
|
||||
cIf(
|
||||
isActive,
|
||||
"bg-mid shadow-inner-sm shadow-shade outline-[transparent]"
|
||||
)
|
||||
cIf(isActive, "bg-mid shadow-inner-sm shadow-shade outline-[transparent]")
|
||||
)}
|
||||
>
|
||||
<div className="text-right">
|
||||
|
@ -40,7 +37,6 @@ export const ChroniclePreview = ({
|
|||
</p>
|
||||
</div>
|
||||
<p className="text-lg leading-tight">{title}</p>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useRouter } from "next/router";
|
||||
import React, { MouseEventHandler } from "react";
|
||||
import { Link } from "./Link";
|
||||
import { Ico, Icon } from "components/Ico";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
import { ConditionalWrapper, Wrapper } from "helpers/component";
|
||||
|
@ -17,8 +17,7 @@ interface Props {
|
|||
active?: boolean;
|
||||
icon?: Icon;
|
||||
text?: string | null | undefined;
|
||||
locale?: string;
|
||||
target?: "_blank";
|
||||
alwaysNewTab?: boolean;
|
||||
onClick?: MouseEventHandler<HTMLDivElement>;
|
||||
draggable?: boolean;
|
||||
badgeNumber?: number;
|
||||
|
@ -35,30 +34,17 @@ export const Button = ({
|
|||
className,
|
||||
icon,
|
||||
text,
|
||||
target,
|
||||
href,
|
||||
locale,
|
||||
alwaysNewTab = false,
|
||||
badgeNumber,
|
||||
size = "normal",
|
||||
}: Props): JSX.Element => {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
}: Props): JSX.Element => (
|
||||
<ConditionalWrapper
|
||||
isWrapping={isDefined(target)}
|
||||
wrapperProps={{ href: href }}
|
||||
isWrapping={isDefinedAndNotEmpty(href)}
|
||||
wrapperProps={{ href: href ?? "", alwaysNewTab }}
|
||||
wrapper={LinkWrapper}
|
||||
>
|
||||
<div
|
||||
className="relative"
|
||||
onClick={() => {
|
||||
if (!isDefined(target) && (isDefined(href) || isDefined(locale))) {
|
||||
router.push(href ?? router.asPath, href, {
|
||||
locale: locale,
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="relative">
|
||||
<div
|
||||
draggable={draggable}
|
||||
id={id}
|
||||
|
@ -98,7 +84,6 @@ export const Button = ({
|
|||
</div>
|
||||
</ConditionalWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
/*
|
||||
* ╭──────────────────────╮
|
||||
|
@ -106,11 +91,16 @@ export const Button = ({
|
|||
*/
|
||||
|
||||
interface LinkWrapperProps {
|
||||
href?: string;
|
||||
href: string;
|
||||
alwaysNewTab: boolean;
|
||||
}
|
||||
|
||||
const LinkWrapper = ({ children, href }: LinkWrapperProps & Wrapper) => (
|
||||
<a href={href} target="_blank" rel="noreferrer">
|
||||
const LinkWrapper = ({
|
||||
children,
|
||||
alwaysNewTab,
|
||||
href,
|
||||
}: LinkWrapperProps & Wrapper) => (
|
||||
<Link href={href} alwaysNewTab={alwaysNewTab}>
|
||||
{children}
|
||||
</a>
|
||||
</Link>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import router from "next/router";
|
||||
import { MouseEventHandler, useState } from "react";
|
||||
import { isDefined } from "helpers/others";
|
||||
|
||||
interface Props {
|
||||
href: string;
|
||||
className?: string;
|
||||
allowNewTab?: boolean;
|
||||
alwaysNewTab?: boolean;
|
||||
children: React.ReactNode;
|
||||
onClick?: MouseEventHandler<HTMLDivElement>;
|
||||
}
|
||||
|
||||
export const Link = ({
|
||||
href,
|
||||
allowNewTab = true,
|
||||
alwaysNewTab = false,
|
||||
children,
|
||||
className,
|
||||
onClick,
|
||||
}: Props): JSX.Element => {
|
||||
const [isValidClick, setIsValidClick] = useState(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
onMouseLeave={() => setIsValidClick(false)}
|
||||
onContextMenu={(event) => event.preventDefault()}
|
||||
onMouseDown={(event) => {
|
||||
event.preventDefault();
|
||||
setIsValidClick(true);
|
||||
}}
|
||||
onMouseUp={(event) => {
|
||||
if (isDefined(onClick)) {
|
||||
onClick(event);
|
||||
} else if (isValidClick && href) {
|
||||
if (event.button !== MouseButton.Right) {
|
||||
if (alwaysNewTab) {
|
||||
window.open(href, "_blank");
|
||||
} else if (event.button === MouseButton.Left) {
|
||||
if (href.startsWith("#")) {
|
||||
router.replace(href);
|
||||
} else {
|
||||
router.push(href);
|
||||
}
|
||||
} else if (allowNewTab) {
|
||||
window.open(href, "_blank");
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
enum MouseButton {
|
||||
Left = 0,
|
||||
Middle = 1,
|
||||
Right = 2,
|
||||
}
|
|
@ -4,6 +4,7 @@ import { Ico, Icon } from "components/Ico";
|
|||
import { ToolTip } from "components/ToolTip";
|
||||
import { cJoin, cIf } from "helpers/className";
|
||||
import { isDefinedAndNotEmpty } from "helpers/others";
|
||||
import { Link } from "components/Inputs/Link";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -51,17 +52,9 @@ export const NavOption = ({
|
|||
className="text-left"
|
||||
disabled={!reduced}
|
||||
>
|
||||
<div
|
||||
onClick={(event) => {
|
||||
if (onClick) onClick(event);
|
||||
if (url) {
|
||||
if (url.startsWith("#")) {
|
||||
router.replace(url);
|
||||
} else {
|
||||
router.push(url);
|
||||
}
|
||||
}
|
||||
}}
|
||||
<Link
|
||||
href={url}
|
||||
onClick={onClick}
|
||||
className={cJoin(
|
||||
`relative grid w-full cursor-pointer auto-cols-fr grid-flow-col grid-cols-[auto]
|
||||
justify-center gap-x-5 rounded-2xl p-4 transition-all hover:bg-mid hover:shadow-inner-sm
|
||||
|
@ -84,7 +77,7 @@ export const NavOption = ({
|
|||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Link>
|
||||
</ToolTip>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import Markdown from "markdown-to-jsx";
|
||||
import Link from "next/link";
|
||||
import { HorizontalLine } from "components/HorizontalLine";
|
||||
import { Button } from "components/Inputs/Button";
|
||||
import { NavOption } from "components/PanelComponents/NavOption";
|
||||
|
@ -11,6 +10,7 @@ import { useMediaDesktop } from "hooks/useMediaQuery";
|
|||
import { Icon } from "components/Ico";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
import { isDefinedAndNotEmpty } from "helpers/others";
|
||||
import { Link } from "components/Inputs/Link";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -54,7 +54,7 @@ export const MainPanel = ({ langui }: Props): JSX.Element => {
|
|||
|
||||
<div>
|
||||
<div className="grid place-items-center">
|
||||
<Link href="/" passHref>
|
||||
<Link href="/" className="flex w-full justify-center">
|
||||
<div
|
||||
className={cJoin(
|
||||
`mb-4 aspect-square cursor-pointer bg-black transition-colors
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Dispatch, SetStateAction, useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import Hotkeys from "react-hot-keys";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import Link from "next/link";
|
||||
import { useMemo } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import { Chip } from "./Chip";
|
||||
import { Ico, Icon } from "./Ico";
|
||||
import { Img } from "./Img";
|
||||
import { Link } from "./Inputs/Link";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import {
|
||||
DatePickerFragment,
|
||||
|
@ -131,8 +131,8 @@ export const PreviewCard = ({
|
|||
);
|
||||
|
||||
return (
|
||||
<Link href={href} passHref>
|
||||
<div
|
||||
<Link
|
||||
href={href}
|
||||
className="group grid cursor-pointer items-end text-left transition-transform
|
||||
drop-shadow-shade-xl hover:scale-[1.02]"
|
||||
>
|
||||
|
@ -293,7 +293,6 @@ export const PreviewCard = ({
|
|||
|
||||
{infoAppend}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Link from "next/link";
|
||||
import { Chip } from "./Chip";
|
||||
import { Img } from "./Img";
|
||||
import { Link } from "./Inputs/Link";
|
||||
import { UploadImageFragment } from "graphql/generated";
|
||||
import { ImageQuality } from "helpers/img";
|
||||
|
||||
|
@ -32,8 +32,8 @@ export const PreviewLine = ({
|
|||
bottomChips,
|
||||
thumbnailAspectRatio,
|
||||
}: Props): JSX.Element => (
|
||||
<Link href={href} passHref>
|
||||
<div
|
||||
<Link
|
||||
href={href}
|
||||
className="flex h-36 w-full cursor-pointer flex-row place-items-center gap-4 overflow-hidden
|
||||
rounded-md bg-light pr-4 transition-transform drop-shadow-shade-xl hover:scale-[1.02]"
|
||||
>
|
||||
|
@ -59,9 +59,7 @@ export const PreviewLine = ({
|
|||
<div className="my-1 flex flex-col">
|
||||
{pre_title && <p className="mb-1 leading-none">{pre_title}</p>}
|
||||
{title && (
|
||||
<p className="font-headers text-lg font-bold leading-none">
|
||||
{title}
|
||||
</p>
|
||||
<p className="font-headers text-lg font-bold leading-none">{title}</p>
|
||||
)}
|
||||
{subtitle && <p className="leading-none">{subtitle}</p>}
|
||||
</div>
|
||||
|
@ -73,6 +71,5 @@ export const PreviewLine = ({
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { useCallback } from "react";
|
||||
import Link from "next/link";
|
||||
import { Chip } from "components/Chip";
|
||||
import { ToolTip } from "components/ToolTip";
|
||||
import { AppStaticProps } from "graphql/getAppStaticProps";
|
||||
|
@ -87,12 +86,10 @@ const DefinitionCard = ({
|
|||
<p>{selectedTranslation?.definition}</p>
|
||||
|
||||
{source?.url && source.name && (
|
||||
<Link href={source.url}>
|
||||
<div className="mt-3 flex place-items-center gap-2 mobile:flex-col mobile:text-center">
|
||||
<p>{langui.source}: </p>
|
||||
<Button size="small" text={source.name} />
|
||||
<Button href={source.url} size="small" text={source.name} />
|
||||
</div>
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -53,15 +53,15 @@ const CheckupContents = ({ contents, ...otherProps }: Props): JSX.Element => {
|
|||
>
|
||||
<Button
|
||||
href={line.frontendUrl}
|
||||
target="_blank"
|
||||
className="w-4 text-xs"
|
||||
text="F"
|
||||
alwaysNewTab
|
||||
/>
|
||||
<Button
|
||||
href={line.backendUrl}
|
||||
target="_blank"
|
||||
className="w-4 text-xs"
|
||||
text="B"
|
||||
alwaysNewTab
|
||||
/>
|
||||
<p>{line.subitems.join(" -> ")}</p>
|
||||
<p>{line.name}</p>
|
||||
|
|
|
@ -58,15 +58,15 @@ const CheckupLibraryItems = ({
|
|||
>
|
||||
<Button
|
||||
href={line.frontendUrl}
|
||||
target="_blank"
|
||||
className="w-4 text-xs"
|
||||
text="F"
|
||||
alwaysNewTab
|
||||
/>
|
||||
<Button
|
||||
href={line.backendUrl}
|
||||
target="_blank"
|
||||
className="w-4 text-xs"
|
||||
text="B"
|
||||
alwaysNewTab
|
||||
/>
|
||||
<p>{line.subitems.join(" -> ")}</p>
|
||||
<p>{line.name}</p>
|
||||
|
|
|
@ -230,8 +230,8 @@ const LibrarySlug = ({
|
|||
<Fragment key={index}>
|
||||
<Button
|
||||
href={url.url}
|
||||
target={"_blank"}
|
||||
text={prettyURL(url.url)}
|
||||
alwaysNewTab
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue