diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-01-06 17:55:24 +0100 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-01-06 18:14:42 +0100 |
| commit | b9c1953c79688fc3f536b7927692309c9780b5da (patch) | |
| tree | 673a26c0b0a9cc587f89d1eea9af739c3f17daf2 /src | |
| parent | 544f8cd400f888464a18ee30836f63d4b93a0822 (diff) | |
refactor: reuse PostMeta components on single articles/pages
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/PostHeader/PostHeader.tsx | 82 | ||||
| -rw-r--r-- | src/components/PostMeta/PostMeta.module.scss | 51 | ||||
| -rw-r--r-- | src/components/PostMeta/PostMeta.tsx | 102 | ||||
| -rw-r--r-- | src/components/PostPreview/PostPreview.tsx | 15 | ||||
| -rw-r--r-- | src/pages/article/[slug].tsx | 25 | ||||
| -rw-r--r-- | src/pages/contact.tsx | 8 | ||||
| -rw-r--r-- | src/pages/cv.tsx | 24 | ||||
| -rw-r--r-- | src/pages/mentions-legales.tsx | 28 | ||||
| -rw-r--r-- | src/pages/sujet/[slug].tsx | 34 | ||||
| -rw-r--r-- | src/pages/thematique/[slug].tsx | 6 | ||||
| -rw-r--r-- | src/ts/types/articles.ts | 8 |
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; |
