aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/templates/page/page-layout.tsx
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-04-25 12:57:12 +0200
committerArmand Philippot <git@armandphilippot.com>2022-04-25 12:57:12 +0200
commit8a6f09b564d5d2f02d0a2605f6b52070a910aaa3 (patch)
treecd9e2b6ae6be75f4595b9823e67ebb6bc76df8e8 /src/components/templates/page/page-layout.tsx
parent782a5a1e794a9a8ef6b0b892cd3f386ed583c680 (diff)
chore: add a PageLayout component
Diffstat (limited to 'src/components/templates/page/page-layout.tsx')
-rw-r--r--src/components/templates/page/page-layout.tsx166
1 files changed, 166 insertions, 0 deletions
diff --git a/src/components/templates/page/page-layout.tsx b/src/components/templates/page/page-layout.tsx
new file mode 100644
index 0000000..24c4e50
--- /dev/null
+++ b/src/components/templates/page/page-layout.tsx
@@ -0,0 +1,166 @@
+import Heading from '@components/atoms/headings/heading';
+import Sidebar from '@components/atoms/layout/sidebar';
+import PageFooter, {
+ type PageFooterProps,
+} from '@components/molecules/layout/page-footer';
+import PageHeader, {
+ type PageHeaderProps,
+} from '@components/molecules/layout/page-header';
+import Breadcrumb, {
+ type BreadcrumbItem,
+} from '@components/molecules/nav/breadcrumb';
+import CommentForm from '@components/organisms/forms/comment-form';
+import CommentsList, {
+ type CommentsListProps,
+} from '@components/organisms/layout/comments-list';
+import TableOfContents from '@components/organisms/widgets/table-of-contents';
+import useIsMounted from '@utils/hooks/use-is-mounted';
+import { FC, ReactNode, useRef } from 'react';
+import { useIntl } from 'react-intl';
+import Layout, { LayoutProps } from '../layout/layout';
+import styles from './page-layout.module.scss';
+
+export type PageLayoutProps = {
+ /**
+ * True if the page accepts new comments. Default: false.
+ */
+ allowComments?: boolean;
+ /**
+ * The breadcrumb items.
+ */
+ breadcrumb: BreadcrumbItem[];
+ /**
+ * The main content of the page.
+ */
+ children: ReactNode;
+ /**
+ * The page comments
+ */
+ comments?: CommentsListProps['comments'];
+ /**
+ * The footer metadata.
+ */
+ footerMeta?: PageFooterProps['meta'];
+ /**
+ * The header metadata.
+ */
+ headerMeta?: PageHeaderProps['meta'];
+ /**
+ * The page introduction.
+ */
+ intro?: PageHeaderProps['intro'];
+ /**
+ * True if it is homepage. Default: false.
+ */
+ isHome?: LayoutProps['isHome'];
+ /**
+ * The page title.
+ */
+ title: PageHeaderProps['title'];
+ /**
+ * An array of widgets to put in the last sidebar.
+ */
+ widgets?: ReactNode[];
+ /**
+ * Show the table of contents. Default: false.
+ */
+ withToC?: boolean;
+};
+
+/**
+ * PageLayout component
+ *
+ * Render the pages layout.
+ */
+const PageLayout: FC<PageLayoutProps> = ({
+ children,
+ allowComments = false,
+ breadcrumb,
+ comments,
+ footerMeta,
+ headerMeta,
+ intro,
+ isHome = false,
+ widgets,
+ title,
+ withToC = false,
+}) => {
+ const intl = useIntl();
+ const commentsTitle = intl.formatMessage({
+ defaultMessage: 'Comments',
+ description: 'PageLayout: comments title',
+ id: '+dJU3e',
+ });
+ const commentFormTitle = intl.formatMessage({
+ defaultMessage: 'Leave a comment',
+ description: 'PageLayout: comment form title',
+ id: 'kzIYoQ',
+ });
+
+ const bodyRef = useRef<HTMLDivElement>(null);
+ const isMounted = useIsMounted(bodyRef);
+
+ const hasComments = Array.isArray(comments) && comments.length > 0;
+ const hasCommentsSection = hasComments || allowComments;
+ const articleModifier = hasCommentsSection
+ ? 'article--has-comments'
+ : 'article--no-comments';
+
+ const saveComment = () => {
+ return null;
+ };
+
+ return (
+ <Layout
+ isHome={isHome}
+ className={`${styles.article} ${styles[articleModifier]}`}
+ >
+ <Breadcrumb
+ items={breadcrumb}
+ className={styles.breadcrumb}
+ itemClassName={styles.breadcrumb__items}
+ />
+ <PageHeader
+ title={title}
+ intro={intro}
+ meta={headerMeta}
+ className={styles.header}
+ />
+ {withToC && (
+ <Sidebar className={`${styles.sidebar} ${styles['sidebar--first']}`}>
+ {isMounted && bodyRef.current && (
+ <TableOfContents wrapper={bodyRef.current} />
+ )}
+ </Sidebar>
+ )}
+ <div ref={bodyRef} className={styles.body}>
+ {children}
+ </div>
+ <PageFooter meta={footerMeta} className={styles.footer} />
+ <Sidebar className={`${styles.sidebar} ${styles['sidebar--last']}`}>
+ {widgets}
+ </Sidebar>
+ {hasCommentsSection && (
+ <div className={styles.comments}>
+ {hasComments && (
+ <section className={styles.comments__section}>
+ <Heading level={2}>{commentsTitle}</Heading>
+ <CommentsList
+ saveComment={saveComment}
+ comments={comments}
+ depth={2}
+ />
+ </section>
+ )}
+ {allowComments && (
+ <section className={styles.comments__section}>
+ <CommentForm saveComment={saveComment} title={commentFormTitle} />
+ </section>
+ )}
+ </div>
+ )}
+ </Layout>
+ );
+};
+
+export default PageLayout;