Continued using hooks
This commit is contained in:
parent
efcf01e8a0
commit
d0b91f9db6
|
@ -161,30 +161,30 @@ export function AppLayout(props: Props): JSX.Element {
|
||||||
}, [fontSize]);
|
}, [fontSize]);
|
||||||
|
|
||||||
const defaultPreferredLanguages = useMemo(() => {
|
const defaultPreferredLanguages = useMemo(() => {
|
||||||
let list: string[] = [];
|
let memo: string[] = [];
|
||||||
if (isDefinedAndNotEmpty(router.locale) && router.locales) {
|
if (isDefinedAndNotEmpty(router.locale) && router.locales) {
|
||||||
if (router.locale === "en") {
|
if (router.locale === "en") {
|
||||||
list = [router.locale];
|
memo = [router.locale];
|
||||||
router.locales.map((locale) => {
|
router.locales.map((locale) => {
|
||||||
if (locale !== router.locale) list.push(locale);
|
if (locale !== router.locale) memo.push(locale);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
list = [router.locale, "en"];
|
memo = [router.locale, "en"];
|
||||||
router.locales.map((locale) => {
|
router.locales.map((locale) => {
|
||||||
if (locale !== router.locale && locale !== "en") list.push(locale);
|
if (locale !== router.locale && locale !== "en") memo.push(locale);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
return memo;
|
||||||
}, [router.locale, router.locales]);
|
}, [router.locale, router.locales]);
|
||||||
|
|
||||||
const currencyOptions = useMemo(() => {
|
const currencyOptions = useMemo(() => {
|
||||||
const list: string[] = [];
|
const memo: string[] = [];
|
||||||
filterHasAttributes(currencies).map((currentCurrency) => {
|
filterHasAttributes(currencies).map((currentCurrency) => {
|
||||||
if (isDefinedAndNotEmpty(currentCurrency.attributes.code))
|
if (isDefinedAndNotEmpty(currentCurrency.attributes.code))
|
||||||
list.push(currentCurrency.attributes.code);
|
memo.push(currentCurrency.attributes.code);
|
||||||
});
|
});
|
||||||
return list;
|
return memo;
|
||||||
}, [currencies]);
|
}, [currencies]);
|
||||||
|
|
||||||
const [currencySelect, setCurrencySelect] = useState<number>(-1);
|
const [currencySelect, setCurrencySelect] = useState<number>(-1);
|
||||||
|
|
|
@ -157,12 +157,10 @@ export function ScanSet(props: Props): JSX.Element {
|
||||||
{filterHasAttributes(selectedScan.cleaners.data).map(
|
{filterHasAttributes(selectedScan.cleaners.data).map(
|
||||||
(cleaner) => (
|
(cleaner) => (
|
||||||
<Fragment key={cleaner.id}>
|
<Fragment key={cleaner.id}>
|
||||||
{cleaner.attributes && (
|
|
||||||
<RecorderChip
|
<RecorderChip
|
||||||
langui={langui}
|
langui={langui}
|
||||||
recorder={cleaner.attributes}
|
recorder={cleaner.attributes}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
@ -178,12 +176,10 @@ export function ScanSet(props: Props): JSX.Element {
|
||||||
{filterHasAttributes(selectedScan.typesetters.data).map(
|
{filterHasAttributes(selectedScan.typesetters.data).map(
|
||||||
(typesetter) => (
|
(typesetter) => (
|
||||||
<Fragment key={typesetter.id}>
|
<Fragment key={typesetter.id}>
|
||||||
{typesetter.attributes && (
|
|
||||||
<RecorderChip
|
<RecorderChip
|
||||||
langui={langui}
|
langui={langui}
|
||||||
recorder={typesetter.attributes}
|
recorder={typesetter.attributes}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
@ -218,9 +214,7 @@ export function ScanSet(props: Props): JSX.Element {
|
||||||
openLightBox(images, index);
|
openLightBox(images, index);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{page.attributes && (
|
|
||||||
<Img image={page.attributes} quality={ImageQuality.Small} />
|
<Img image={page.attributes} quality={ImageQuality.Small} />
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { getAssetURL, ImageQuality } from "helpers/img";
|
||||||
import { filterHasAttributes, getStatusDescription } from "helpers/others";
|
import { filterHasAttributes, getStatusDescription } from "helpers/others";
|
||||||
|
|
||||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||||
import { Fragment } from "react";
|
import { Fragment, useMemo } from "react";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
openLightBox: (images: string[], index?: number) => void;
|
openLightBox: (images: string[], index?: number) => void;
|
||||||
|
@ -35,19 +35,22 @@ export function ScanSetCover(props: Props): JSX.Element {
|
||||||
languageExtractor: (item) => item.language?.data?.attributes?.code,
|
languageExtractor: (item) => item.language?.data?.attributes?.code,
|
||||||
});
|
});
|
||||||
|
|
||||||
const coverImages: UploadImageFragment[] = [];
|
const coverImages = useMemo(() => {
|
||||||
|
const memo: UploadImageFragment[] = [];
|
||||||
if (selectedScan?.obi_belt?.full?.data?.attributes)
|
if (selectedScan?.obi_belt?.full?.data?.attributes)
|
||||||
coverImages.push(selectedScan.obi_belt.full.data.attributes);
|
memo.push(selectedScan.obi_belt.full.data.attributes);
|
||||||
if (selectedScan?.obi_belt?.inside_full?.data?.attributes)
|
if (selectedScan?.obi_belt?.inside_full?.data?.attributes)
|
||||||
coverImages.push(selectedScan.obi_belt.inside_full.data.attributes);
|
memo.push(selectedScan.obi_belt.inside_full.data.attributes);
|
||||||
if (selectedScan?.dust_jacket?.full?.data?.attributes)
|
if (selectedScan?.dust_jacket?.full?.data?.attributes)
|
||||||
coverImages.push(selectedScan.dust_jacket.full.data.attributes);
|
memo.push(selectedScan.dust_jacket.full.data.attributes);
|
||||||
if (selectedScan?.dust_jacket?.inside_full?.data?.attributes)
|
if (selectedScan?.dust_jacket?.inside_full?.data?.attributes)
|
||||||
coverImages.push(selectedScan.dust_jacket.inside_full.data.attributes);
|
memo.push(selectedScan.dust_jacket.inside_full.data.attributes);
|
||||||
if (selectedScan?.cover?.full?.data?.attributes)
|
if (selectedScan?.cover?.full?.data?.attributes)
|
||||||
coverImages.push(selectedScan.cover.full.data.attributes);
|
memo.push(selectedScan.cover.full.data.attributes);
|
||||||
if (selectedScan?.cover?.inside_full?.data?.attributes)
|
if (selectedScan?.cover?.inside_full?.data?.attributes)
|
||||||
coverImages.push(selectedScan.cover.inside_full.data.attributes);
|
memo.push(selectedScan.cover.inside_full.data.attributes);
|
||||||
|
return memo;
|
||||||
|
}, [selectedScan]);
|
||||||
|
|
||||||
if (coverImages.length > 0) {
|
if (coverImages.length > 0) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -67,7 +67,8 @@ export function PostPage(props: Props): JSX.Element {
|
||||||
[post.slug, post.thumbnail, selectedTranslation]
|
[post.slug, post.thumbnail, selectedTranslation]
|
||||||
);
|
);
|
||||||
|
|
||||||
const subPanel =
|
const subPanel = useMemo(
|
||||||
|
() =>
|
||||||
returnHref || returnTitle || displayCredits || displayToc ? (
|
returnHref || returnTitle || displayCredits || displayToc ? (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
{returnHref && returnTitle && (
|
{returnHref && returnTitle && (
|
||||||
|
@ -120,9 +121,22 @@ export function PostPage(props: Props): JSX.Element {
|
||||||
|
|
||||||
{displayToc && <TOC text={body} title={title} />}
|
{displayToc && <TOC text={body} title={title} />}
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
) : undefined;
|
) : undefined,
|
||||||
|
[
|
||||||
|
body,
|
||||||
|
displayCredits,
|
||||||
|
displayToc,
|
||||||
|
langui,
|
||||||
|
post.authors,
|
||||||
|
returnHref,
|
||||||
|
returnTitle,
|
||||||
|
selectedTranslation,
|
||||||
|
title,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel>
|
<ContentPanel>
|
||||||
{returnHref && returnTitle && (
|
{returnHref && returnTitle && (
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
|
@ -166,6 +180,23 @@ export function PostPage(props: Props): JSX.Element {
|
||||||
<Markdawn text={body} />
|
<Markdawn text={body} />
|
||||||
{appendBody}
|
{appendBody}
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
LanguageSwitcher,
|
||||||
|
appendBody,
|
||||||
|
body,
|
||||||
|
displayLanguageSwitcher,
|
||||||
|
displayThumbnailHeader,
|
||||||
|
displayTitle,
|
||||||
|
excerpt,
|
||||||
|
langui,
|
||||||
|
post.categories,
|
||||||
|
prependBody,
|
||||||
|
returnHref,
|
||||||
|
returnTitle,
|
||||||
|
thumbnail,
|
||||||
|
title,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -85,7 +85,6 @@ export function ChronologyItemComponent(props: Props): JSX.Element {
|
||||||
{translation.description && (
|
{translation.description && (
|
||||||
<p
|
<p
|
||||||
className={
|
className={
|
||||||
event.translations &&
|
|
||||||
event.translations.length > 1
|
event.translations.length > 1
|
||||||
? `mt-2 whitespace-pre-line before:ml-[-1em] before:inline-block
|
? `mt-2 whitespace-pre-line before:ml-[-1em] before:inline-block
|
||||||
before:w-4 before:text-dark before:content-['-']`
|
before:w-4 before:text-dark before:content-['-']`
|
||||||
|
|
|
@ -208,7 +208,7 @@ export function sortBy(
|
||||||
orderByType: number,
|
orderByType: number,
|
||||||
items: Items,
|
items: Items,
|
||||||
currencies: AppStaticProps["currencies"]
|
currencies: AppStaticProps["currencies"]
|
||||||
): Items {
|
) {
|
||||||
switch (orderByType) {
|
switch (orderByType) {
|
||||||
case 0:
|
case 0:
|
||||||
return items.sort((a, b) => {
|
return items.sort((a, b) => {
|
||||||
|
|
|
@ -19,9 +19,7 @@ type SortContentProps =
|
||||||
>["contents"];
|
>["contents"];
|
||||||
|
|
||||||
export function sortContent(contents: SortContentProps) {
|
export function sortContent(contents: SortContentProps) {
|
||||||
if (contents) {
|
contents?.data.sort((a, b) => {
|
||||||
const newContent = { ...contents };
|
|
||||||
newContent?.data.sort((a, b) => {
|
|
||||||
if (
|
if (
|
||||||
a.attributes?.range[0]?.__typename === "ComponentRangePageRange" &&
|
a.attributes?.range[0]?.__typename === "ComponentRangePageRange" &&
|
||||||
b.attributes?.range[0]?.__typename === "ComponentRangePageRange"
|
b.attributes?.range[0]?.__typename === "ComponentRangePageRange"
|
||||||
|
@ -33,9 +31,6 @@ export function sortContent(contents: SortContentProps) {
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
return newContent;
|
|
||||||
}
|
|
||||||
return contents;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getStatusDescription(
|
export function getStatusDescription(
|
||||||
|
|
|
@ -38,12 +38,12 @@ export function useSmartLanguage<T>(
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const availableLocales = useMemo(() => {
|
const availableLocales = useMemo(() => {
|
||||||
const map = new Map<string, number>();
|
const memo = new Map<string, number>();
|
||||||
filterDefined(items).map((elem, index) => {
|
filterDefined(items).map((elem, index) => {
|
||||||
const result = languageExtractor(elem);
|
const result = languageExtractor(elem);
|
||||||
if (isDefined(result)) map.set(result, index);
|
if (isDefined(result)) memo.set(result, index);
|
||||||
});
|
});
|
||||||
return map;
|
return memo;
|
||||||
}, [items, languageExtractor]);
|
}, [items, languageExtractor]);
|
||||||
|
|
||||||
const [selectedTranslationIndex, setSelectedTranslationIndex] = useState<
|
const [selectedTranslationIndex, setSelectedTranslationIndex] = useState<
|
||||||
|
|
|
@ -7,12 +7,14 @@ import { ContentPanel } from "components/Panels/ContentPanel";
|
||||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||||
|
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {}
|
interface Props extends AppStaticProps {}
|
||||||
|
|
||||||
export default function FourOhFour(props: Props): JSX.Element {
|
export default function FourOhFour(props: Props): JSX.Element {
|
||||||
const { langui } = props;
|
const { langui } = props;
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel>
|
<ContentPanel>
|
||||||
<h1>404 - {langui.page_not_found}</h1>
|
<h1>404 - {langui.page_not_found}</h1>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
|
@ -22,6 +24,8 @@ export default function FourOhFour(props: Props): JSX.Element {
|
||||||
displayOn={ReturnButtonType.Both}
|
displayOn={ReturnButtonType.Both}
|
||||||
/>
|
/>
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[langui]
|
||||||
);
|
);
|
||||||
return <AppLayout navTitle="404" contentPanel={contentPanel} {...props} />;
|
return <AppLayout navTitle="404" contentPanel={contentPanel} {...props} />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,14 @@ import { ContentPanel } from "components/Panels/ContentPanel";
|
||||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||||
|
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {}
|
interface Props extends AppStaticProps {}
|
||||||
|
|
||||||
export default function FiveHundred(props: Props): JSX.Element {
|
export default function FiveHundred(props: Props): JSX.Element {
|
||||||
const { langui } = props;
|
const { langui } = props;
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel>
|
<ContentPanel>
|
||||||
<h1>500 - Internal Server Error</h1>
|
<h1>500 - Internal Server Error</h1>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
|
@ -22,6 +24,8 @@ export default function FiveHundred(props: Props): JSX.Element {
|
||||||
displayOn={ReturnButtonType.Both}
|
displayOn={ReturnButtonType.Both}
|
||||||
/>
|
/>
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[langui]
|
||||||
);
|
);
|
||||||
return <AppLayout navTitle="500" contentPanel={contentPanel} {...props} />;
|
return <AppLayout navTitle="500" contentPanel={contentPanel} {...props} />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,14 @@ import { SubPanel } from "components/Panels/SubPanel";
|
||||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||||
|
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {}
|
interface Props extends AppStaticProps {}
|
||||||
|
|
||||||
export default function AboutUs(props: Props): JSX.Element {
|
export default function AboutUs(props: Props): JSX.Element {
|
||||||
const { langui } = props;
|
const { langui } = props;
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<PanelHeader
|
<PanelHeader
|
||||||
icon={Icon.Info}
|
icon={Icon.Info}
|
||||||
|
@ -24,7 +26,6 @@ export default function AboutUs(props: Props): JSX.Element {
|
||||||
border
|
border
|
||||||
/>
|
/>
|
||||||
<NavOption title={langui.legality} url="/about-us/legality" border />
|
<NavOption title={langui.legality} url="/about-us/legality" border />
|
||||||
{/* <NavOption title={langui.members} url="/about-us/members" border /> */}
|
|
||||||
<NavOption
|
<NavOption
|
||||||
title={langui.sharing_policy}
|
title={langui.sharing_policy}
|
||||||
url="/about-us/sharing-policy"
|
url="/about-us/sharing-policy"
|
||||||
|
@ -32,6 +33,8 @@ export default function AboutUs(props: Props): JSX.Element {
|
||||||
/>
|
/>
|
||||||
<NavOption title={langui.contact_us} url="/about-us/contact" border />
|
<NavOption title={langui.contact_us} url="/about-us/contact" border />
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[langui]
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<AppLayout navTitle={langui.about_us} subPanel={subPanel} {...props} />
|
<AppLayout navTitle={langui.about_us} subPanel={subPanel} {...props} />
|
||||||
|
|
|
@ -6,12 +6,14 @@ import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||||
|
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {}
|
interface Props extends AppStaticProps {}
|
||||||
|
|
||||||
export default function Archives(props: Props): JSX.Element {
|
export default function Archives(props: Props): JSX.Element {
|
||||||
const { langui } = props;
|
const { langui } = props;
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<PanelHeader
|
<PanelHeader
|
||||||
icon={Icon.Inventory}
|
icon={Icon.Inventory}
|
||||||
|
@ -20,6 +22,8 @@ export default function Archives(props: Props): JSX.Element {
|
||||||
/>
|
/>
|
||||||
<NavOption title={"Videos"} url="/archives/videos/" border />
|
<NavOption title={"Videos"} url="/archives/videos/" border />
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[langui]
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<AppLayout navTitle={langui.archives} subPanel={subPanel} {...props} />
|
<AppLayout navTitle={langui.archives} subPanel={subPanel} {...props} />
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {
|
||||||
GetStaticPathsResult,
|
GetStaticPathsResult,
|
||||||
GetStaticPropsContext,
|
GetStaticPropsContext,
|
||||||
} from "next";
|
} from "next";
|
||||||
import { Fragment, useState } from "react";
|
import { Fragment, useState, useMemo } from "react";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
import { useMediaHoverable } from "hooks/useMediaQuery";
|
import { useMediaHoverable } from "hooks/useMediaQuery";
|
||||||
import { WithLabel } from "components/Inputs/WithLabel";
|
import { WithLabel } from "components/Inputs/WithLabel";
|
||||||
|
@ -37,7 +37,8 @@ export default function Channel(props: Props): JSX.Element {
|
||||||
const [keepInfoVisible, setKeepInfoVisible] = useState(true);
|
const [keepInfoVisible, setKeepInfoVisible] = useState(true);
|
||||||
const hoverable = useMediaHoverable();
|
const hoverable = useMediaHoverable();
|
||||||
|
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href="/archives/videos/"
|
href="/archives/videos/"
|
||||||
|
@ -62,9 +63,12 @@ export default function Channel(props: Props): JSX.Element {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[hoverable, keepInfoVisible, langui]
|
||||||
);
|
);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<h1 className="text-3xl">{channel?.title}</h1>
|
<h1 className="text-3xl">{channel?.title}</h1>
|
||||||
|
@ -97,7 +101,15 @@ export default function Channel(props: Props): JSX.Element {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
channel?.subscribers,
|
||||||
|
channel?.title,
|
||||||
|
channel?.videos?.data,
|
||||||
|
keepInfoVisible,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLayout
|
<AppLayout
|
||||||
navTitle={langui.archives}
|
navTitle={langui.archives}
|
||||||
|
|
|
@ -22,40 +22,33 @@ import { filterHasAttributes } from "helpers/others";
|
||||||
import { getVideoThumbnailURL } from "helpers/videos";
|
import { getVideoThumbnailURL } from "helpers/videos";
|
||||||
import { useMediaHoverable } from "hooks/useMediaQuery";
|
import { useMediaHoverable } from "hooks/useMediaQuery";
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
import { Fragment, useState } from "react";
|
import { Fragment, useMemo, useState } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {
|
interface Props extends AppStaticProps {
|
||||||
videos: NonNullable<GetVideosPreviewQuery["videos"]>["data"];
|
videos: NonNullable<GetVideosPreviewQuery["videos"]>["data"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ITEM_PER_PAGE = 50;
|
||||||
|
|
||||||
export default function Videos(props: Props): JSX.Element {
|
export default function Videos(props: Props): JSX.Element {
|
||||||
const { langui, videos } = props;
|
const { langui, videos } = props;
|
||||||
const hoverable = useMediaHoverable();
|
const hoverable = useMediaHoverable();
|
||||||
|
|
||||||
videos
|
const paginatedVideos = useMemo(() => {
|
||||||
.sort((a, b) => {
|
const memo = [];
|
||||||
const dateA = a.attributes?.published_date
|
for (let index = 0; ITEM_PER_PAGE * index < videos.length; index += 1) {
|
||||||
? prettyDate(a.attributes.published_date)
|
memo.push(
|
||||||
: "9999";
|
videos.slice(index * ITEM_PER_PAGE, (index + 1) * ITEM_PER_PAGE)
|
||||||
const dateB = b.attributes?.published_date
|
|
||||||
? prettyDate(b.attributes.published_date)
|
|
||||||
: "9999";
|
|
||||||
return dateA.localeCompare(dateB);
|
|
||||||
})
|
|
||||||
.reverse();
|
|
||||||
|
|
||||||
const itemPerPage = 50;
|
|
||||||
const paginatedVideos: Props["videos"][] = [];
|
|
||||||
for (let index = 0; itemPerPage * index < videos.length; index += 1) {
|
|
||||||
paginatedVideos.push(
|
|
||||||
videos.slice(index * itemPerPage, (index + 1) * itemPerPage)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return memo;
|
||||||
|
}, [videos]);
|
||||||
|
|
||||||
const [page, setPage] = useState(0);
|
const [page, setPage] = useState(0);
|
||||||
const [keepInfoVisible, setKeepInfoVisible] = useState(true);
|
const [keepInfoVisible, setKeepInfoVisible] = useState(true);
|
||||||
|
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href="/archives/"
|
href="/archives/"
|
||||||
|
@ -80,12 +73,15 @@ export default function Videos(props: Props): JSX.Element {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[hoverable, keepInfoVisible, langui]
|
||||||
);
|
);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
<PageSelector
|
<PageSelector
|
||||||
maxPage={Math.floor(videos.length / itemPerPage)}
|
maxPage={Math.floor(videos.length / ITEM_PER_PAGE)}
|
||||||
page={page}
|
page={page}
|
||||||
setPage={setPage}
|
setPage={setPage}
|
||||||
className="mb-12"
|
className="mb-12"
|
||||||
|
@ -120,12 +116,14 @@ export default function Videos(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PageSelector
|
<PageSelector
|
||||||
maxPage={Math.floor(videos.length / itemPerPage)}
|
maxPage={Math.floor(videos.length / ITEM_PER_PAGE)}
|
||||||
page={page}
|
page={page}
|
||||||
setPage={setPage}
|
setPage={setPage}
|
||||||
className="mt-12"
|
className="mt-12"
|
||||||
/>
|
/>
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[keepInfoVisible, page, paginatedVideos, videos.length]
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<AppLayout
|
<AppLayout
|
||||||
|
@ -143,6 +141,17 @@ export async function getStaticProps(
|
||||||
const sdk = getReadySdk();
|
const sdk = getReadySdk();
|
||||||
const videos = await sdk.getVideosPreview();
|
const videos = await sdk.getVideosPreview();
|
||||||
if (!videos.videos) return { notFound: true };
|
if (!videos.videos) return { notFound: true };
|
||||||
|
videos.videos.data
|
||||||
|
.sort((a, b) => {
|
||||||
|
const dateA = a.attributes?.published_date
|
||||||
|
? prettyDate(a.attributes.published_date)
|
||||||
|
: "9999";
|
||||||
|
const dateB = b.attributes?.published_date
|
||||||
|
? prettyDate(b.attributes.published_date)
|
||||||
|
: "9999";
|
||||||
|
return dateA.localeCompare(dateB);
|
||||||
|
})
|
||||||
|
.reverse();
|
||||||
const props: Props = {
|
const props: Props = {
|
||||||
...(await getAppStaticProps(context)),
|
...(await getAppStaticProps(context)),
|
||||||
videos: videos.videos.data,
|
videos: videos.videos.data,
|
||||||
|
|
|
@ -26,6 +26,7 @@ import {
|
||||||
GetStaticPathsResult,
|
GetStaticPathsResult,
|
||||||
GetStaticPropsContext,
|
GetStaticPropsContext,
|
||||||
} from "next";
|
} from "next";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {
|
interface Props extends AppStaticProps {
|
||||||
video: NonNullable<
|
video: NonNullable<
|
||||||
|
@ -37,7 +38,8 @@ export default function Video(props: Props): JSX.Element {
|
||||||
const { langui, video } = props;
|
const { langui, video } = props;
|
||||||
const isMobile = useMediaMobile();
|
const isMobile = useMediaMobile();
|
||||||
const appLayout = useAppLayout();
|
const appLayout = useAppLayout();
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href="/archives/videos/"
|
href="/archives/videos/"
|
||||||
|
@ -70,9 +72,12 @@ export default function Video(props: Props): JSX.Element {
|
||||||
onClick={() => appLayout.setSubPanelOpen(false)}
|
onClick={() => appLayout.setSubPanelOpen(false)}
|
||||||
/>
|
/>
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[appLayout, langui]
|
||||||
);
|
);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href="/library/"
|
href="/library/"
|
||||||
|
@ -175,7 +180,22 @@ export default function Video(props: Props): JSX.Element {
|
||||||
</InsetBox>
|
</InsetBox>
|
||||||
</div>
|
</div>
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
isMobile,
|
||||||
|
langui,
|
||||||
|
video.channel?.data?.attributes,
|
||||||
|
video.description,
|
||||||
|
video.gone,
|
||||||
|
video.likes,
|
||||||
|
video.published_date,
|
||||||
|
video.source,
|
||||||
|
video.title,
|
||||||
|
video.uid,
|
||||||
|
video.views,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLayout
|
<AppLayout
|
||||||
navTitle={langui.archives}
|
navTitle={langui.archives}
|
||||||
|
|
|
@ -5,12 +5,14 @@ import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||||
|
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {}
|
interface Props extends AppStaticProps {}
|
||||||
|
|
||||||
export default function Chronicles(props: Props): JSX.Element {
|
export default function Chronicles(props: Props): JSX.Element {
|
||||||
const { langui } = props;
|
const { langui } = props;
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<PanelHeader
|
<PanelHeader
|
||||||
icon={Icon.WatchLater}
|
icon={Icon.WatchLater}
|
||||||
|
@ -18,7 +20,10 @@ export default function Chronicles(props: Props): JSX.Element {
|
||||||
description={langui.chronicles_description}
|
description={langui.chronicles_description}
|
||||||
/>
|
/>
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[langui]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLayout navTitle={langui.chronicles} subPanel={subPanel} {...props} />
|
<AppLayout navTitle={langui.chronicles} subPanel={subPanel} {...props} />
|
||||||
);
|
);
|
||||||
|
|
|
@ -76,7 +76,8 @@ export default function Content(props: Props): JSX.Element {
|
||||||
[content.group, content.slug]
|
[content.group, content.slug]
|
||||||
);
|
);
|
||||||
|
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href={`/contents`}
|
href={`/contents`}
|
||||||
|
@ -96,7 +97,8 @@ export default function Content(props: Props): JSX.Element {
|
||||||
: langui.translation_notice}
|
: langui.translation_notice}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{selectedTranslation.text_set.source_language.data.attributes.code !==
|
{selectedTranslation.text_set.source_language.data.attributes
|
||||||
|
.code !==
|
||||||
selectedTranslation.language?.data?.attributes?.code && (
|
selectedTranslation.language?.data?.attributes?.code && (
|
||||||
<div className="grid place-items-center gap-2">
|
<div className="grid place-items-center gap-2">
|
||||||
<p className="font-headers">{langui.source_language}:</p>
|
<p className="font-headers">{langui.source_language}:</p>
|
||||||
|
@ -272,8 +274,18 @@ export default function Content(props: Props): JSX.Element {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
content.ranged_contents?.data,
|
||||||
|
currencies,
|
||||||
|
languages,
|
||||||
|
langui,
|
||||||
|
selectedTranslation,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
const contentPanel = (
|
|
||||||
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel>
|
<ContentPanel>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href={`/contents`}
|
href={`/contents`}
|
||||||
|
@ -313,7 +325,9 @@ export default function Content(props: Props): JSX.Element {
|
||||||
)}
|
)}
|
||||||
slug={previousContent.attributes.slug}
|
slug={previousContent.attributes.slug}
|
||||||
languages={languages}
|
languages={languages}
|
||||||
thumbnail={previousContent.attributes.thumbnail?.data?.attributes}
|
thumbnail={
|
||||||
|
previousContent.attributes.thumbnail?.data?.attributes
|
||||||
|
}
|
||||||
thumbnailAspectRatio="3/2"
|
thumbnailAspectRatio="3/2"
|
||||||
topChips={
|
topChips={
|
||||||
isMobile
|
isMobile
|
||||||
|
@ -325,7 +339,8 @@ export default function Content(props: Props): JSX.Element {
|
||||||
? previousContent.attributes.type.data.attributes
|
? previousContent.attributes.type.data.attributes
|
||||||
.titles[0]?.title
|
.titles[0]?.title
|
||||||
: prettySlug(
|
: prettySlug(
|
||||||
previousContent.attributes.type.data.attributes.slug
|
previousContent.attributes.type.data.attributes
|
||||||
|
.slug
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
: undefined
|
: undefined
|
||||||
|
@ -371,8 +386,8 @@ export default function Content(props: Props): JSX.Element {
|
||||||
: nextContent.attributes.type?.data?.attributes
|
: nextContent.attributes.type?.data?.attributes
|
||||||
? [
|
? [
|
||||||
nextContent.attributes.type.data.attributes.titles?.[0]
|
nextContent.attributes.type.data.attributes.titles?.[0]
|
||||||
? nextContent.attributes.type.data.attributes.titles[0]
|
? nextContent.attributes.type.data.attributes
|
||||||
?.title
|
.titles[0]?.title
|
||||||
: prettySlug(
|
: prettySlug(
|
||||||
nextContent.attributes.type.data.attributes.slug
|
nextContent.attributes.type.data.attributes.slug
|
||||||
),
|
),
|
||||||
|
@ -391,6 +406,19 @@ export default function Content(props: Props): JSX.Element {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
LanguageSwitcher,
|
||||||
|
content.categories,
|
||||||
|
content.thumbnail?.data?.attributes,
|
||||||
|
content.type,
|
||||||
|
isMobile,
|
||||||
|
languages,
|
||||||
|
langui,
|
||||||
|
nextContent?.attributes,
|
||||||
|
previousContent?.attributes,
|
||||||
|
selectedTranslation,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -71,7 +71,8 @@ export default function Contents(props: Props): JSX.Element {
|
||||||
[combineRelatedContent, searchName.length]
|
[combineRelatedContent, searchName.length]
|
||||||
);
|
);
|
||||||
|
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<PanelHeader
|
<PanelHeader
|
||||||
icon={Icon.Workspaces}
|
icon={Icon.Workspaces}
|
||||||
|
@ -131,8 +132,19 @@ export default function Contents(props: Props): JSX.Element {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
effectiveCombineRelatedContent,
|
||||||
|
groupingMethod,
|
||||||
|
hoverable,
|
||||||
|
keepInfoVisible,
|
||||||
|
langui,
|
||||||
|
searchName,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
const contentPanel = (
|
|
||||||
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
{/* TODO: Add to langui */}
|
{/* TODO: Add to langui */}
|
||||||
{groups.size === 0 && (
|
{groups.size === 0 && (
|
||||||
|
@ -162,8 +174,8 @@ export default function Contents(props: Props): JSX.Element {
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
currentSum +
|
currentSum +
|
||||||
(item.attributes.group.data.attributes.contents?.data
|
(item.attributes.group.data.attributes.contents
|
||||||
.length ?? 1)
|
?.data.length ?? 1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,16 +214,16 @@ export default function Contents(props: Props): JSX.Element {
|
||||||
effectiveCombineRelatedContent &&
|
effectiveCombineRelatedContent &&
|
||||||
item.attributes.group?.data?.attributes?.combine ===
|
item.attributes.group?.data?.attributes?.combine ===
|
||||||
true
|
true
|
||||||
? item.attributes.group.data.attributes.contents?.data
|
? item.attributes.group.data.attributes.contents
|
||||||
.length
|
?.data.length
|
||||||
: 0
|
: 0
|
||||||
}
|
}
|
||||||
topChips={
|
topChips={
|
||||||
item.attributes.type?.data?.attributes
|
item.attributes.type?.data?.attributes
|
||||||
? [
|
? [
|
||||||
item.attributes.type.data.attributes.titles?.[0]
|
item.attributes.type.data.attributes.titles?.[0]
|
||||||
? item.attributes.type.data.attributes.titles[0]
|
? item.attributes.type.data.attributes
|
||||||
?.title
|
.titles[0]?.title
|
||||||
: prettySlug(
|
: prettySlug(
|
||||||
item.attributes.type.data.attributes.slug
|
item.attributes.type.data.attributes.slug
|
||||||
),
|
),
|
||||||
|
@ -230,7 +242,17 @@ export default function Contents(props: Props): JSX.Element {
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
effectiveCombineRelatedContent,
|
||||||
|
groups,
|
||||||
|
keepInfoVisible,
|
||||||
|
languages,
|
||||||
|
langui.result,
|
||||||
|
langui.results,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLayout
|
<AppLayout
|
||||||
navTitle={langui.contents}
|
navTitle={langui.contents}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { getReadySdk } from "graphql/sdk";
|
||||||
import { filterDefined, filterHasAttributes } from "helpers/others";
|
import { filterDefined, filterHasAttributes } from "helpers/others";
|
||||||
|
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {
|
interface Props extends AppStaticProps {
|
||||||
contents: DevGetContentsQuery;
|
contents: DevGetContentsQuery;
|
||||||
|
@ -21,7 +22,8 @@ export default function CheckupContents(props: Props): JSX.Element {
|
||||||
const { contents } = props;
|
const { contents } = props;
|
||||||
const testReport = testingContent(contents);
|
const testReport = testingContent(contents);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
{<h2 className="text-2xl">{testReport.title}</h2>}
|
{<h2 className="text-2xl">{testReport.title}</h2>}
|
||||||
|
|
||||||
|
@ -75,7 +77,10 @@ export default function CheckupContents(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[testReport.lines, testReport.title]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLayout navTitle={"Checkup"} contentPanel={contentPanel} {...props} />
|
<AppLayout navTitle={"Checkup"} contentPanel={contentPanel} {...props} />
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
|
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {
|
interface Props extends AppStaticProps {
|
||||||
libraryItems: DevGetLibraryItemsQuery;
|
libraryItems: DevGetLibraryItemsQuery;
|
||||||
|
@ -23,7 +24,8 @@ export default function CheckupLibraryItems(props: Props): JSX.Element {
|
||||||
const { libraryItems } = props;
|
const { libraryItems } = props;
|
||||||
const testReport = testingLibraryItem(libraryItems);
|
const testReport = testingLibraryItem(libraryItems);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
{<h2 className="text-2xl">{testReport.title}</h2>}
|
{<h2 className="text-2xl">{testReport.title}</h2>}
|
||||||
|
|
||||||
|
@ -77,7 +79,10 @@ export default function CheckupLibraryItems(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[testReport.lines, testReport.title]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLayout navTitle={"Checkup"} contentPanel={contentPanel} {...props} />
|
<AppLayout navTitle={"Checkup"} contentPanel={contentPanel} {...props} />
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { ToolTip } from "components/ToolTip";
|
||||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||||
|
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useMemo, useState } from "react";
|
||||||
import TurndownService from "turndown";
|
import TurndownService from "turndown";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
import { TOC } from "components/Markdown/TOC";
|
import { TOC } from "components/Markdown/TOC";
|
||||||
|
@ -25,11 +25,42 @@ export default function Editor(props: Props): JSX.Element {
|
||||||
const [markdown, setMarkdown] = useState("");
|
const [markdown, setMarkdown] = useState("");
|
||||||
const [converterOpened, setConverterOpened] = useState(false);
|
const [converterOpened, setConverterOpened] = useState(false);
|
||||||
|
|
||||||
function wrap(
|
const transformationWrapper = useCallback(
|
||||||
|
(
|
||||||
|
transformation: (
|
||||||
|
value: string,
|
||||||
|
selectionStart: number,
|
||||||
|
selectedEnd: number
|
||||||
|
) => { prependLength: number; transformedValue: string }
|
||||||
|
) => {
|
||||||
|
const textarea =
|
||||||
|
document.querySelector<HTMLTextAreaElement>("#editorTextArea");
|
||||||
|
if (textarea) {
|
||||||
|
const { value, selectionStart, selectionEnd } = textarea;
|
||||||
|
|
||||||
|
const { prependLength, transformedValue } = transformation(
|
||||||
|
value,
|
||||||
|
selectionStart,
|
||||||
|
selectionEnd
|
||||||
|
);
|
||||||
|
|
||||||
|
textarea.value = transformedValue;
|
||||||
|
handleInput(textarea.value);
|
||||||
|
|
||||||
|
textarea.focus();
|
||||||
|
textarea.selectionStart = selectionStart + prependLength;
|
||||||
|
textarea.selectionEnd = selectionEnd + prependLength;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[handleInput]
|
||||||
|
);
|
||||||
|
|
||||||
|
const wrap = useCallback(
|
||||||
|
(
|
||||||
wrapper: string,
|
wrapper: string,
|
||||||
properties?: Record<string, string>,
|
properties?: Record<string, string>,
|
||||||
addInnerNewLines?: boolean
|
addInnerNewLines?: boolean
|
||||||
) {
|
) => {
|
||||||
transformationWrapper((value, selectionStart, selectionEnd) => {
|
transformationWrapper((value, selectionStart, selectionEnd) => {
|
||||||
let prepend = wrapper;
|
let prepend = wrapper;
|
||||||
let append = wrapper;
|
let append = wrapper;
|
||||||
|
@ -55,13 +86,29 @@ export default function Editor(props: Props): JSX.Element {
|
||||||
newValue += value.slice(selectionEnd);
|
newValue += value.slice(selectionEnd);
|
||||||
return { prependLength: prepend.length, transformedValue: newValue };
|
return { prependLength: prepend.length, transformedValue: newValue };
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
[transformationWrapper]
|
||||||
|
);
|
||||||
|
|
||||||
function toggleWrap(
|
const unwrap = useCallback(
|
||||||
|
(wrapper: string) => {
|
||||||
|
transformationWrapper((value, selectionStart, selectionEnd) => {
|
||||||
|
let newValue = "";
|
||||||
|
newValue += value.slice(0, selectionStart - wrapper.length);
|
||||||
|
newValue += value.slice(selectionStart, selectionEnd);
|
||||||
|
newValue += value.slice(wrapper.length + selectionEnd);
|
||||||
|
return { prependLength: -wrapper.length, transformedValue: newValue };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[transformationWrapper]
|
||||||
|
);
|
||||||
|
|
||||||
|
const toggleWrap = useCallback(
|
||||||
|
(
|
||||||
wrapper: string,
|
wrapper: string,
|
||||||
properties?: Record<string, string>,
|
properties?: Record<string, string>,
|
||||||
addInnerNewLines?: boolean
|
addInnerNewLines?: boolean
|
||||||
) {
|
) => {
|
||||||
const textarea =
|
const textarea =
|
||||||
document.querySelector<HTMLTextAreaElement>("#editorTextArea");
|
document.querySelector<HTMLTextAreaElement>("#editorTextArea");
|
||||||
if (textarea) {
|
if (textarea) {
|
||||||
|
@ -77,21 +124,15 @@ export default function Editor(props: Props): JSX.Element {
|
||||||
wrap(wrapper, properties, addInnerNewLines);
|
wrap(wrapper, properties, addInnerNewLines);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
[unwrap, wrap]
|
||||||
|
);
|
||||||
|
|
||||||
function unwrap(wrapper: string) {
|
const preline = useCallback(
|
||||||
transformationWrapper((value, selectionStart, selectionEnd) => {
|
(prepend: string) => {
|
||||||
let newValue = "";
|
|
||||||
newValue += value.slice(0, selectionStart - wrapper.length);
|
|
||||||
newValue += value.slice(selectionStart, selectionEnd);
|
|
||||||
newValue += value.slice(wrapper.length + selectionEnd);
|
|
||||||
return { prependLength: -wrapper.length, transformedValue: newValue };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function preline(prepend: string) {
|
|
||||||
transformationWrapper((value, selectionStart) => {
|
transformationWrapper((value, selectionStart) => {
|
||||||
const lastNewLine = value.slice(0, selectionStart).lastIndexOf("\n") + 1;
|
const lastNewLine =
|
||||||
|
value.slice(0, selectionStart).lastIndexOf("\n") + 1;
|
||||||
|
|
||||||
let newValue = "";
|
let newValue = "";
|
||||||
newValue += value.slice(0, lastNewLine);
|
newValue += value.slice(0, lastNewLine);
|
||||||
|
@ -100,9 +141,12 @@ export default function Editor(props: Props): JSX.Element {
|
||||||
|
|
||||||
return { prependLength: prepend.length, transformedValue: newValue };
|
return { prependLength: prepend.length, transformedValue: newValue };
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
[transformationWrapper]
|
||||||
|
);
|
||||||
|
|
||||||
function insert(prepend: string) {
|
const insert = useCallback(
|
||||||
|
(prepend: string) => {
|
||||||
transformationWrapper((value, selectionStart) => {
|
transformationWrapper((value, selectionStart) => {
|
||||||
let newValue = "";
|
let newValue = "";
|
||||||
newValue += value.slice(0, selectionStart);
|
newValue += value.slice(0, selectionStart);
|
||||||
|
@ -111,54 +155,33 @@ export default function Editor(props: Props): JSX.Element {
|
||||||
|
|
||||||
return { prependLength: prepend.length, transformedValue: newValue };
|
return { prependLength: prepend.length, transformedValue: newValue };
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
[transformationWrapper]
|
||||||
|
);
|
||||||
|
|
||||||
function appendDoc(append: string) {
|
const appendDoc = useCallback(
|
||||||
|
(append: string) => {
|
||||||
transformationWrapper((value) => {
|
transformationWrapper((value) => {
|
||||||
const newValue = value + append;
|
const newValue = value + append;
|
||||||
return { prependLength: 0, transformedValue: newValue };
|
return { prependLength: 0, transformedValue: newValue };
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
[transformationWrapper]
|
||||||
function transformationWrapper(
|
|
||||||
transformation: (
|
|
||||||
value: string,
|
|
||||||
selectionStart: number,
|
|
||||||
selectedEnd: number
|
|
||||||
) => { prependLength: number; transformedValue: string }
|
|
||||||
) {
|
|
||||||
const textarea =
|
|
||||||
document.querySelector<HTMLTextAreaElement>("#editorTextArea");
|
|
||||||
if (textarea) {
|
|
||||||
const { value, selectionStart, selectionEnd } = textarea;
|
|
||||||
|
|
||||||
const { prependLength, transformedValue } = transformation(
|
|
||||||
value,
|
|
||||||
selectionStart,
|
|
||||||
selectionEnd
|
|
||||||
);
|
);
|
||||||
|
|
||||||
textarea.value = transformedValue;
|
const contentPanel = useMemo(
|
||||||
handleInput(textarea.value);
|
() => (
|
||||||
|
|
||||||
textarea.focus();
|
|
||||||
textarea.selectionStart = selectionStart + prependLength;
|
|
||||||
textarea.selectionEnd = selectionEnd + prependLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const contentPanel = (
|
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
<Popup setState={setConverterOpened} state={converterOpened}>
|
<Popup setState={setConverterOpened} state={converterOpened}>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<h2 className="mt-4">Convert HTML to markdown</h2>
|
<h2 className="mt-4">Convert HTML to markdown</h2>
|
||||||
<p>
|
<p>
|
||||||
Copy and paste any HTML content (content from web pages) here.{" "}
|
Copy and paste any HTML content (content from web pages) here.
|
||||||
<br />
|
<br />
|
||||||
The text will immediatly be converted to valid Markdown.
|
The text will immediatly be converted to valid Markdown.
|
||||||
<br />
|
<br />
|
||||||
You can then copy the converted text and paste it anywhere you want
|
You can then copy the converted text and paste it anywhere you
|
||||||
in the editor
|
want in the editor
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<textarea
|
<textarea
|
||||||
|
@ -258,8 +281,8 @@ export default function Editor(props: Props): JSX.Element {
|
||||||
<>
|
<>
|
||||||
<h3 className="text-lg">Transcripts</h3>
|
<h3 className="text-lg">Transcripts</h3>
|
||||||
<p>
|
<p>
|
||||||
Use this to create dialogues and transcripts. Start by adding a
|
Use this to create dialogues and transcripts. Start by adding
|
||||||
container, then add transcript speech line within.
|
a container, then add transcript speech line within.
|
||||||
</p>
|
</p>
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<ToolTip
|
<ToolTip
|
||||||
|
@ -381,7 +404,9 @@ export default function Editor(props: Props): JSX.Element {
|
||||||
|
|
||||||
<ToolTip
|
<ToolTip
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
content={<h3 className="text-lg">Player’s name placeholder</h3>}
|
content={
|
||||||
|
<h3 className="text-lg">Player’s name placeholder</h3>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Button onClick={() => insert("<player>")} icon={Icon.Person} />
|
<Button onClick={() => insert("<player>")} icon={Icon.Person} />
|
||||||
</ToolTip>
|
</ToolTip>
|
||||||
|
@ -426,7 +451,19 @@ export default function Editor(props: Props): JSX.Element {
|
||||||
<TOC text={markdown} />
|
<TOC text={markdown} />
|
||||||
</div>
|
</div>
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
appendDoc,
|
||||||
|
converterOpened,
|
||||||
|
handleInput,
|
||||||
|
insert,
|
||||||
|
markdown,
|
||||||
|
preline,
|
||||||
|
toggleWrap,
|
||||||
|
wrap,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLayout
|
<AppLayout
|
||||||
navTitle="Markdawn Editor"
|
navTitle="Markdawn Editor"
|
||||||
|
|
|
@ -49,15 +49,17 @@ import {
|
||||||
GetStaticPathsResult,
|
GetStaticPathsResult,
|
||||||
GetStaticPropsContext,
|
GetStaticPropsContext,
|
||||||
} from "next";
|
} from "next";
|
||||||
import { Fragment, useState } from "react";
|
import { Fragment, useMemo, useState } from "react";
|
||||||
import { isUntangibleGroupItem } from "helpers/libraryItem";
|
import { isUntangibleGroupItem } from "helpers/libraryItem";
|
||||||
import { useMediaHoverable } from "hooks/useMediaQuery";
|
import { useMediaHoverable } from "hooks/useMediaQuery";
|
||||||
import { WithLabel } from "components/Inputs/WithLabel";
|
import { WithLabel } from "components/Inputs/WithLabel";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {
|
interface Props extends AppStaticProps {
|
||||||
item: NonNullable<
|
item: NonNullable<
|
||||||
|
NonNullable<
|
||||||
GetLibraryItemQuery["libraryItems"]
|
GetLibraryItemQuery["libraryItems"]
|
||||||
>["data"][number]["attributes"];
|
>["data"][number]["attributes"]
|
||||||
|
>;
|
||||||
itemId: NonNullable<
|
itemId: NonNullable<
|
||||||
GetLibraryItemQuery["libraryItems"]
|
GetLibraryItemQuery["libraryItems"]
|
||||||
>["data"][number]["id"];
|
>["data"][number]["id"];
|
||||||
|
@ -67,29 +69,29 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
const { item, itemId, langui, currencies } = props;
|
const { item, itemId, langui, currencies } = props;
|
||||||
const appLayout = useAppLayout();
|
const appLayout = useAppLayout();
|
||||||
const hoverable = useMediaHoverable();
|
const hoverable = useMediaHoverable();
|
||||||
|
|
||||||
useScrollTopOnChange(AnchorIds.ContentPanel, [item]);
|
|
||||||
|
|
||||||
const isVariantSet =
|
|
||||||
item?.metadata?.[0]?.__typename === "ComponentMetadataGroup" &&
|
|
||||||
item.metadata[0].subtype?.data?.attributes?.slug === "variant-set";
|
|
||||||
|
|
||||||
sortContent(item?.contents);
|
|
||||||
|
|
||||||
const [openLightBox, LightBox] = useLightBox();
|
const [openLightBox, LightBox] = useLightBox();
|
||||||
const [keepInfoVisible, setKeepInfoVisible] = useState(false);
|
const [keepInfoVisible, setKeepInfoVisible] = useState(false);
|
||||||
|
|
||||||
let displayOpenScans = false;
|
useScrollTopOnChange(AnchorIds.ContentPanel, [item]);
|
||||||
if (item?.contents?.data)
|
|
||||||
for (const content of item.contents.data) {
|
|
||||||
if (
|
|
||||||
content.attributes?.scan_set &&
|
|
||||||
content.attributes.scan_set.length > 0
|
|
||||||
)
|
|
||||||
displayOpenScans = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const subPanel = (
|
const isVariantSet = useMemo(
|
||||||
|
() =>
|
||||||
|
item.metadata?.[0]?.__typename === "ComponentMetadataGroup" &&
|
||||||
|
item.metadata[0].subtype?.data?.attributes?.slug === "variant-set",
|
||||||
|
[item.metadata]
|
||||||
|
);
|
||||||
|
|
||||||
|
const displayOpenScans = useMemo(
|
||||||
|
() =>
|
||||||
|
item.contents?.data.some(
|
||||||
|
(content) =>
|
||||||
|
content.attributes?.scan_set && content.attributes.scan_set.length > 0
|
||||||
|
),
|
||||||
|
[item.contents?.data]
|
||||||
|
);
|
||||||
|
|
||||||
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href="/library/"
|
href="/library/"
|
||||||
|
@ -102,13 +104,13 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
<div className="grid gap-4">
|
<div className="grid gap-4">
|
||||||
<NavOption title={langui.summary} url="#summary" border />
|
<NavOption title={langui.summary} url="#summary" border />
|
||||||
|
|
||||||
{item?.gallery && item.gallery.data.length > 0 && (
|
{item.gallery && item.gallery.data.length > 0 && (
|
||||||
<NavOption title={langui.gallery} url="#gallery" border />
|
<NavOption title={langui.gallery} url="#gallery" border />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<NavOption title={langui.details} url="#details" border />
|
<NavOption title={langui.details} url="#details" border />
|
||||||
|
|
||||||
{item?.subitems && item.subitems.data.length > 0 && (
|
{item.subitems && item.subitems.data.length > 0 && (
|
||||||
<NavOption
|
<NavOption
|
||||||
title={isVariantSet ? langui.variants : langui.subitems}
|
title={isVariantSet ? langui.variants : langui.subitems}
|
||||||
url={isVariantSet ? "#variants" : "#subitems"}
|
url={isVariantSet ? "#variants" : "#subitems"}
|
||||||
|
@ -116,14 +118,17 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{item?.contents && item.contents.data.length > 0 && (
|
{item.contents && item.contents.data.length > 0 && (
|
||||||
<NavOption title={langui.contents} url="#contents" border />
|
<NavOption title={langui.contents} url="#contents" border />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[isVariantSet, item.contents, item.gallery, item.subitems, langui]
|
||||||
);
|
);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
<LightBox />
|
<LightBox />
|
||||||
|
|
||||||
|
@ -139,7 +144,7 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
className="relative h-[50vh] w-full
|
className="relative h-[50vh] w-full
|
||||||
cursor-pointer drop-shadow-shade-xl desktop:mb-16 mobile:h-[60vh]"
|
cursor-pointer drop-shadow-shade-xl desktop:mb-16 mobile:h-[60vh]"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (item?.thumbnail?.data?.attributes) {
|
if (item.thumbnail?.data?.attributes) {
|
||||||
openLightBox([
|
openLightBox([
|
||||||
getAssetURL(
|
getAssetURL(
|
||||||
item.thumbnail.data.attributes.url,
|
item.thumbnail.data.attributes.url,
|
||||||
|
@ -149,7 +154,7 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item?.thumbnail?.data?.attributes ? (
|
{item.thumbnail?.data?.attributes ? (
|
||||||
<Img
|
<Img
|
||||||
image={item.thumbnail.data.attributes}
|
image={item.thumbnail.data.attributes}
|
||||||
quality={ImageQuality.Large}
|
quality={ImageQuality.Large}
|
||||||
|
@ -162,7 +167,7 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
|
|
||||||
<InsetBox id="summary" className="grid place-items-center">
|
<InsetBox id="summary" className="grid place-items-center">
|
||||||
<div className="grid w-[clamp(0px,100%,42rem)] place-items-center gap-8">
|
<div className="grid w-[clamp(0px,100%,42rem)] place-items-center gap-8">
|
||||||
{item?.subitem_of?.data[0]?.attributes && (
|
{item.subitem_of?.data[0]?.attributes && (
|
||||||
<div className="grid place-items-center">
|
<div className="grid place-items-center">
|
||||||
<p>{langui.subitem_of}</p>
|
<p>{langui.subitem_of}</p>
|
||||||
<Button
|
<Button
|
||||||
|
@ -176,23 +181,25 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="grid place-items-center text-center">
|
<div className="grid place-items-center text-center">
|
||||||
<h1 className="text-3xl">{item?.title}</h1>
|
<h1 className="text-3xl">{item.title}</h1>
|
||||||
{item && isDefinedAndNotEmpty(item.subtitle) && (
|
{isDefinedAndNotEmpty(item.subtitle) && (
|
||||||
<h2 className="text-2xl">{item.subtitle}</h2>
|
<h2 className="text-2xl">{item.subtitle}</h2>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PreviewCardCTAs
|
<PreviewCardCTAs
|
||||||
id={itemId}
|
id={itemId}
|
||||||
displayCTAs={!isUntangibleGroupItem(item?.metadata?.[0])}
|
displayCTAs={!isUntangibleGroupItem(item.metadata?.[0])}
|
||||||
langui={langui}
|
langui={langui}
|
||||||
expand
|
expand
|
||||||
/>
|
/>
|
||||||
{item?.descriptions?.[0] && (
|
{item.descriptions?.[0] && (
|
||||||
<p className="text-justify">{item.descriptions[0].description}</p>
|
<p className="text-justify">
|
||||||
|
{item.descriptions[0].description}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
{!(
|
{!(
|
||||||
item?.metadata &&
|
item.metadata &&
|
||||||
item.metadata[0]?.__typename === "ComponentMetadataGroup" &&
|
item.metadata[0]?.__typename === "ComponentMetadataGroup" &&
|
||||||
(item.metadata[0].subtype?.data?.attributes?.slug ===
|
(item.metadata[0].subtype?.data?.attributes?.slug ===
|
||||||
"variant-set" ||
|
"variant-set" ||
|
||||||
|
@ -200,7 +207,7 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
"relation-set")
|
"relation-set")
|
||||||
) && (
|
) && (
|
||||||
<>
|
<>
|
||||||
{item?.urls && item.urls.length ? (
|
{item.urls?.length ? (
|
||||||
<div className="flex flex-row place-items-center gap-3">
|
<div className="flex flex-row place-items-center gap-3">
|
||||||
<p>{langui.available_at}</p>
|
<p>{langui.available_at}</p>
|
||||||
{filterHasAttributes(item.urls).map((url, index) => (
|
{filterHasAttributes(item.urls).map((url, index) => (
|
||||||
|
@ -221,7 +228,7 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
</InsetBox>
|
</InsetBox>
|
||||||
|
|
||||||
{item?.gallery && item.gallery.data.length > 0 && (
|
{item.gallery && item.gallery.data.length > 0 && (
|
||||||
<div id="gallery" className="grid w-full place-items-center gap-8">
|
<div id="gallery" className="grid w-full place-items-center gap-8">
|
||||||
<h2 className="text-2xl">{langui.gallery}</h2>
|
<h2 className="text-2xl">{langui.gallery}</h2>
|
||||||
<div
|
<div
|
||||||
|
@ -238,7 +245,10 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
const images: string[] = filterHasAttributes(
|
const images: string[] = filterHasAttributes(
|
||||||
item.gallery?.data
|
item.gallery?.data
|
||||||
).map((image) =>
|
).map((image) =>
|
||||||
getAssetURL(image.attributes.url, ImageQuality.Large)
|
getAssetURL(
|
||||||
|
image.attributes.url,
|
||||||
|
ImageQuality.Large
|
||||||
|
)
|
||||||
);
|
);
|
||||||
openLightBox(images, index);
|
openLightBox(images, index);
|
||||||
}}
|
}}
|
||||||
|
@ -263,7 +273,7 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
className="grid place-items-center gap-y-8
|
className="grid place-items-center gap-y-8
|
||||||
desktop:grid-flow-col desktop:place-content-between"
|
desktop:grid-flow-col desktop:place-content-between"
|
||||||
>
|
>
|
||||||
{item?.metadata?.[0] && (
|
{item.metadata?.[0] && (
|
||||||
<div className="grid place-content-start place-items-center">
|
<div className="grid place-content-start place-items-center">
|
||||||
<h3 className="text-xl">{langui.type}</h3>
|
<h3 className="text-xl">{langui.type}</h3>
|
||||||
<div className="grid grid-flow-col gap-1">
|
<div className="grid grid-flow-col gap-1">
|
||||||
|
@ -274,14 +284,14 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{item?.release_date && (
|
{item.release_date && (
|
||||||
<div className="grid place-content-start place-items-center">
|
<div className="grid place-content-start place-items-center">
|
||||||
<h3 className="text-xl">{langui.release_date}</h3>
|
<h3 className="text-xl">{langui.release_date}</h3>
|
||||||
<p>{prettyDate(item.release_date)}</p>
|
<p>{prettyDate(item.release_date)}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{item?.price && (
|
{item.price && (
|
||||||
<div className="grid place-content-start place-items-center text-center">
|
<div className="grid place-content-start place-items-center text-center">
|
||||||
<h3 className="text-xl">{langui.price}</h3>
|
<h3 className="text-xl">{langui.price}</h3>
|
||||||
<p>
|
<p>
|
||||||
|
@ -294,7 +304,11 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
{item.price.currency?.data?.attributes?.code !==
|
{item.price.currency?.data?.attributes?.code !==
|
||||||
appLayout.currency && (
|
appLayout.currency && (
|
||||||
<p>
|
<p>
|
||||||
{prettyPrice(item.price, currencies, appLayout.currency)}{" "}
|
{prettyPrice(
|
||||||
|
item.price,
|
||||||
|
currencies,
|
||||||
|
appLayout.currency
|
||||||
|
)}{" "}
|
||||||
<br />({langui.calculated?.toLowerCase()})
|
<br />({langui.calculated?.toLowerCase()})
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
@ -302,7 +316,7 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{item?.categories && item.categories.data.length > 0 && (
|
{item.categories && item.categories.data.length > 0 && (
|
||||||
<div className="flex flex-col place-items-center gap-2">
|
<div className="flex flex-col place-items-center gap-2">
|
||||||
<h3 className="text-xl">{langui.categories}</h3>
|
<h3 className="text-xl">{langui.categories}</h3>
|
||||||
<div className="flex flex-row flex-wrap place-content-center gap-2">
|
<div className="flex flex-row flex-wrap place-content-center gap-2">
|
||||||
|
@ -313,7 +327,7 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{item?.size && (
|
{item.size && (
|
||||||
<div className="grid gap-8 mobile:place-items-center">
|
<div className="grid gap-8 mobile:place-items-center">
|
||||||
<h3 className="text-xl">{langui.size}</h3>
|
<h3 className="text-xl">{langui.size}</h3>
|
||||||
<div
|
<div
|
||||||
|
@ -356,12 +370,12 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{item?.metadata?.[0]?.__typename !== "ComponentMetadataGroup" &&
|
{item.metadata?.[0]?.__typename !== "ComponentMetadataGroup" &&
|
||||||
item?.metadata?.[0]?.__typename !== "ComponentMetadataOther" && (
|
item.metadata?.[0]?.__typename !== "ComponentMetadataOther" && (
|
||||||
<>
|
<>
|
||||||
<h3 className="text-xl">{langui.type_information}</h3>
|
<h3 className="text-xl">{langui.type_information}</h3>
|
||||||
<div className="grid w-full grid-cols-2 place-content-between">
|
<div className="grid w-full grid-cols-2 place-content-between">
|
||||||
{item?.metadata?.[0]?.__typename ===
|
{item.metadata?.[0]?.__typename ===
|
||||||
"ComponentMetadataBooks" && (
|
"ComponentMetadataBooks" && (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-row place-content-start gap-4">
|
<div className="flex flex-row place-content-start gap-4">
|
||||||
|
@ -408,7 +422,7 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
</InsetBox>
|
</InsetBox>
|
||||||
|
|
||||||
{item?.subitems && item.subitems.data.length > 0 && (
|
{item.subitems && item.subitems.data.length > 0 && (
|
||||||
<div
|
<div
|
||||||
id={isVariantSet ? "variants" : "subitems"}
|
id={isVariantSet ? "variants" : "subitems"}
|
||||||
className="grid w-full place-items-center gap-8"
|
className="grid w-full place-items-center gap-8"
|
||||||
|
@ -477,7 +491,7 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{item?.contents && item.contents.data.length > 0 && (
|
{item.contents && item.contents.data.length > 0 && (
|
||||||
<div id="contents" className="grid w-full place-items-center gap-8">
|
<div id="contents" className="grid w-full place-items-center gap-8">
|
||||||
<h2 className="-mb-6 text-2xl">{langui.contents}</h2>
|
<h2 className="-mb-6 text-2xl">{langui.contents}</h2>
|
||||||
{displayOpenScans && (
|
{displayOpenScans && (
|
||||||
|
@ -500,15 +514,29 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
LightBox,
|
||||||
|
openLightBox,
|
||||||
|
appLayout.currency,
|
||||||
|
currencies,
|
||||||
|
displayOpenScans,
|
||||||
|
hoverable,
|
||||||
|
isVariantSet,
|
||||||
|
item,
|
||||||
|
itemId,
|
||||||
|
keepInfoVisible,
|
||||||
|
langui,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLayout
|
<AppLayout
|
||||||
navTitle={prettyinlineTitle("", item?.title, item?.subtitle)}
|
navTitle={prettyinlineTitle("", item.title, item.subtitle)}
|
||||||
contentPanel={contentPanel}
|
contentPanel={contentPanel}
|
||||||
subPanel={subPanel}
|
subPanel={subPanel}
|
||||||
thumbnail={item?.thumbnail?.data?.attributes ?? undefined}
|
thumbnail={item.thumbnail?.data?.attributes ?? undefined}
|
||||||
description={item?.descriptions?.[0]?.description ?? undefined}
|
description={item.descriptions?.[0]?.description ?? undefined}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -526,6 +554,7 @@ export async function getStaticProps(
|
||||||
language_code: context.locale ?? "en",
|
language_code: context.locale ?? "en",
|
||||||
});
|
});
|
||||||
if (!item.libraryItems?.data[0]?.attributes) return { notFound: true };
|
if (!item.libraryItems?.data[0]?.attributes) return { notFound: true };
|
||||||
|
sortContent(item.libraryItems.data[0].attributes.contents);
|
||||||
const props: Props = {
|
const props: Props = {
|
||||||
...(await getAppStaticProps(context)),
|
...(await getAppStaticProps(context)),
|
||||||
item: item.libraryItems.data[0].attributes,
|
item: item.libraryItems.data[0].attributes,
|
||||||
|
@ -544,7 +573,7 @@ export async function getStaticPaths(
|
||||||
const paths: GetStaticPathsResult["paths"] = [];
|
const paths: GetStaticPathsResult["paths"] = [];
|
||||||
filterHasAttributes(libraryItems.libraryItems?.data).map((item) => {
|
filterHasAttributes(libraryItems.libraryItems?.data).map((item) => {
|
||||||
context.locales?.map((local) =>
|
context.locales?.map((local) =>
|
||||||
paths.push({ params: { slug: item.attributes?.slug }, locale: local })
|
paths.push({ params: { slug: item.attributes.slug }, locale: local })
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -23,33 +23,36 @@ import {
|
||||||
GetStaticPathsResult,
|
GetStaticPathsResult,
|
||||||
GetStaticPropsContext,
|
GetStaticPropsContext,
|
||||||
} from "next";
|
} from "next";
|
||||||
import { Fragment } from "react";
|
import { Fragment, useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {
|
interface Props extends AppStaticProps {
|
||||||
item: NonNullable<
|
item: NonNullable<
|
||||||
|
NonNullable<
|
||||||
GetLibraryItemScansQuery["libraryItems"]
|
GetLibraryItemScansQuery["libraryItems"]
|
||||||
>["data"][number]["attributes"];
|
>["data"][number]["attributes"]
|
||||||
|
>;
|
||||||
itemId: NonNullable<
|
itemId: NonNullable<
|
||||||
GetLibraryItemScansQuery["libraryItems"]
|
NonNullable<GetLibraryItemScansQuery["libraryItems"]>["data"][number]["id"]
|
||||||
>["data"][number]["id"];
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function LibrarySlug(props: Props): JSX.Element {
|
export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
const { item, langui, languages } = props;
|
const { item, langui, languages } = props;
|
||||||
const [openLightBox, LightBox] = useLightBox();
|
const [openLightBox, LightBox] = useLightBox();
|
||||||
sortContent(item?.contents);
|
sortContent(item.contents);
|
||||||
|
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href={`/library/${item?.slug}`}
|
href={`/library/${item.slug}`}
|
||||||
title={langui.item}
|
title={langui.item}
|
||||||
langui={langui}
|
langui={langui}
|
||||||
displayOn={ReturnButtonType.Desktop}
|
displayOn={ReturnButtonType.Desktop}
|
||||||
horizontalLine
|
horizontalLine
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{item?.contents?.data.map((content) => (
|
{item.contents?.data.map((content) => (
|
||||||
<NavOption
|
<NavOption
|
||||||
key={content.id}
|
key={content.id}
|
||||||
url={`#${content.attributes?.slug}`}
|
url={`#${content.attributes?.slug}`}
|
||||||
|
@ -66,21 +69,24 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[item.contents?.data, item.slug, langui]
|
||||||
);
|
);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
<LightBox />
|
<LightBox />
|
||||||
|
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href={`/library/${item?.slug}`}
|
href={`/library/${item.slug}`}
|
||||||
title={langui.item}
|
title={langui.item}
|
||||||
langui={langui}
|
langui={langui}
|
||||||
displayOn={ReturnButtonType.Mobile}
|
displayOn={ReturnButtonType.Mobile}
|
||||||
className="mb-10"
|
className="mb-10"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{item?.images && (
|
{item.images && (
|
||||||
<ScanSetCover
|
<ScanSetCover
|
||||||
images={item.images}
|
images={item.images}
|
||||||
openLightBox={openLightBox}
|
openLightBox={openLightBox}
|
||||||
|
@ -89,7 +95,7 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{item?.contents?.data.map((content) => (
|
{item.contents?.data.map((content) => (
|
||||||
<Fragment key={content.id}>
|
<Fragment key={content.id}>
|
||||||
{content.attributes?.scan_set?.[0] && (
|
{content.attributes?.scan_set?.[0] && (
|
||||||
<ScanSet
|
<ScanSet
|
||||||
|
@ -105,14 +111,24 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
LightBox,
|
||||||
|
openLightBox,
|
||||||
|
item.contents?.data,
|
||||||
|
item.images,
|
||||||
|
item.slug,
|
||||||
|
languages,
|
||||||
|
langui,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLayout
|
<AppLayout
|
||||||
navTitle={prettyinlineTitle("", item?.title, item?.subtitle)}
|
navTitle={prettyinlineTitle("", item.title, item.subtitle)}
|
||||||
contentPanel={contentPanel}
|
contentPanel={contentPanel}
|
||||||
subPanel={subPanel}
|
subPanel={subPanel}
|
||||||
thumbnail={item?.thumbnail?.data?.attributes ?? undefined}
|
thumbnail={item.thumbnail?.data?.attributes ?? undefined}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -129,7 +145,8 @@ export async function getStaticProps(
|
||||||
: "",
|
: "",
|
||||||
language_code: context.locale ?? "en",
|
language_code: context.locale ?? "en",
|
||||||
});
|
});
|
||||||
if (!item.libraryItems?.data[0]?.attributes) return { notFound: true };
|
if (!item.libraryItems?.data[0]?.attributes || !item.libraryItems.data[0]?.id)
|
||||||
|
return { notFound: true };
|
||||||
const props: Props = {
|
const props: Props = {
|
||||||
...(await getAppStaticProps(context)),
|
...(await getAppStaticProps(context)),
|
||||||
item: item.libraryItems.data[0].attributes,
|
item: item.libraryItems.data[0].attributes,
|
||||||
|
|
|
@ -114,7 +114,8 @@ export default function Library(props: Props): JSX.Element {
|
||||||
[langui, groupingMethod, sortedItems]
|
[langui, groupingMethod, sortedItems]
|
||||||
);
|
);
|
||||||
|
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<PanelHeader
|
<PanelHeader
|
||||||
icon={Icon.LibraryBooks}
|
icon={Icon.LibraryBooks}
|
||||||
|
@ -177,7 +178,10 @@ export default function Library(props: Props): JSX.Element {
|
||||||
<WithLabel
|
<WithLabel
|
||||||
label={langui.show_secondary_items}
|
label={langui.show_secondary_items}
|
||||||
input={
|
input={
|
||||||
<Switch state={showSecondaryItems} setState={setShowSecondaryItems} />
|
<Switch
|
||||||
|
state={showSecondaryItems}
|
||||||
|
setState={setShowSecondaryItems}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -237,8 +241,23 @@ export default function Library(props: Props): JSX.Element {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
filterUserStatus,
|
||||||
|
groupingMethod,
|
||||||
|
hoverable,
|
||||||
|
keepInfoVisible,
|
||||||
|
langui,
|
||||||
|
searchName,
|
||||||
|
showPrimaryItems,
|
||||||
|
showSecondaryItems,
|
||||||
|
showSubitems,
|
||||||
|
sortingMethod,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
const contentPanel = (
|
|
||||||
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
{/* TODO: Add to langui */}
|
{/* TODO: Add to langui */}
|
||||||
{groups.size === 0 && (
|
{groups.size === 0 && (
|
||||||
|
@ -311,7 +330,10 @@ export default function Library(props: Props): JSX.Element {
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[currencies, groups, keepInfoVisible, langui]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLayout
|
<AppLayout
|
||||||
navTitle={langui.library}
|
navTitle={langui.library}
|
||||||
|
|
|
@ -5,11 +5,13 @@ import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||||
|
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
import { Icon } from "components/Ico";
|
import { Icon } from "components/Ico";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {}
|
interface Props extends AppStaticProps {}
|
||||||
export default function Merch(props: Props): JSX.Element {
|
export default function Merch(props: Props): JSX.Element {
|
||||||
const { langui } = props;
|
const { langui } = props;
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<PanelHeader
|
<PanelHeader
|
||||||
icon={Icon.Store}
|
icon={Icon.Store}
|
||||||
|
@ -17,6 +19,8 @@ export default function Merch(props: Props): JSX.Element {
|
||||||
description={langui.merch_description}
|
description={langui.merch_description}
|
||||||
/>
|
/>
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[langui]
|
||||||
);
|
);
|
||||||
|
|
||||||
return <AppLayout navTitle={langui.merch} subPanel={subPanel} {...props} />;
|
return <AppLayout navTitle={langui.merch} subPanel={subPanel} {...props} />;
|
||||||
|
|
|
@ -46,7 +46,8 @@ export default function News(props: Props): JSX.Element {
|
||||||
[posts, searchName]
|
[posts, searchName]
|
||||||
);
|
);
|
||||||
|
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<PanelHeader
|
<PanelHeader
|
||||||
icon={Icon.Feed}
|
icon={Icon.Feed}
|
||||||
|
@ -80,9 +81,12 @@ export default function News(props: Props): JSX.Element {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[hoverable, keepInfoVisible, langui, searchName]
|
||||||
);
|
);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
<div
|
<div
|
||||||
className="grid grid-cols-1 items-end gap-8
|
className="grid grid-cols-1 items-end gap-8
|
||||||
|
@ -113,6 +117,8 @@ export default function News(props: Props): JSX.Element {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[filteredItems, keepInfoVisible]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -26,6 +26,7 @@ import {
|
||||||
GetStaticPathsResult,
|
GetStaticPathsResult,
|
||||||
GetStaticPropsContext,
|
GetStaticPropsContext,
|
||||||
} from "next";
|
} from "next";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {
|
interface Props extends AppStaticProps {
|
||||||
page: WikiPageWithTranslations;
|
page: WikiPageWithTranslations;
|
||||||
|
@ -40,7 +41,8 @@ export default function WikiPage(props: Props): JSX.Element {
|
||||||
languageExtractor: (item) => item.language?.data?.attributes?.code,
|
languageExtractor: (item) => item.language?.data?.attributes?.code,
|
||||||
});
|
});
|
||||||
|
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href={`/wiki`}
|
href={`/wiki`}
|
||||||
|
@ -50,8 +52,12 @@ export default function WikiPage(props: Props): JSX.Element {
|
||||||
horizontalLine
|
horizontalLine
|
||||||
/>
|
/>
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[langui]
|
||||||
);
|
);
|
||||||
const contentPanel = (
|
|
||||||
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Large}>
|
<ContentPanel width={ContentPanelWidthSizes.Large}>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href={`/wiki`}
|
href={`/wiki`}
|
||||||
|
@ -98,13 +104,13 @@ export default function WikiPage(props: Props): JSX.Element {
|
||||||
<DefinitionCard
|
<DefinitionCard
|
||||||
key={index}
|
key={index}
|
||||||
source={definition.source?.data?.attributes?.name}
|
source={definition.source?.data?.attributes?.name}
|
||||||
translations={filterHasAttributes(definition.translations).map(
|
translations={filterHasAttributes(
|
||||||
(translation) => ({
|
definition.translations
|
||||||
|
).map((translation) => ({
|
||||||
language: translation.language.data?.attributes?.code,
|
language: translation.language.data?.attributes?.code,
|
||||||
definition: translation.definition,
|
definition: translation.definition,
|
||||||
status: translation.status,
|
status: translation.status,
|
||||||
})
|
}))}
|
||||||
)}
|
|
||||||
index={index + 1}
|
index={index + 1}
|
||||||
languages={languages}
|
languages={languages}
|
||||||
langui={langui}
|
langui={langui}
|
||||||
|
@ -114,6 +120,16 @@ export default function WikiPage(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
LanguageSwitcher,
|
||||||
|
languages,
|
||||||
|
langui,
|
||||||
|
page.categories?.data,
|
||||||
|
page.definitions,
|
||||||
|
page.thumbnail?.data?.attributes,
|
||||||
|
selectedTranslation,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { getReadySdk } from "graphql/sdk";
|
||||||
import { prettySlug } from "helpers/formatters";
|
import { prettySlug } from "helpers/formatters";
|
||||||
import { filterHasAttributes, isDefined } from "helpers/others";
|
import { filterHasAttributes, isDefined } from "helpers/others";
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
import { Fragment } from "react";
|
import { Fragment, useMemo } from "react";
|
||||||
|
|
||||||
interface Props extends AppStaticProps {
|
interface Props extends AppStaticProps {
|
||||||
chronologyItems: NonNullable<
|
chronologyItems: NonNullable<
|
||||||
|
@ -27,10 +27,10 @@ export default function Chronology(props: Props): JSX.Element {
|
||||||
const { chronologyItems, chronologyEras, langui } = props;
|
const { chronologyItems, chronologyEras, langui } = props;
|
||||||
|
|
||||||
// Group by year the Chronology items
|
// Group by year the Chronology items
|
||||||
const chronologyItemYearGroups: Props["chronologyItems"][number][][][] = [];
|
const chronologyItemYearGroups = useMemo(() => {
|
||||||
|
const memo: Props["chronologyItems"][number][][][] = [];
|
||||||
chronologyEras.map(() => {
|
chronologyEras.map(() => {
|
||||||
chronologyItemYearGroups.push([]);
|
memo.push([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
let currentChronologyEraIndex = 0;
|
let currentChronologyEraIndex = 0;
|
||||||
|
@ -45,22 +45,21 @@ export default function Chronology(props: Props): JSX.Element {
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
Object.prototype.hasOwnProperty.call(
|
Object.prototype.hasOwnProperty.call(
|
||||||
chronologyItemYearGroups[currentChronologyEraIndex],
|
memo[currentChronologyEraIndex],
|
||||||
item.attributes.year
|
item.attributes.year
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
chronologyItemYearGroups[currentChronologyEraIndex][
|
memo[currentChronologyEraIndex][item.attributes.year].push(item);
|
||||||
item.attributes.year
|
|
||||||
].push(item);
|
|
||||||
} else {
|
} else {
|
||||||
chronologyItemYearGroups[currentChronologyEraIndex][
|
memo[currentChronologyEraIndex][item.attributes.year] = [item];
|
||||||
item.attributes.year
|
|
||||||
] = [item];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return memo;
|
||||||
|
}, [chronologyEras, chronologyItems]);
|
||||||
|
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href="/wiki"
|
href="/wiki"
|
||||||
|
@ -87,9 +86,12 @@ export default function Chronology(props: Props): JSX.Element {
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[chronologyEras, langui]
|
||||||
);
|
);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel>
|
<ContentPanel>
|
||||||
<ReturnButton
|
<ReturnButton
|
||||||
href="/wiki"
|
href="/wiki"
|
||||||
|
@ -130,6 +132,8 @@ export default function Chronology(props: Props): JSX.Element {
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[chronologyEras, chronologyItemYearGroups, langui]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -47,7 +47,8 @@ export default function Wiki(props: Props): JSX.Element {
|
||||||
[pages, searchName]
|
[pages, searchName]
|
||||||
);
|
);
|
||||||
|
|
||||||
const subPanel = (
|
const subPanel = useMemo(
|
||||||
|
() => (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<PanelHeader
|
<PanelHeader
|
||||||
icon={Icon.TravelExplore}
|
icon={Icon.TravelExplore}
|
||||||
|
@ -87,9 +88,12 @@ export default function Wiki(props: Props): JSX.Element {
|
||||||
|
|
||||||
<NavOption title={langui.chronology} url="/wiki/chronology" border />
|
<NavOption title={langui.chronology} url="/wiki/chronology" border />
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
|
),
|
||||||
|
[hoverable, keepInfoVisible, langui, searchName]
|
||||||
);
|
);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
<div
|
<div
|
||||||
className="grid grid-cols-2 items-end gap-8
|
className="grid grid-cols-2 items-end gap-8
|
||||||
|
@ -130,6 +134,8 @@ export default function Wiki(props: Props): JSX.Element {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[filteredPages, keepInfoVisible, languages]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in New Issue