Use Next/Link
This commit is contained in:
parent
35fdc7af14
commit
6abff354ee
|
@ -1,8 +1,7 @@
|
||||||
import React, { MouseEventHandler, useCallback } from "react";
|
import { MouseEventHandler, useCallback } from "react";
|
||||||
import { Link } from "./Link";
|
import { Link } from "./Link";
|
||||||
import { Ico, Icon } from "components/Ico";
|
import { Ico, Icon } from "components/Ico";
|
||||||
import { cIf, cJoin } from "helpers/className";
|
import { cIf, cJoin } from "helpers/className";
|
||||||
import { ConditionalWrapper, Wrapper } from "helpers/component";
|
|
||||||
import { isDefined, isDefinedAndNotEmpty } from "helpers/others";
|
import { isDefined, isDefinedAndNotEmpty } from "helpers/others";
|
||||||
import { TranslatedProps } from "types/TranslatedProps";
|
import { TranslatedProps } from "types/TranslatedProps";
|
||||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||||
|
@ -45,10 +44,7 @@ export const Button = ({
|
||||||
disabled,
|
disabled,
|
||||||
size = "normal",
|
size = "normal",
|
||||||
}: Props): JSX.Element => (
|
}: Props): JSX.Element => (
|
||||||
<ConditionalWrapper
|
<Link href={href} alwaysNewTab={alwaysNewTab} disabled={disabled}>
|
||||||
isWrapping={isDefinedAndNotEmpty(href) && !disabled}
|
|
||||||
wrapperProps={{ href: href ?? "", alwaysNewTab }}
|
|
||||||
wrapper={LinkWrapper}>
|
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div
|
<div
|
||||||
draggable={draggable}
|
draggable={draggable}
|
||||||
|
@ -90,7 +86,7 @@ export const Button = ({
|
||||||
{isDefinedAndNotEmpty(text) && <p className="-translate-y-[0.05em] text-center">{text}</p>}
|
{isDefinedAndNotEmpty(text) && <p className="-translate-y-[0.05em] text-center">{text}</p>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ConditionalWrapper>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -110,19 +106,3 @@ export const TranslatedButton = ({
|
||||||
|
|
||||||
return <Button text={selectedTranslation?.text ?? fallback.text} {...otherProps} />;
|
return <Button text={selectedTranslation?.text ?? fallback.text} {...otherProps} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* ╭──────────────────────╮
|
|
||||||
* ───────────────────────────────────╯ PRIVATE COMPONENTS ╰──────────────────────────────────────
|
|
||||||
*/
|
|
||||||
|
|
||||||
interface LinkWrapperProps {
|
|
||||||
href: string;
|
|
||||||
alwaysNewTab: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LinkWrapper = ({ children, alwaysNewTab, href }: LinkWrapperProps & Wrapper) => (
|
|
||||||
<Link href={href} alwaysNewTab={alwaysNewTab}>
|
|
||||||
{children}
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
|
|
|
@ -1,74 +1,81 @@
|
||||||
import router from "next/router";
|
import React, { MouseEventHandler } from "react";
|
||||||
import { MouseEventHandler, useState } from "react";
|
import NextLink from "next/link";
|
||||||
import { isDefined } from "helpers/others";
|
import { ConditionalWrapper, Wrapper } from "helpers/component";
|
||||||
|
import { isDefinedAndNotEmpty } from "helpers/others";
|
||||||
|
import { cIf, cJoin } from "helpers/className";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
href: string;
|
href: string | null | undefined;
|
||||||
className?: string;
|
className?: string;
|
||||||
allowNewTab?: boolean;
|
|
||||||
alwaysNewTab?: boolean;
|
alwaysNewTab?: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
onClick?: MouseEventHandler<HTMLDivElement>;
|
onClick?: MouseEventHandler<HTMLDivElement>;
|
||||||
onFocusChanged?: (isFocused: boolean) => void;
|
onFocusChanged?: (isFocused: boolean) => void;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
linkStyled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Link = ({
|
export const Link = ({
|
||||||
href,
|
href,
|
||||||
allowNewTab = true,
|
|
||||||
alwaysNewTab = false,
|
|
||||||
disabled = false,
|
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
onClick,
|
alwaysNewTab,
|
||||||
|
disabled,
|
||||||
|
linkStyled = false,
|
||||||
onFocusChanged,
|
onFocusChanged,
|
||||||
}: Props): JSX.Element => {
|
}: Props): JSX.Element => (
|
||||||
const [isValidClick, setIsValidClick] = useState(false);
|
<ConditionalWrapper
|
||||||
|
isWrapping={isDefinedAndNotEmpty(href) && !disabled}
|
||||||
return (
|
wrapperProps={{
|
||||||
<div
|
href: href ?? "",
|
||||||
className={className}
|
alwaysNewTab,
|
||||||
onMouseLeave={() => {
|
onFocusChanged,
|
||||||
setIsValidClick(false);
|
className: cJoin(
|
||||||
onFocusChanged?.(false);
|
cIf(
|
||||||
|
linkStyled,
|
||||||
|
`underline decoration-dark decoration-dotted underline-offset-2 transition-colors
|
||||||
|
hover:text-dark`
|
||||||
|
),
|
||||||
|
className
|
||||||
|
),
|
||||||
}}
|
}}
|
||||||
onContextMenu={(event) => event.preventDefault()}
|
wrapper={LinkWrapper}
|
||||||
onMouseDown={(event) => {
|
wrapperFalse={DisabledWrapper}
|
||||||
if (!disabled) {
|
wrapperFalseProps={{ className }}>
|
||||||
event.preventDefault();
|
|
||||||
onFocusChanged?.(true);
|
|
||||||
setIsValidClick(true);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onMouseUp={(event) => {
|
|
||||||
onFocusChanged?.(false);
|
|
||||||
if (!disabled) {
|
|
||||||
if (isDefined(onClick)) {
|
|
||||||
onClick(event);
|
|
||||||
} else if (isValidClick && href) {
|
|
||||||
if (event.button !== MouseButton.Right) {
|
|
||||||
if (alwaysNewTab) {
|
|
||||||
window.open(href, "_blank", "noopener");
|
|
||||||
} else if (event.button === MouseButton.Left) {
|
|
||||||
if (href.startsWith("#")) {
|
|
||||||
router.replace(href);
|
|
||||||
} else {
|
|
||||||
router.push(href);
|
|
||||||
}
|
|
||||||
} else if (allowNewTab) {
|
|
||||||
window.open(href, "_blank");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</ConditionalWrapper>
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
enum MouseButton {
|
interface LinkWrapperProps {
|
||||||
Left = 0,
|
href: string;
|
||||||
Middle = 1,
|
className?: string;
|
||||||
Right = 2,
|
alwaysNewTab?: boolean;
|
||||||
|
onFocusChanged?: (isFocused: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LinkWrapper = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
onFocusChanged,
|
||||||
|
alwaysNewTab = false,
|
||||||
|
href,
|
||||||
|
}: LinkWrapperProps & Wrapper) => (
|
||||||
|
<NextLink
|
||||||
|
href={href}
|
||||||
|
className={className}
|
||||||
|
target={alwaysNewTab ? "_blank" : "_self"}
|
||||||
|
replace={href.startsWith("#")}
|
||||||
|
onMouseLeave={() => onFocusChanged?.(false)}
|
||||||
|
onMouseDown={() => onFocusChanged?.(true)}
|
||||||
|
onMouseUp={() => onFocusChanged?.(false)}>
|
||||||
|
{children}
|
||||||
|
</NextLink>
|
||||||
|
);
|
||||||
|
|
||||||
|
interface DisabledWrapperProps {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DisabledWrapper = ({ children, className }: DisabledWrapperProps & Wrapper) => (
|
||||||
|
<div className={className}>{children}</div>
|
||||||
|
);
|
||||||
|
|
|
@ -34,8 +34,8 @@ export const PreviewCardCTAs = ({ id, expand = false }: Props): JSX.Element => {
|
||||||
icon={Icon.Favorite}
|
icon={Icon.Favorite}
|
||||||
text={expand ? langui.want_it : undefined}
|
text={expand ? langui.want_it : undefined}
|
||||||
active={libraryItemUserStatus[id] === LibraryItemUserStatus.Want}
|
active={libraryItemUserStatus[id] === LibraryItemUserStatus.Want}
|
||||||
onMouseUp={(event) => event.stopPropagation()}
|
onClick={(event) => {
|
||||||
onClick={() => {
|
event.preventDefault();
|
||||||
setLibraryItemUserStatus((current) => {
|
setLibraryItemUserStatus((current) => {
|
||||||
const newLibraryItemUserStatus = { ...current };
|
const newLibraryItemUserStatus = { ...current };
|
||||||
newLibraryItemUserStatus[id] =
|
newLibraryItemUserStatus[id] =
|
||||||
|
@ -52,8 +52,8 @@ export const PreviewCardCTAs = ({ id, expand = false }: Props): JSX.Element => {
|
||||||
icon={Icon.BackHand}
|
icon={Icon.BackHand}
|
||||||
text={expand ? langui.have_it : undefined}
|
text={expand ? langui.have_it : undefined}
|
||||||
active={libraryItemUserStatus[id] === LibraryItemUserStatus.Have}
|
active={libraryItemUserStatus[id] === LibraryItemUserStatus.Have}
|
||||||
onMouseUp={(event) => event.stopPropagation()}
|
onClick={(event) => {
|
||||||
onClick={() => {
|
event.preventDefault();
|
||||||
setLibraryItemUserStatus((current) => {
|
setLibraryItemUserStatus((current) => {
|
||||||
const newLibraryItemUserStatus = { ...current };
|
const newLibraryItemUserStatus = { ...current };
|
||||||
newLibraryItemUserStatus[id] =
|
newLibraryItemUserStatus[id] =
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import Markdown from "markdown-to-jsx";
|
import Markdown from "markdown-to-jsx";
|
||||||
import { useRouter } from "next/router";
|
import React, { Fragment, useMemo } from "react";
|
||||||
import React, { Fragment } from "react";
|
|
||||||
import ReactDOMServer from "react-dom/server";
|
import ReactDOMServer from "react-dom/server";
|
||||||
import { HorizontalLine } from "components/HorizontalLine";
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
import { Img } from "components/Img";
|
import { Img } from "components/Img";
|
||||||
|
@ -15,6 +14,7 @@ import { Ico, Icon } from "components/Ico";
|
||||||
import { useDeviceSupportsHover } from "hooks/useMediaQuery";
|
import { useDeviceSupportsHover } from "hooks/useMediaQuery";
|
||||||
import { atoms } from "contexts/atoms";
|
import { atoms } from "contexts/atoms";
|
||||||
import { useAtomGetter } from "helpers/atoms";
|
import { useAtomGetter } from "helpers/atoms";
|
||||||
|
import { Link } from "components/Inputs/Link";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ╭─────────────╮
|
* ╭─────────────╮
|
||||||
|
@ -30,7 +30,6 @@ interface MarkdawnProps {
|
||||||
|
|
||||||
export const Markdawn = ({ className, text: rawText }: MarkdawnProps): JSX.Element => {
|
export const Markdawn = ({ className, text: rawText }: MarkdawnProps): JSX.Element => {
|
||||||
const playerName = useAtomGetter(atoms.settings.playerName);
|
const playerName = useAtomGetter(atoms.settings.playerName);
|
||||||
const router = useRouter();
|
|
||||||
const isContentPanelAtLeastLg = useAtomGetter(atoms.containerQueries.isContentPanelAtLeastLg);
|
const isContentPanelAtLeastLg = useAtomGetter(atoms.containerQueries.isContentPanelAtLeastLg);
|
||||||
const { showLightBox } = useAtomGetter(atoms.lightBox);
|
const { showLightBox } = useAtomGetter(atoms.lightBox);
|
||||||
|
|
||||||
|
@ -53,13 +52,15 @@ export const Markdawn = ({ className, text: rawText }: MarkdawnProps): JSX.Eleme
|
||||||
component: (compProps: { href: string; children: React.ReactNode }) => {
|
component: (compProps: { href: string; children: React.ReactNode }) => {
|
||||||
if (compProps.href.startsWith("/") || compProps.href.startsWith("#")) {
|
if (compProps.href.startsWith("/") || compProps.href.startsWith("#")) {
|
||||||
return (
|
return (
|
||||||
<a onClick={async () => router.push(compProps.href)}>{compProps.children}</a>
|
<Link href={compProps.href} linkStyled>
|
||||||
|
{compProps.children}
|
||||||
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<a href={compProps.href} target="_blank" rel="noreferrer">
|
<Link href={compProps.href} alwaysNewTab linkStyled>
|
||||||
{compProps.children}
|
{compProps.children}
|
||||||
</a>
|
</Link>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -95,9 +96,9 @@ export const Markdawn = ({ className, text: rawText }: MarkdawnProps): JSX.Eleme
|
||||||
? slugify(compProps.target)
|
? slugify(compProps.target)
|
||||||
: slugify(compProps.children?.toString());
|
: slugify(compProps.children?.toString());
|
||||||
return (
|
return (
|
||||||
<a onClick={async () => router.replace(`${compProps.page ?? ""}#${slug}`)}>
|
<Link href={`${compProps.page ?? ""}#${slug}`} linkStyled>
|
||||||
{compProps.children}
|
{compProps.children}
|
||||||
</a>
|
</Link>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -224,7 +225,6 @@ export const TableOfContents = ({
|
||||||
title,
|
title,
|
||||||
horizontalLine = false,
|
horizontalLine = false,
|
||||||
}: TableOfContentsProps): JSX.Element => {
|
}: TableOfContentsProps): JSX.Element => {
|
||||||
const router = useRouter();
|
|
||||||
const langui = useAtomGetter(atoms.localData.langui);
|
const langui = useAtomGetter(atoms.localData.langui);
|
||||||
const toc = getTocFromMarkdawn(preprocessMarkDawn(text), title);
|
const toc = getTocFromMarkdawn(preprocessMarkDawn(text), title);
|
||||||
|
|
||||||
|
@ -238,9 +238,9 @@ export const TableOfContents = ({
|
||||||
<p
|
<p
|
||||||
className="relative my-2 overflow-x-hidden text-ellipsis whitespace-nowrap
|
className="relative my-2 overflow-x-hidden text-ellipsis whitespace-nowrap
|
||||||
text-left">
|
text-left">
|
||||||
<a onClick={async () => router.replace(`#${toc.slug}`)}>
|
<Link href={`#${toc.slug}`} linkStyled>
|
||||||
{<abbr title={toc.title}>{toc.title}</abbr>}
|
{<abbr title={toc.title}>{toc.title}</abbr>}
|
||||||
</a>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
<TocLevel tocchildren={toc.children} parentNumbering="" />
|
<TocLevel tocchildren={toc.children} parentNumbering="" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -340,8 +340,7 @@ const TocLevel = ({
|
||||||
parentNumbering,
|
parentNumbering,
|
||||||
allowIntersection = true,
|
allowIntersection = true,
|
||||||
}: LevelProps): JSX.Element => {
|
}: LevelProps): JSX.Element => {
|
||||||
const router = useRouter();
|
const ids = useMemo(() => tocchildren.map((child) => child.slug), [tocchildren]);
|
||||||
const ids = tocchildren.map((child) => child.slug);
|
|
||||||
const currentIntersection = useIntersectionList(ids);
|
const currentIntersection = useIntersectionList(ids);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -354,9 +353,9 @@ const TocLevel = ({
|
||||||
cIf(allowIntersection && currentIntersection === childIndex, "text-dark")
|
cIf(allowIntersection && currentIntersection === childIndex, "text-dark")
|
||||||
)}>
|
)}>
|
||||||
<span className="text-dark">{`${parentNumbering}${childIndex + 1}.`}</span>{" "}
|
<span className="text-dark">{`${parentNumbering}${childIndex + 1}.`}</span>{" "}
|
||||||
<a onClick={async () => router.replace(`#${child.slug}`)}>
|
<Link href={`#${child.slug}`} linkStyled>
|
||||||
{<abbr title={child.title}>{child.title}</abbr>}
|
{<abbr title={child.title}>{child.title}</abbr>}
|
||||||
</a>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
<TocLevel
|
<TocLevel
|
||||||
tocchildren={child.children}
|
tocchildren={child.children}
|
||||||
|
|
|
@ -170,11 +170,12 @@ export const MainPanel = (): JSX.Element => {
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<div className="mt-4 mb-8 grid place-content-center">
|
<div className="mt-4 mb-8 grid place-content-center">
|
||||||
<a
|
<Link
|
||||||
onClick={() => sendAnalytics("MainPanel", "Visit license")}
|
onClick={() => sendAnalytics("MainPanel", "Visit license")}
|
||||||
aria-label="Read more about the license we use for this website"
|
aria-label="Read more about the license we use for this website"
|
||||||
className="group grid grid-flow-col place-content-center gap-1 transition-filter"
|
className="group grid grid-flow-col place-content-center gap-1 transition-filter"
|
||||||
href="https://creativecommons.org/licenses/by-sa/4.0/">
|
href="https://creativecommons.org/licenses/by-sa/4.0/"
|
||||||
|
alwaysNewTab>
|
||||||
<ColoredSvg
|
<ColoredSvg
|
||||||
className="h-6 w-6 bg-black group-hover:bg-dark"
|
className="h-6 w-6 bg-black group-hover:bg-dark"
|
||||||
src="/icons/creative-commons-brands.svg"
|
src="/icons/creative-commons-brands.svg"
|
||||||
|
@ -187,7 +188,7 @@ export const MainPanel = (): JSX.Element => {
|
||||||
className="h-6 w-6 bg-black group-hover:bg-dark"
|
className="h-6 w-6 bg-black group-hover:bg-dark"
|
||||||
src="/icons/creative-commons-sa-brands.svg"
|
src="/icons/creative-commons-sa-brands.svg"
|
||||||
/>
|
/>
|
||||||
</a>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
{isDefinedAndNotEmpty(langui.copyright_notice) && (
|
{isDefinedAndNotEmpty(langui.copyright_notice) && (
|
||||||
<p>
|
<p>
|
||||||
|
@ -195,39 +196,36 @@ export const MainPanel = (): JSX.Element => {
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<div className="mt-12 mb-4 grid h-4 grid-flow-col place-content-center gap-8">
|
<div className="mt-12 mb-4 grid h-4 grid-flow-col place-content-center gap-8">
|
||||||
<a
|
<Link
|
||||||
aria-label="Browse our GitHub repository, which include this website source code"
|
aria-label="Browse our GitHub repository, which include this website source code"
|
||||||
onClick={() => sendAnalytics("MainPanel", "Visit GitHub")}
|
onClick={() => sendAnalytics("MainPanel", "Visit GitHub")}
|
||||||
href="https://github.com/Accords-Library"
|
href="https://github.com/Accords-Library"
|
||||||
target="_blank"
|
alwaysNewTab>
|
||||||
rel="noopener noreferrer">
|
|
||||||
<ColoredSvg
|
<ColoredSvg
|
||||||
className="h-10 w-10 bg-black hover:bg-dark"
|
className="h-10 w-10 bg-black hover:bg-dark"
|
||||||
src="/icons/github-brands.svg"
|
src="/icons/github-brands.svg"
|
||||||
/>
|
/>
|
||||||
</a>
|
</Link>
|
||||||
<a
|
<Link
|
||||||
aria-label="Follow us on Twitter"
|
aria-label="Follow us on Twitter"
|
||||||
onClick={() => sendAnalytics("MainPanel", "Visit Twitter")}
|
onClick={() => sendAnalytics("MainPanel", "Visit Twitter")}
|
||||||
href="https://twitter.com/AccordsLibrary"
|
href="https://twitter.com/AccordsLibrary"
|
||||||
target="_blank"
|
alwaysNewTab>
|
||||||
rel="noopener noreferrer">
|
|
||||||
<ColoredSvg
|
<ColoredSvg
|
||||||
className="h-10 w-10 bg-black hover:bg-dark"
|
className="h-10 w-10 bg-black hover:bg-dark"
|
||||||
src="/icons/twitter-brands.svg"
|
src="/icons/twitter-brands.svg"
|
||||||
/>
|
/>
|
||||||
</a>
|
</Link>
|
||||||
<a
|
<Link
|
||||||
aria-label="Join our Discord server!"
|
aria-label="Join our Discord server!"
|
||||||
onClick={() => sendAnalytics("MainPanel", "Visit Discord")}
|
onClick={() => sendAnalytics("MainPanel", "Visit Discord")}
|
||||||
href="/discord"
|
href="/discord"
|
||||||
target="_blank"
|
alwaysNewTab>
|
||||||
rel="noopener noreferrer">
|
|
||||||
<ColoredSvg
|
<ColoredSvg
|
||||||
className="h-10 w-10 bg-black hover:bg-dark"
|
className="h-10 w-10 bg-black hover:bg-dark"
|
||||||
src="/icons/discord-brands.svg"
|
src="/icons/discord-brands.svg"
|
||||||
/>
|
/>
|
||||||
</a>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -73,7 +73,7 @@ export const SmartList = <T,>({
|
||||||
const [page, setPage] = useState(0);
|
const [page, setPage] = useState(0);
|
||||||
const langui = useAtomGetter(atoms.localData.langui);
|
const langui = useAtomGetter(atoms.localData.langui);
|
||||||
useScrollTopOnChange(Ids.ContentPanel, [page], paginationScroolTop);
|
useScrollTopOnChange(Ids.ContentPanel, [page], paginationScroolTop);
|
||||||
useEffect(() => setPage(0), [searchingTerm, groupingFunction, groupSortingFunction, items]);
|
useEffect(() => setPage(0), [searchingTerm, groupingFunction, groupSortingFunction]);
|
||||||
|
|
||||||
const searchFilter = useCallback(() => {
|
const searchFilter = useCallback(() => {
|
||||||
if (isDefinedAndNotEmpty(searchingTerm) && isDefined(searchingBy)) {
|
if (isDefinedAndNotEmpty(searchingTerm) && isDefined(searchingBy)) {
|
||||||
|
|
|
@ -1,18 +1,30 @@
|
||||||
|
import { isDefined } from "./others";
|
||||||
|
|
||||||
export interface Wrapper {
|
export interface Wrapper {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConditionalWrapperProps<T> {
|
interface ConditionalWrapperProps<T, U> {
|
||||||
isWrapping: boolean;
|
isWrapping: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
wrapper: (wrapperProps: T & Wrapper) => JSX.Element;
|
wrapper: (wrapperProps: T & Wrapper) => JSX.Element;
|
||||||
wrapperProps: T;
|
wrapperProps: T;
|
||||||
|
wrapperFalse?: (wrapperProps: U & Wrapper) => JSX.Element;
|
||||||
|
wrapperFalseProps?: U;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ConditionalWrapper = <T,>({
|
export const ConditionalWrapper = <T, U>({
|
||||||
isWrapping,
|
isWrapping,
|
||||||
children,
|
children,
|
||||||
wrapper: Wrapper,
|
wrapper: Wrapper,
|
||||||
|
wrapperFalse: WrapperFalse,
|
||||||
wrapperProps,
|
wrapperProps,
|
||||||
}: ConditionalWrapperProps<T>): JSX.Element =>
|
wrapperFalseProps,
|
||||||
isWrapping ? <Wrapper {...wrapperProps}>{children}</Wrapper> : <>{children}</>;
|
}: ConditionalWrapperProps<T, U>): JSX.Element =>
|
||||||
|
isWrapping ? (
|
||||||
|
<Wrapper {...wrapperProps}>{children}</Wrapper>
|
||||||
|
) : isDefined(WrapperFalse) && isDefined(wrapperFalseProps) ? (
|
||||||
|
<WrapperFalse {...wrapperFalseProps}>{children}</WrapperFalse>
|
||||||
|
) : (
|
||||||
|
<>{children}</>
|
||||||
|
);
|
||||||
|
|
|
@ -36,10 +36,9 @@ const AccordsLibraryApp = (props: AppProps): JSX.Element => {
|
||||||
<SettingsPopup />
|
<SettingsPopup />
|
||||||
<LightBoxProvider />
|
<LightBoxProvider />
|
||||||
<Script
|
<Script
|
||||||
async
|
|
||||||
defer
|
|
||||||
data-website-id={process.env.NEXT_PUBLIC_UMAMI_ID}
|
data-website-id={process.env.NEXT_PUBLIC_UMAMI_ID}
|
||||||
src={`${process.env.NEXT_PUBLIC_UMAMI_URL}/umami.js`}
|
src={`${process.env.NEXT_PUBLIC_UMAMI_URL}/umami.js`}
|
||||||
|
strategy="lazyOnload"
|
||||||
/>
|
/>
|
||||||
<props.Component {...props.pageProps} />
|
<props.Component {...props.pageProps} />
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { getLangui } from "graphql/fetchLocalData";
|
import { getLangui } from "graphql/fetchLocalData";
|
||||||
import { atoms } from "contexts/atoms";
|
import { atoms } from "contexts/atoms";
|
||||||
import { useAtomGetter } from "helpers/atoms";
|
import { useAtomGetter } from "helpers/atoms";
|
||||||
|
import { Link } from "components/Inputs/Link";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ╭────────╮
|
* ╭────────╮
|
||||||
|
@ -95,9 +96,9 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => {
|
||||||
: prettyShortenNumber(video.likes)}
|
: prettyShortenNumber(video.likes)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<a href={`https://youtu.be/${video.uid}`} target="_blank" rel="noreferrer">
|
<Link href={`https://youtu.be/${video.uid}`} alwaysNewTab>
|
||||||
<Button className="!py-0 !px-3" text={`${langui.view_on} ${video.source}`} />
|
<Button size="small" text={`${langui.view_on} ${video.source}`} />
|
||||||
</a>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -53,6 +53,7 @@ import { getLangui } from "graphql/fetchLocalData";
|
||||||
import { Ids } from "types/ids";
|
import { Ids } from "types/ids";
|
||||||
import { atoms } from "contexts/atoms";
|
import { atoms } from "contexts/atoms";
|
||||||
import { useAtomGetter } from "helpers/atoms";
|
import { useAtomGetter } from "helpers/atoms";
|
||||||
|
import { Link } from "components/Inputs/Link";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ╭─────────────╮
|
* ╭─────────────╮
|
||||||
|
@ -713,7 +714,7 @@ const ContentLine = ({
|
||||||
cIf(isOpened, "my-2 h-auto bg-mid py-3 shadow-inner-sm shadow-shade")
|
cIf(isOpened, "my-2 h-auto bg-mid py-3 shadow-inner-sm shadow-shade")
|
||||||
)}>
|
)}>
|
||||||
<div className="grid grid-cols-[auto_auto_1fr_auto_12ch] place-items-center gap-4">
|
<div className="grid grid-cols-[auto_auto_1fr_auto_12ch] place-items-center gap-4">
|
||||||
<a>
|
<Link href={""} linkStyled>
|
||||||
<h3 className="cursor-pointer" onClick={toggleOpened}>
|
<h3 className="cursor-pointer" onClick={toggleOpened}>
|
||||||
{selectedTranslation
|
{selectedTranslation
|
||||||
? prettyInlineTitle(
|
? prettyInlineTitle(
|
||||||
|
@ -725,7 +726,7 @@ const ContentLine = ({
|
||||||
? prettySlug(content.slug, parentSlug)
|
? prettySlug(content.slug, parentSlug)
|
||||||
: prettySlug(slug, parentSlug)}
|
: prettySlug(slug, parentSlug)}
|
||||||
</h3>
|
</h3>
|
||||||
</a>
|
</Link>
|
||||||
<div className="flex flex-row flex-wrap gap-1">
|
<div className="flex flex-row flex-wrap gap-1">
|
||||||
{content?.categories?.map((category, index) => (
|
{content?.categories?.map((category, index) => (
|
||||||
<Chip key={index} text={category} />
|
<Chip key={index} text={category} />
|
||||||
|
|
|
@ -19,11 +19,6 @@ h6 {
|
||||||
@apply font-headers font-black;
|
@apply font-headers font-black;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
|
||||||
@apply cursor-pointer underline decoration-dark decoration-dotted
|
|
||||||
underline-offset-2 transition-colors hover:text-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
*::selection {
|
*::selection {
|
||||||
@apply bg-dark text-light;
|
@apply bg-dark text-light;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue