aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-01-06 17:55:24 +0100
committerArmand Philippot <git@armandphilippot.com>2022-01-06 18:14:42 +0100
commitb9c1953c79688fc3f536b7927692309c9780b5da (patch)
tree673a26c0b0a9cc587f89d1eea9af739c3f17daf2 /src
parent544f8cd400f888464a18ee30836f63d4b93a0822 (diff)
refactor: reuse PostMeta components on single articles/pages
Diffstat (limited to 'src')
-rw-r--r--src/components/PostHeader/PostHeader.tsx82
-rw-r--r--src/components/PostMeta/PostMeta.module.scss51
-rw-r--r--src/components/PostMeta/PostMeta.tsx102
-rw-r--r--src/components/PostPreview/PostPreview.tsx15
-rw-r--r--src/pages/article/[slug].tsx25
-rw-r--r--src/pages/contact.tsx8
-rw-r--r--src/pages/cv.tsx24
-rw-r--r--src/pages/mentions-legales.tsx28
-rw-r--r--src/pages/sujet/[slug].tsx34
-rw-r--r--src/pages/thematique/[slug].tsx6
-rw-r--r--src/ts/types/articles.ts8
11 files changed, 220 insertions, 163 deletions
diff --git a/src/components/PostHeader/PostHeader.tsx b/src/components/PostHeader/PostHeader.tsx
index 3ee6705..e445b58 100644
--- a/src/components/PostHeader/PostHeader.tsx
+++ b/src/components/PostHeader/PostHeader.tsx
@@ -1,71 +1,37 @@
-import { t } from '@lingui/macro';
-import { Dates } from '@ts/types/app';
-import { ArticleAuthor } from '@ts/types/articles';
-import { ThematicPreview } from '@ts/types/taxonomies';
-import Link from 'next/link';
-import { useRouter } from 'next/router';
+import PostMeta from '@components/PostMeta/PostMeta';
+import { ArticleMeta } from '@ts/types/articles';
+import { Cover } from '@ts/types/cover';
+import Image from 'next/image';
import styles from './PostHeader.module.scss';
const PostHeader = ({
- author,
- dates,
+ cover,
intro,
title,
- thematics,
+ meta,
}: {
- author: ArticleAuthor;
- dates: Dates;
+ cover?: Cover;
intro: string;
+ meta?: ArticleMeta;
title: string;
- thematics: ThematicPreview[];
}) => {
- const { locale } = useRouter();
-
- const getAuthor = () => {
- return author.firstName
- ? `${author.firstName} ${author.lastName}`
- : author.name;
- };
-
- const getLocaleDate = (date: string) => {
- const dateOptions: Intl.DateTimeFormatOptions = {
- day: 'numeric',
- month: 'long',
- year: 'numeric',
- };
- return new Date(date).toLocaleDateString(locale, dateOptions);
- };
-
- const getThematics = () => {
- return thematics.map((thematic) => {
- return (
- <dd key={thematic.id}>
- <Link href={`/thematique/${thematic.slug}`}>
- <a>{thematic.title}</a>
- </Link>
- </dd>
- );
- });
- };
-
return (
- <header>
- <h1>{title}</h1>
- <ul className={styles.meta}>
- <li>{t`Written by ${getAuthor()} on ${getLocaleDate(
- dates.publication
- )}.`}</li>
- <li>{t`Last update on ${getLocaleDate(dates.update)}.`}</li>
- {thematics.length > 0 && (
- <li>
- <dl>
- <dt className={styles.label}>{t`Posted in:`}</dt>
- {getThematics()}
- </dl>
- </li>
- )}
- </ul>
- <div dangerouslySetInnerHTML={{ __html: intro }}></div>
+ <header className={styles.wrapper}>
+ <div className={styles.body}>
+ <h1 className={styles.title}>
+ {cover && (
+ <span className={styles.cover}>
+ <Image src={cover.sourceUrl} alt={cover.altText} layout="fill" />
+ </span>
+ )}
+ {title}
+ </h1>
+ {meta && <PostMeta mode="single" meta={meta} />}
+ <div
+ className={styles.intro}
+ dangerouslySetInnerHTML={{ __html: intro }}
+ ></div>
+ </div>
</header>
);
};
diff --git a/src/components/PostMeta/PostMeta.module.scss b/src/components/PostMeta/PostMeta.module.scss
index 3ec7daf..ac25828 100644
--- a/src/components/PostMeta/PostMeta.module.scss
+++ b/src/components/PostMeta/PostMeta.module.scss
@@ -2,17 +2,50 @@
@use "@styles/abstracts/mixins" as mix;
.wrapper {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- margin-top: var(--spacing-md);
- font-size: var(--font-size-sm);
+ &--list {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ margin-top: var(--spacing-md);
+ font-size: var(--font-size-sm);
- @include mix.media("screen") {
- @include mix.dimensions("sm") {
+ @include mix.media("screen") {
+ @include mix.dimensions("sm") {
+ display: flex;
+ flex-flow: column nowrap;
+ margin: 0;
+ composes: meta from "@components/PostPreview/PostPreview.module.scss";
+ }
+ }
+ }
+
+ &--single {
+ flex-flow: column wrap;
+ margin: 0;
+ padding: 0 var(--spacing-md);
+
+ @include mix.media("screen") {
+ @include mix.dimensions("xs") {
+ font-size: var(--font-size-sm);
+ }
+ }
+
+ .item {
display: flex;
- flex-flow: column nowrap;
- margin: 0;
- composes: meta from "@components/PostPreview/PostPreview.module.scss";
+ flex-flow: row wrap;
+ }
+
+ .term {
+ margin-right: var(--spacing-2xs);
+ color: var(--color-primary-darker);
+ }
+
+ .description {
+ &:not(:first-of-type) {
+ &::before {
+ content: "/";
+ margin: 0 var(--spacing-2xs);
+ }
+ }
}
}
}
diff --git a/src/components/PostMeta/PostMeta.tsx b/src/components/PostMeta/PostMeta.tsx
index 776d912..6d40048 100644
--- a/src/components/PostMeta/PostMeta.tsx
+++ b/src/components/PostMeta/PostMeta.tsx
@@ -1,20 +1,19 @@
import { t } from '@lingui/macro';
-import { ThematicPreview } from '@ts/types/taxonomies';
+import { ArticleMeta } from '@ts/types/articles';
import Link from 'next/link';
import { useRouter } from 'next/router';
import styles from './PostMeta.module.scss';
+type PostMetaMode = 'list' | 'single';
+
const PostMeta = ({
- commentCount,
- publicationDate,
- updateDate,
- thematics,
+ meta,
+ mode = 'list',
}: {
- commentCount: number | null;
- publicationDate: string;
- updateDate: string;
- thematics: ThematicPreview[];
+ meta: ArticleMeta;
+ mode?: PostMetaMode;
}) => {
+ const { author, commentCount, dates, thematics, website } = meta;
const { locale } = useRouter();
const dateOptions: Intl.DateTimeFormatOptions = {
day: 'numeric',
@@ -23,20 +22,22 @@ const PostMeta = ({
};
const getThematics = () => {
- return thematics.map((thematic) => {
- return (
- <dd key={thematic.id}>
- <Link href={`/thematique/${thematic.slug}`}>
- <a>{thematic.title}</a>
- </Link>
- </dd>
- );
- });
+ return (
+ thematics &&
+ thematics.map((thematic) => {
+ return (
+ <dd key={thematic.id} className={styles.description}>
+ <Link href={`/thematique/${thematic.slug}`}>
+ <a>{thematic.title}</a>
+ </Link>
+ </dd>
+ );
+ })
+ );
};
const getCommentsCount = () => {
switch (commentCount) {
- case null:
case 0:
return t`No comments`;
case 1:
@@ -46,32 +47,57 @@ const PostMeta = ({
}
};
+ const wrapperClass = styles[`wrapper--${mode}`];
+
return (
- <dl className={styles.wrapper}>
- <div>
- <dt>{t`Published on`}</dt>
- <dd>
- {new Date(publicationDate).toLocaleDateString(locale, dateOptions)}
- </dd>
- </div>
- {publicationDate !== updateDate && (
- <div>
- <dt>{t`Updated on`}</dt>
- <dd>
- {new Date(updateDate).toLocaleDateString(locale, dateOptions)}
+ <dl className={wrapperClass}>
+ {author && (
+ <div className={styles.item}>
+ <dt className={styles.term}>{t`Written by`}</dt>
+ <dd className={styles.description}>{author.name}</dd>
+ </div>
+ )}
+ {dates && (
+ <div className={styles.item}>
+ <dt className={styles.term}>{t`Published on`}</dt>
+ <dd className={styles.description}>
+ {new Date(dates.publication).toLocaleDateString(
+ locale,
+ dateOptions
+ )}
</dd>
</div>
)}
- {thematics.length > 0 && (
- <div>
- <dt>{thematics.length > 1 ? t`Thematics` : t`Thematic`}</dt>
+ {dates && dates.publication !== dates.update && (
+ <div className={styles.item}>
+ <dt className={styles.term}>{t`Updated on`}</dt>
+ <dd className={styles.description}>
+ {new Date(dates.update).toLocaleDateString(locale, dateOptions)}
+ </dd>
+ </div>
+ )}
+ {thematics && thematics.length > 0 && (
+ <div className={styles.item}>
+ <dt className={styles.term}>
+ {thematics.length > 1 ? t`Thematics` : t`Thematic`}
+ </dt>
{getThematics()}
</div>
)}
- <div>
- <dt>{t`Comments`}</dt>
- {getCommentsCount()}
- </div>
+ {website && (
+ <div className={styles.item}>
+ <dt className={styles.term}>{t`Website`}</dt>
+ <dd className={styles.description}>
+ <a href={website}>{website}</a>
+ </dd>
+ </div>
+ )}
+ {commentCount !== undefined && (
+ <div className={styles.item}>
+ <dt className={styles.term}>{t`Comments`}</dt>
+ {getCommentsCount()}
+ </div>
+ )}
</dl>
);
};
diff --git a/src/components/PostPreview/PostPreview.tsx b/src/components/PostPreview/PostPreview.tsx
index ccbb9e5..fa8bfd0 100644
--- a/src/components/PostPreview/PostPreview.tsx
+++ b/src/components/PostPreview/PostPreview.tsx
@@ -1,6 +1,6 @@
import PostMeta from '@components/PostMeta/PostMeta';
import { t } from '@lingui/macro';
-import { ArticlePreview } from '@ts/types/articles';
+import { ArticleMeta, ArticlePreview } from '@ts/types/articles';
import Link from 'next/link';
import styles from './PostPreview.module.scss';
import Image from 'next/image';
@@ -18,6 +18,12 @@ const PostPreview = ({
}) => {
const TitleTag = `h${titleLevel}` as keyof JSX.IntrinsicElements;
+ const meta: ArticleMeta = {
+ commentCount: post.commentCount ? post.commentCount : 0,
+ dates: post.dates,
+ thematics: post.thematics,
+ };
+
return (
<article className={styles.wrapper}>
{post.featuredImage && Object.keys(post.featuredImage).length > 0 && (
@@ -55,12 +61,7 @@ const PostPreview = ({
<ArrowIcon />
</ButtonLink>
</footer>
- <PostMeta
- commentCount={post.commentCount}
- publicationDate={post.dates.publication}
- updateDate={post.dates.update}
- thematics={post.thematics}
- />
+ <PostMeta meta={meta} />
</article>
);
};
diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx
index 493f061..e8df85e 100644
--- a/src/pages/article/[slug].tsx
+++ b/src/pages/article/[slug].tsx
@@ -9,7 +9,7 @@ import { config } from '@config/website';
import { t } from '@lingui/macro';
import { getAllPostsSlug, getPostBySlug } from '@services/graphql/queries';
import { NextPageWithLayout } from '@ts/types/app';
-import { ArticleProps } from '@ts/types/articles';
+import { ArticleMeta, ArticleProps } from '@ts/types/articles';
import { loadTranslation } from '@utils/helpers/i18n';
import { addPrismClasses, translateCopyButton } from '@utils/helpers/prism';
import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from 'next';
@@ -32,6 +32,13 @@ const SingleArticle: NextPageWithLayout<ArticleProps> = ({ post }) => {
title,
} = post;
+ const meta: ArticleMeta = {
+ author,
+ commentCount: comments.length,
+ dates,
+ thematics,
+ };
+
const router = useRouter();
const locale = router.locale ? router.locale : config.defaultLocale;
@@ -51,17 +58,15 @@ const SingleArticle: NextPageWithLayout<ArticleProps> = ({ post }) => {
<meta name="description" content={seo.metaDesc} />
</Head>
<article>
- <PostHeader
- author={author}
- dates={dates}
- intro={intro}
- title={title}
- thematics={thematics}
- />
- <ToC />
+ <PostHeader intro={intro} meta={meta} title={title} />
+ <aside>
+ <ToC />
+ </aside>
<div dangerouslySetInnerHTML={{ __html: content }}></div>
<PostFooter subjects={subjects} />
- <Sharing title={title} excerpt={intro} />
+ <aside>
+ <Sharing title={title} excerpt={intro} />
+ </aside>
<section>
<h2>{t`Comments`}</h2>
<CommentsList comments={comments} />
diff --git a/src/pages/contact.tsx b/src/pages/contact.tsx
index 3ce6098..ca82f5b 100644
--- a/src/pages/contact.tsx
+++ b/src/pages/contact.tsx
@@ -9,6 +9,7 @@ import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticProps, GetStaticPropsContext } from 'next';
import Head from 'next/head';
import { FormEvent, useState } from 'react';
+import PostHeader from '@components/PostHeader/PostHeader';
const ContactPage: NextPageWithLayout = () => {
const [name, setName] = useState('');
@@ -48,6 +49,9 @@ const ContactPage: NextPageWithLayout = () => {
}
};
+ const title = t`Contact`;
+ const intro = t`Please fill the form to contact me.`;
+
return (
<>
<Head>
@@ -55,9 +59,7 @@ const ContactPage: NextPageWithLayout = () => {
<meta name="description" content={seo.contact.description} />
</Head>
<article>
- <header>
- <h1>{t`Contact`}</h1>
- </header>
+ <PostHeader title={title} intro={intro} />
<div>
<p>{t`All fields marked with * are required.`}</p>
{status && <p>{status}</p>}
diff --git a/src/pages/cv.tsx b/src/pages/cv.tsx
index 5107f6a..3faa941 100644
--- a/src/pages/cv.tsx
+++ b/src/pages/cv.tsx
@@ -6,8 +6,19 @@ import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticProps, GetStaticPropsContext } from 'next';
import Head from 'next/head';
import CVContent, { intro, meta } from '@content/pages/cv.mdx';
+import PostHeader from '@components/PostHeader/PostHeader';
+import { ArticleMeta } from '@ts/types/articles';
const CV: NextPageWithLayout = () => {
+ const dates = {
+ publication: meta.publishedOn,
+ update: meta.updatedOn,
+ };
+
+ const pageMeta: ArticleMeta = {
+ dates,
+ };
+
return (
<>
<Head>
@@ -15,12 +26,13 @@ const CV: NextPageWithLayout = () => {
<meta name="description" content={seo.cv.description} />
</Head>
<article>
- <header>
- <h1>{meta.title}</h1>
- <div dangerouslySetInnerHTML={{ __html: intro }}></div>
- </header>
- <ToC />
- <CVContent />
+ <PostHeader intro={intro} meta={pageMeta} title={meta.title} />
+ <aside>
+ <ToC />
+ </aside>
+ <div>
+ <CVContent />
+ </div>
</article>
</>
);
diff --git a/src/pages/mentions-legales.tsx b/src/pages/mentions-legales.tsx
index 6bb1a55..d8dfe49 100644
--- a/src/pages/mentions-legales.tsx
+++ b/src/pages/mentions-legales.tsx
@@ -5,9 +5,23 @@ import { NextPageWithLayout } from '@ts/types/app';
import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticProps, GetStaticPropsContext } from 'next';
import Head from 'next/head';
-import LegalNoticeContent, { meta } from '@content/pages/legal-notice.mdx';
+import LegalNoticeContent, {
+ intro,
+ meta,
+} from '@content/pages/legal-notice.mdx';
+import PostHeader from '@components/PostHeader/PostHeader';
+import { ArticleMeta } from '@ts/types/articles';
const LegalNotice: NextPageWithLayout = () => {
+ const dates = {
+ publication: meta.publishedOn,
+ update: meta.updatedOn,
+ };
+
+ const pageMeta: ArticleMeta = {
+ dates,
+ };
+
return (
<>
<Head>
@@ -15,11 +29,13 @@ const LegalNotice: NextPageWithLayout = () => {
<meta name="description" content={seo.legalNotice.description} />
</Head>
<article>
- <header>
- <h1>{meta.title}</h1>
- </header>
- <ToC />
- <LegalNoticeContent />
+ <PostHeader intro={intro} meta={pageMeta} title={meta.title} />
+ <aside>
+ <ToC />
+ </aside>
+ <div>
+ <LegalNoticeContent />
+ </div>
</article>
</>
);
diff --git a/src/pages/sujet/[slug].tsx b/src/pages/sujet/[slug].tsx
index 527d529..bcea544 100644
--- a/src/pages/sujet/[slug].tsx
+++ b/src/pages/sujet/[slug].tsx
@@ -5,13 +5,14 @@ import { NextPageWithLayout } from '@ts/types/app';
import { SubjectProps } from '@ts/types/taxonomies';
import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from 'next';
-import Image from 'next/image';
import { ParsedUrlQuery } from 'querystring';
import styles from '@styles/pages/Subject.module.scss';
import {
getAllSubjectsSlug,
getSubjectBySlug,
} from '@services/graphql/queries';
+import PostHeader from '@components/PostHeader/PostHeader';
+import { ArticleMeta } from '@ts/types/articles';
const Subject: NextPageWithLayout<SubjectProps> = ({ subject }) => {
const getPostsList = () => {
@@ -22,29 +23,18 @@ const Subject: NextPageWithLayout<SubjectProps> = ({ subject }) => {
));
};
+ const meta: ArticleMeta = {
+ website: subject.officialWebsite,
+ };
+
return (
<article>
- <header>
- <h1 className={styles.title}>
- {subject.featuredImage && (
- <span className={styles.cover}>
- <Image
- src={subject.featuredImage.sourceUrl}
- alt={subject.featuredImage.altText}
- layout="fill"
- />
- </span>
- )}
- {subject.title}
- </h1>
- {subject.officialWebsite && (
- <dl>
- <dt>{t`Official website:`}</dt>
- <dd>{subject.officialWebsite}</dd>
- </dl>
- )}
- <div dangerouslySetInnerHTML={{ __html: subject.intro }}></div>
- </header>
+ <PostHeader
+ cover={subject.featuredImage}
+ intro={subject.intro}
+ meta={meta}
+ title={subject.title}
+ />
<div dangerouslySetInnerHTML={{ __html: subject.content }}></div>
{subject.posts.length > 0 && (
<div>
diff --git a/src/pages/thematique/[slug].tsx b/src/pages/thematique/[slug].tsx
index 74c2212..dca8f25 100644
--- a/src/pages/thematique/[slug].tsx
+++ b/src/pages/thematique/[slug].tsx
@@ -11,6 +11,7 @@ import {
getAllThematicsSlug,
getThematicBySlug,
} from '@services/graphql/queries';
+import PostHeader from '@components/PostHeader/PostHeader';
const Thematic: NextPageWithLayout<ThematicProps> = ({ thematic }) => {
const getPostsList = () => {
@@ -23,10 +24,7 @@ const Thematic: NextPageWithLayout<ThematicProps> = ({ thematic }) => {
return (
<article>
- <header>
- <h1>{thematic.title}</h1>
- <div dangerouslySetInnerHTML={{ __html: thematic.intro }}></div>
- </header>
+ <PostHeader intro={thematic.intro} title={thematic.title} />
<div dangerouslySetInnerHTML={{ __html: thematic.content }}></div>
{thematic.posts.length > 0 && (
<div>
diff --git a/src/ts/types/articles.ts b/src/ts/types/articles.ts
index dc5bbe4..44c1d79 100644
--- a/src/ts/types/articles.ts
+++ b/src/ts/types/articles.ts
@@ -24,6 +24,14 @@ export type ACFPosts = {
postsInThematic: ThematicPreview[] | null;
};
+export type ArticleMeta = {
+ author?: ArticleAuthor;
+ commentCount?: number;
+ dates?: Dates;
+ thematics?: ThematicPreview[];
+ website?: string;
+};
+
export type Article = {
author: ArticleAuthor;
commentCount: number | null;