239 lines
7.3 KiB
TypeScript
239 lines
7.3 KiB
TypeScript
import { Fragment, useCallback, useMemo } from "react";
|
|
import { AppLayout } from "./AppLayout";
|
|
import { Chip } from "./Chip";
|
|
import { HorizontalLine } from "./HorizontalLine";
|
|
import { Markdawn, TableOfContents } from "./Markdown/Markdawn";
|
|
import { ReturnButton, ReturnButtonType } from "./PanelComponents/ReturnButton";
|
|
import { ContentPanel } from "./Panels/ContentPanel";
|
|
import { SubPanel } from "./Panels/SubPanel";
|
|
import { RecorderChip } from "./RecorderChip";
|
|
import { ThumbnailHeader } from "./ThumbnailHeader";
|
|
import { ToolTip } from "./ToolTip";
|
|
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
|
import { PostWithTranslations } from "helpers/types";
|
|
import { filterHasAttributes, getStatusDescription } from "helpers/others";
|
|
import { prettySlug } from "helpers/formatters";
|
|
import { getDescription } from "helpers/description";
|
|
import { AppStaticProps } from "graphql/getAppStaticProps";
|
|
|
|
/*
|
|
* ╭─────────────╮
|
|
* ───────────────────────────────────────╯ COMPONENT ╰───────────────────────────────────────────
|
|
*/
|
|
|
|
interface Props {
|
|
post: PostWithTranslations;
|
|
langui: AppStaticProps["langui"];
|
|
languages: AppStaticProps["languages"];
|
|
currencies: AppStaticProps["currencies"];
|
|
returnHref?: string;
|
|
returnTitle?: string | null | undefined;
|
|
displayCredits?: boolean;
|
|
displayToc?: boolean;
|
|
displayThumbnailHeader?: boolean;
|
|
displayTitle?: boolean;
|
|
displayLanguageSwitcher?: boolean;
|
|
prependBody?: JSX.Element;
|
|
appendBody?: JSX.Element;
|
|
}
|
|
|
|
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
|
|
|
export const PostPage = ({
|
|
post,
|
|
langui,
|
|
languages,
|
|
returnHref,
|
|
returnTitle,
|
|
displayCredits,
|
|
displayToc,
|
|
displayThumbnailHeader,
|
|
displayLanguageSwitcher,
|
|
appendBody,
|
|
prependBody,
|
|
displayTitle = true,
|
|
currencies,
|
|
}: Props): JSX.Element => {
|
|
const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] =
|
|
useSmartLanguage({
|
|
items: post.translations,
|
|
languages: languages,
|
|
languageExtractor: useCallback(
|
|
(item: NonNullable<PostWithTranslations["translations"][number]>) =>
|
|
item.language?.data?.attributes?.code,
|
|
[]
|
|
),
|
|
});
|
|
|
|
const { thumbnail, body, title, excerpt } = useMemo(
|
|
() => ({
|
|
thumbnail:
|
|
selectedTranslation?.thumbnail?.data?.attributes ??
|
|
post.thumbnail?.data?.attributes,
|
|
body: selectedTranslation?.body ?? "",
|
|
title: selectedTranslation?.title ?? prettySlug(post.slug),
|
|
excerpt: selectedTranslation?.excerpt ?? "",
|
|
}),
|
|
[post.slug, post.thumbnail, selectedTranslation]
|
|
);
|
|
|
|
const subPanel = useMemo(
|
|
() =>
|
|
returnHref || returnTitle || displayCredits || displayToc ? (
|
|
<SubPanel>
|
|
{returnHref && returnTitle && (
|
|
<ReturnButton
|
|
href={returnHref}
|
|
title={returnTitle}
|
|
langui={langui}
|
|
displayOn={ReturnButtonType.Desktop}
|
|
horizontalLine
|
|
/>
|
|
)}
|
|
|
|
{displayCredits && (
|
|
<>
|
|
{selectedTranslation && (
|
|
<div className="grid grid-flow-col place-content-center place-items-center gap-2">
|
|
<p className="font-headers font-bold">{langui.status}:</p>
|
|
|
|
<ToolTip
|
|
content={getStatusDescription(
|
|
selectedTranslation.status,
|
|
langui
|
|
)}
|
|
maxWidth={"20rem"}
|
|
>
|
|
<Chip text={selectedTranslation.status} />
|
|
</ToolTip>
|
|
</div>
|
|
)}
|
|
|
|
{post.authors && post.authors.data.length > 0 && (
|
|
<div>
|
|
<p className="font-headers font-bold">{"Authors"}:</p>
|
|
<div className="grid place-content-center place-items-center gap-2">
|
|
{filterHasAttributes(post.authors.data, [
|
|
"id",
|
|
"attributes",
|
|
] as const).map((author) => (
|
|
<Fragment key={author.id}>
|
|
<RecorderChip
|
|
langui={langui}
|
|
recorder={author.attributes}
|
|
/>
|
|
</Fragment>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<HorizontalLine />
|
|
</>
|
|
)}
|
|
|
|
{displayToc && (
|
|
<TableOfContents text={body} title={title} langui={langui} />
|
|
)}
|
|
</SubPanel>
|
|
) : undefined,
|
|
[
|
|
body,
|
|
displayCredits,
|
|
displayToc,
|
|
langui,
|
|
post.authors,
|
|
returnHref,
|
|
returnTitle,
|
|
selectedTranslation,
|
|
title,
|
|
]
|
|
);
|
|
|
|
const contentPanel = useMemo(
|
|
() => (
|
|
<ContentPanel>
|
|
{returnHref && returnTitle && (
|
|
<ReturnButton
|
|
href={returnHref}
|
|
title={returnTitle}
|
|
langui={langui}
|
|
displayOn={ReturnButtonType.Mobile}
|
|
horizontalLine
|
|
/>
|
|
)}
|
|
|
|
{displayThumbnailHeader ? (
|
|
<>
|
|
<ThumbnailHeader
|
|
thumbnail={thumbnail}
|
|
title={title}
|
|
description={excerpt}
|
|
langui={langui}
|
|
categories={post.categories}
|
|
languageSwitcher={
|
|
languageSwitcherProps.locales.size > 1 ? (
|
|
<LanguageSwitcher {...languageSwitcherProps} />
|
|
) : undefined
|
|
}
|
|
/>
|
|
|
|
<HorizontalLine />
|
|
</>
|
|
) : (
|
|
<>
|
|
{displayLanguageSwitcher && (
|
|
<div className="grid place-content-end place-items-start">
|
|
<LanguageSwitcher {...languageSwitcherProps} />
|
|
</div>
|
|
)}
|
|
{displayTitle && (
|
|
<h1 className="my-16 flex justify-center gap-3 text-center text-4xl">
|
|
{title}
|
|
</h1>
|
|
)}
|
|
</>
|
|
)}
|
|
|
|
{prependBody}
|
|
<Markdawn text={body} />
|
|
{appendBody}
|
|
</ContentPanel>
|
|
),
|
|
[
|
|
LanguageSwitcher,
|
|
appendBody,
|
|
body,
|
|
displayLanguageSwitcher,
|
|
displayThumbnailHeader,
|
|
displayTitle,
|
|
excerpt,
|
|
languageSwitcherProps,
|
|
langui,
|
|
post.categories,
|
|
prependBody,
|
|
returnHref,
|
|
returnTitle,
|
|
thumbnail,
|
|
title,
|
|
]
|
|
);
|
|
|
|
return (
|
|
<AppLayout
|
|
navTitle={title}
|
|
description={getDescription({
|
|
langui: langui,
|
|
description: selectedTranslation?.excerpt,
|
|
categories: post.categories,
|
|
})}
|
|
contentPanel={contentPanel}
|
|
subPanel={subPanel}
|
|
thumbnail={thumbnail ?? undefined}
|
|
currencies={currencies}
|
|
languages={languages}
|
|
langui={langui}
|
|
/>
|
|
);
|
|
};
|