2022-08-27 17:03:05 +02:00

220 lines
6.7 KiB
TypeScript

import { Fragment, useCallback, useMemo } from "react";
import { AppLayout, AppLayoutRequired } from "./AppLayout";
import { Chip } from "./Chip";
import { HorizontalLine } from "./HorizontalLine";
import { Markdawn, TableOfContents } from "./Markdown/Markdawn";
import { ReturnButton } 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 { useAppLayout } from "contexts/AppLayoutContext";
/*
* ╭─────────────╮
* ───────────────────────────────────────╯ COMPONENT ╰───────────────────────────────────────────
*/
interface Props extends AppLayoutRequired {
post: PostWithTranslations;
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,
returnHref,
returnTitle,
displayCredits,
displayToc,
displayThumbnailHeader,
displayLanguageSwitcher,
appendBody,
prependBody,
displayTitle = true,
...otherProps
}: Props): JSX.Element => {
const { langui } = useAppLayout();
const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] =
useSmartLanguage({
items: post.translations,
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}
displayOnlyOn={"3ColumnsLayout"}
/>
)}
{displayCredits && (
<>
<HorizontalLine />
{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 recorder={author.attributes} />
</Fragment>
))}
</div>
</div>
)}
</>
)}
{displayToc && (
<TableOfContents text={body} title={title} horizontalLine />
)}
</SubPanel>
) : undefined,
[
body,
displayCredits,
displayToc,
langui,
post.authors,
returnHref,
returnTitle,
selectedTranslation,
title,
]
);
const contentPanel = useMemo(
() => (
<ContentPanel>
{returnHref && returnTitle && (
<ReturnButton
href={returnHref}
title={returnTitle}
displayOnlyOn={"1ColumnLayout"}
className="mb-10"
/>
)}
{displayThumbnailHeader ? (
<>
<ThumbnailHeader
thumbnail={thumbnail}
title={title}
description={excerpt}
categories={post.categories}
languageSwitcher={
languageSwitcherProps.locales.size > 1 ? (
<LanguageSwitcher {...languageSwitcherProps} />
) : undefined
}
/>
</>
) : (
<>
{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}
{body && (
<>
{displayThumbnailHeader && <HorizontalLine />}
<Markdawn text={body} />
</>
)}
{appendBody}
</ContentPanel>
),
[
LanguageSwitcher,
appendBody,
body,
displayLanguageSwitcher,
displayThumbnailHeader,
displayTitle,
excerpt,
languageSwitcherProps,
post.categories,
prependBody,
returnHref,
returnTitle,
thumbnail,
title,
]
);
return (
<AppLayout
{...otherProps}
contentPanel={contentPanel}
subPanel={subPanel}
/>
);
};