aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2021-12-21 14:29:19 +0100
committerArmand Philippot <git@armandphilippot.com>2021-12-21 14:29:19 +0100
commita367f605b842ad0a71a63025da15ac62ed0364a5 (patch)
treeb15150fbe219d1905b98570ebafb5063d0ade1b1
parent6092ad0c91e0dc268e5988174db87ded14e6c931 (diff)
chore: add a breadcrumb component
-rw-r--r--src/components/Breadcrumb/Breadcrumb.module.scss21
-rw-r--r--src/components/Breadcrumb/Breadcrumb.tsx53
-rw-r--r--src/components/Layouts/Layout.tsx14
-rw-r--r--src/pages/404.tsx8
-rw-r--r--src/pages/article/[slug].tsx9
-rw-r--r--src/pages/blog/index.tsx9
-rw-r--r--src/pages/contact.tsx9
-rw-r--r--src/pages/cv.tsx7
-rw-r--r--src/pages/mentions-legales.tsx7
-rw-r--r--src/pages/recherche/index.tsx9
-rw-r--r--src/pages/sujet/[slug].tsx9
-rw-r--r--src/pages/thematique/[slug].tsx9
12 files changed, 128 insertions, 36 deletions
diff --git a/src/components/Breadcrumb/Breadcrumb.module.scss b/src/components/Breadcrumb/Breadcrumb.module.scss
new file mode 100644
index 0000000..bfba21f
--- /dev/null
+++ b/src/components/Breadcrumb/Breadcrumb.module.scss
@@ -0,0 +1,21 @@
+@use "@styles/abstracts/placeholders";
+
+.list {
+ @extend %reset-ordered-list;
+
+ display: flex;
+ flex-flow: row wrap;
+ align-items: center;
+ gap: var(--spacing-2xs);
+ margin: 0 0 var(--spacing-md) 0;
+ font-size: var(--font-size-sm);
+}
+
+.item {
+ &:not(:last-of-type) {
+ &::after {
+ content: ">";
+ margin-left: var(--spacing-2xs);
+ }
+ }
+}
diff --git a/src/components/Breadcrumb/Breadcrumb.tsx b/src/components/Breadcrumb/Breadcrumb.tsx
new file mode 100644
index 0000000..e090a4f
--- /dev/null
+++ b/src/components/Breadcrumb/Breadcrumb.tsx
@@ -0,0 +1,53 @@
+import { t } from '@lingui/macro';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+import styles from './Breadcrumb.module.scss';
+
+const Breadcrumb = ({ pageTitle }: { pageTitle: string }) => {
+ const router = useRouter();
+
+ const isHome = router.pathname === '/';
+ const isBlog = router.pathname === '/blog';
+ const isArticle = router.pathname.includes('/article/');
+ const isThematic = router.pathname.includes('/thematique/');
+ const isSubject = router.pathname.includes('/sujet/');
+
+ const getItems = () => {
+ return (
+ <>
+ <li className={styles.item}>
+ <Link href="/">
+ <a>{t`Home`}</a>
+ </Link>
+ </li>
+ {isBlog && <li className={styles.item}>{t`Blog`}</li>}
+ {(isArticle || isThematic || isSubject) && (
+ <>
+ <li className={styles.item}>
+ <Link href="/blog">
+ <a>{t`Blog`}</a>
+ </Link>
+ </li>
+ <li className={styles.item}>{pageTitle}</li>
+ </>
+ )}
+ {!isBlog && !isArticle && !isThematic && !isSubject && (
+ <li className={styles.item}>{pageTitle}</li>
+ )}
+ </>
+ );
+ };
+
+ return (
+ <>
+ {!isHome && (
+ <nav>
+ <span className="screen-reader-text">{t`You are here:`}</span>
+ <ol className={styles.list}>{getItems()}</ol>
+ </nav>
+ )}
+ </>
+ );
+};
+
+export default Breadcrumb;
diff --git a/src/components/Layouts/Layout.tsx b/src/components/Layouts/Layout.tsx
index 7f8ab9d..8c5570f 100644
--- a/src/components/Layouts/Layout.tsx
+++ b/src/components/Layouts/Layout.tsx
@@ -1,7 +1,8 @@
-import { ReactNode } from 'react';
+import { ReactElement, ReactNode } from 'react';
import Footer from '@components/Footer/Footer';
import Header from '@components/Header/Header';
import Main from '@components/Main/Main';
+import Breadcrumb from '@components/Breadcrumb/Breadcrumb';
const Layout = ({
children,
@@ -19,4 +20,15 @@ const Layout = ({
);
};
+export const getLayout = (page: ReactElement) => {
+ const pageTitle: string = page.props.breadcrumbTitle;
+
+ return (
+ <Layout>
+ <Breadcrumb pageTitle={pageTitle} />
+ {page}
+ </Layout>
+ );
+};
+
export default Layout;
diff --git a/src/pages/404.tsx b/src/pages/404.tsx
index 903a386..6b6fbf5 100644
--- a/src/pages/404.tsx
+++ b/src/pages/404.tsx
@@ -1,4 +1,4 @@
-import Layout from '@components/Layouts/Layout';
+import { getLayout } from '@components/Layouts/Layout';
import { seo } from '@config/seo';
import { t, Trans } from '@lingui/macro';
import { NextPageWithLayout } from '@ts/types/app';
@@ -6,7 +6,6 @@ import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticProps, GetStaticPropsContext } from 'next';
import Head from 'next/head';
import Link from 'next/link';
-import { ReactElement } from 'react';
const error404: NextPageWithLayout = () => {
return (
@@ -32,7 +31,7 @@ const error404: NextPageWithLayout = () => {
);
};
-error404.getLayout = (page: ReactElement) => <Layout>{page}</Layout>;
+error404.getLayout = getLayout;
export const getStaticProps: GetStaticProps = async (
context: GetStaticPropsContext
@@ -42,8 +41,11 @@ export const getStaticProps: GetStaticProps = async (
process.env.NODE_ENV === 'production'
);
+ const breadcrumbTitle = t`Error`;
+
return {
props: {
+ breadcrumbTitle,
translation,
},
};
diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx
index bb11220..621b2e2 100644
--- a/src/pages/article/[slug].tsx
+++ b/src/pages/article/[slug].tsx
@@ -1,6 +1,6 @@
import CommentForm from '@components/CommentForm/CommentForm';
import CommentsList from '@components/CommentsList/CommentsList';
-import Layout from '@components/Layouts/Layout';
+import { getLayout } from '@components/Layouts/Layout';
import PostFooter from '@components/PostFooter/PostFooter';
import PostHeader from '@components/PostHeader/PostHeader';
import { t } from '@lingui/macro';
@@ -11,7 +11,6 @@ import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from 'next';
import Head from 'next/head';
import { ParsedUrlQuery } from 'querystring';
-import { ReactElement } from 'react';
const SingleArticle: NextPageWithLayout<ArticleProps> = ({ post }) => {
const {
@@ -53,9 +52,7 @@ const SingleArticle: NextPageWithLayout<ArticleProps> = ({ post }) => {
);
};
-SingleArticle.getLayout = function getLayout(page: ReactElement) {
- return <Layout>{page}</Layout>;
-};
+SingleArticle.getLayout = getLayout;
interface PostParams extends ParsedUrlQuery {
slug: string;
@@ -70,9 +67,11 @@ export const getStaticProps: GetStaticProps = async (
);
const { slug } = context.params as PostParams;
const post = await getPostBySlug(slug);
+ const breadcrumbTitle = post.title;
return {
props: {
+ breadcrumbTitle,
post,
translation,
},
diff --git a/src/pages/blog/index.tsx b/src/pages/blog/index.tsx
index 7d34763..23013bd 100644
--- a/src/pages/blog/index.tsx
+++ b/src/pages/blog/index.tsx
@@ -1,8 +1,7 @@
-import { ReactElement } from 'react';
import { GetStaticProps } from 'next';
import Head from 'next/head';
import { t } from '@lingui/macro';
-import Layout from '@components/Layouts/Layout';
+import { getLayout } from '@components/Layouts/Layout';
import { seo } from '@config/seo';
import { config } from '@config/website';
import { NextPageWithLayout } from '@ts/types/app';
@@ -62,9 +61,7 @@ const Blog: NextPageWithLayout<BlogPageProps> = ({ fallback }) => {
);
};
-Blog.getLayout = function getLayout(page: ReactElement) {
- return <Layout>{page}</Layout>;
-};
+Blog.getLayout = getLayout;
export const getStaticProps: GetStaticProps = async (context) => {
const translation = await loadTranslation(
@@ -72,9 +69,11 @@ export const getStaticProps: GetStaticProps = async (context) => {
process.env.NODE_ENV === 'production'
);
const data = await getPublishedPosts({ first: config.postsPerPage });
+ const breadcrumbTitle = t`Blog`;
return {
props: {
+ breadcrumbTitle,
fallback: {
'/api/posts': data,
},
diff --git a/src/pages/contact.tsx b/src/pages/contact.tsx
index ff60188..8e6de7a 100644
--- a/src/pages/contact.tsx
+++ b/src/pages/contact.tsx
@@ -1,6 +1,6 @@
import { ButtonSubmit } from '@components/Buttons';
import { Form, FormItem, Input, TextArea } from '@components/Form';
-import Layout from '@components/Layouts/Layout';
+import { getLayout } from '@components/Layouts/Layout';
import { seo } from '@config/seo';
import { t } from '@lingui/macro';
import { sendMail } from '@services/graphql/mutations';
@@ -8,7 +8,7 @@ import { NextPageWithLayout } from '@ts/types/app';
import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticProps, GetStaticPropsContext } from 'next';
import Head from 'next/head';
-import { FormEvent, ReactElement, useState } from 'react';
+import { FormEvent, useState } from 'react';
const ContactPage: NextPageWithLayout = () => {
const [name, setName] = useState('');
@@ -110,7 +110,7 @@ const ContactPage: NextPageWithLayout = () => {
);
};
-ContactPage.getLayout = (page: ReactElement) => <Layout>{page}</Layout>;
+ContactPage.getLayout = getLayout;
export const getStaticProps: GetStaticProps = async (
context: GetStaticPropsContext
@@ -120,8 +120,11 @@ export const getStaticProps: GetStaticProps = async (
process.env.NODE_ENV === 'production'
);
+ const breadcrumbTitle = t`Contact`;
+
return {
props: {
+ breadcrumbTitle,
translation,
},
};
diff --git a/src/pages/cv.tsx b/src/pages/cv.tsx
index 150e29a..de63ec6 100644
--- a/src/pages/cv.tsx
+++ b/src/pages/cv.tsx
@@ -1,4 +1,4 @@
-import Layout from '@components/Layouts/Layout';
+import { getLayout } from '@components/Layouts/Layout';
import { seo } from '@config/seo';
import { getPageByUri } from '@services/graphql/queries';
import { NextPageWithLayout } from '@ts/types/app';
@@ -6,7 +6,6 @@ import { PageProps } from '@ts/types/pages';
import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticProps, GetStaticPropsContext } from 'next';
import Head from 'next/head';
-import { ReactElement } from 'react';
const CV: NextPageWithLayout<PageProps> = ({ page }) => {
return (
@@ -26,7 +25,7 @@ const CV: NextPageWithLayout<PageProps> = ({ page }) => {
);
};
-CV.getLayout = (page: ReactElement) => <Layout>{page}</Layout>;
+CV.getLayout = getLayout;
export const getStaticProps: GetStaticProps = async (
context: GetStaticPropsContext
@@ -36,9 +35,11 @@ export const getStaticProps: GetStaticProps = async (
process.env.NODE_ENV === 'production'
);
const page = await getPageByUri('/cv/');
+ const breadcrumbTitle = page.title;
return {
props: {
+ breadcrumbTitle,
page,
translation,
},
diff --git a/src/pages/mentions-legales.tsx b/src/pages/mentions-legales.tsx
index c90b8d6..6155132 100644
--- a/src/pages/mentions-legales.tsx
+++ b/src/pages/mentions-legales.tsx
@@ -1,4 +1,4 @@
-import Layout from '@components/Layouts/Layout';
+import { getLayout } from '@components/Layouts/Layout';
import { seo } from '@config/seo';
import { getPageByUri } from '@services/graphql/queries';
import { NextPageWithLayout } from '@ts/types/app';
@@ -6,7 +6,6 @@ import { PageProps } from '@ts/types/pages';
import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticProps, GetStaticPropsContext } from 'next';
import Head from 'next/head';
-import { ReactElement } from 'react';
const LegalNotice: NextPageWithLayout<PageProps> = ({ page }) => {
return (
@@ -26,7 +25,7 @@ const LegalNotice: NextPageWithLayout<PageProps> = ({ page }) => {
);
};
-LegalNotice.getLayout = (page: ReactElement) => <Layout>{page}</Layout>;
+LegalNotice.getLayout = getLayout;
export const getStaticProps: GetStaticProps = async (
context: GetStaticPropsContext
@@ -36,9 +35,11 @@ export const getStaticProps: GetStaticProps = async (
process.env.NODE_ENV === 'production'
);
const page = await getPageByUri('/mentions-legales/');
+ const breadcrumbTitle = page.title;
return {
props: {
+ breadcrumbTitle,
page,
translation,
},
diff --git a/src/pages/recherche/index.tsx b/src/pages/recherche/index.tsx
index 6de5816..b39d3f9 100644
--- a/src/pages/recherche/index.tsx
+++ b/src/pages/recherche/index.tsx
@@ -1,5 +1,5 @@
import { Button } from '@components/Buttons';
-import Layout from '@components/Layouts/Layout';
+import { getLayout } from '@components/Layouts/Layout';
import PostsList from '@components/PostsList/PostsList';
import { config } from '@config/website';
import { t } from '@lingui/macro';
@@ -10,7 +10,7 @@ import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticProps } from 'next';
import Head from 'next/head';
import { useRouter } from 'next/router';
-import { ReactElement, useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import useSWRInfinite from 'swr/infinite';
const Search: NextPageWithLayout = () => {
@@ -92,7 +92,7 @@ const Search: NextPageWithLayout = () => {
);
};
-Search.getLayout = (page: ReactElement) => <Layout>{page}</Layout>;
+Search.getLayout = getLayout;
export const getStaticProps: GetStaticProps = async (context) => {
const translation = await loadTranslation(
@@ -100,8 +100,11 @@ export const getStaticProps: GetStaticProps = async (context) => {
process.env.NODE_ENV === 'production'
);
+ const breadcrumbTitle = t`Search`;
+
return {
props: {
+ breadcrumbTitle,
translation,
},
};
diff --git a/src/pages/sujet/[slug].tsx b/src/pages/sujet/[slug].tsx
index 4dc4e9b..f6571e1 100644
--- a/src/pages/sujet/[slug].tsx
+++ b/src/pages/sujet/[slug].tsx
@@ -1,4 +1,4 @@
-import Layout from '@components/Layouts/Layout';
+import { getLayout } from '@components/Layouts/Layout';
import PostPreview from '@components/PostPreview/PostPreview';
import { t } from '@lingui/macro';
import { NextPageWithLayout } from '@ts/types/app';
@@ -7,7 +7,6 @@ import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from 'next';
import Image from 'next/image';
import { ParsedUrlQuery } from 'querystring';
-import { ReactElement } from 'react';
import styles from '@styles/pages/Subject.module.scss';
import {
getAllSubjectsSlug,
@@ -57,9 +56,7 @@ const Subject: NextPageWithLayout<SubjectProps> = ({ subject }) => {
);
};
-Subject.getLayout = function getLayout(page: ReactElement) {
- return <Layout>{page}</Layout>;
-};
+Subject.getLayout = getLayout;
interface PostParams extends ParsedUrlQuery {
slug: string;
@@ -74,9 +71,11 @@ export const getStaticProps: GetStaticProps = async (
);
const { slug } = context.params as PostParams;
const subject = await getSubjectBySlug(slug);
+ const breadcrumbTitle = subject.title;
return {
props: {
+ breadcrumbTitle,
subject,
translation,
},
diff --git a/src/pages/thematique/[slug].tsx b/src/pages/thematique/[slug].tsx
index 2e7c346..51506e5 100644
--- a/src/pages/thematique/[slug].tsx
+++ b/src/pages/thematique/[slug].tsx
@@ -1,4 +1,4 @@
-import Layout from '@components/Layouts/Layout';
+import { getLayout } from '@components/Layouts/Layout';
import PostPreview from '@components/PostPreview/PostPreview';
import { t } from '@lingui/macro';
import { NextPageWithLayout } from '@ts/types/app';
@@ -6,7 +6,6 @@ import { ThematicProps } from '@ts/types/taxonomies';
import { loadTranslation } from '@utils/helpers/i18n';
import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from 'next';
import { ParsedUrlQuery } from 'querystring';
-import { ReactElement } from 'react';
import styles from '@styles/pages/Thematic.module.scss';
import {
getAllThematicsSlug,
@@ -39,9 +38,7 @@ const Thematic: NextPageWithLayout<ThematicProps> = ({ thematic }) => {
);
};
-Thematic.getLayout = function getLayout(page: ReactElement) {
- return <Layout>{page}</Layout>;
-};
+Thematic.getLayout = getLayout;
interface PostParams extends ParsedUrlQuery {
slug: string;
@@ -56,9 +53,11 @@ export const getStaticProps: GetStaticProps = async (
);
const { slug } = context.params as PostParams;
const thematic = await getThematicBySlug(slug);
+ const breadcrumbTitle = thematic.title;
return {
props: {
+ breadcrumbTitle,
thematic,
translation,
},