From 926e1df1e9a7de29134293fe2306c9d9ecb594a6 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Tue, 21 Dec 2021 15:20:17 +0100 Subject: chore: add a table of contents --- src/components/ToC/ToC.tsx | 31 +++++++++++++++++++++++++++++++ src/pages/article/[slug].tsx | 2 ++ src/pages/cv.tsx | 12 ++++++++++-- src/pages/mentions-legales.tsx | 12 ++++++++++-- src/ts/types/app.ts | 7 +++++++ src/utils/hooks/useHeadingsTree.tsx | 8 +------- 6 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 src/components/ToC/ToC.tsx diff --git a/src/components/ToC/ToC.tsx b/src/components/ToC/ToC.tsx new file mode 100644 index 0000000..e7aafa5 --- /dev/null +++ b/src/components/ToC/ToC.tsx @@ -0,0 +1,31 @@ +import { t } from '@lingui/macro'; +import { Heading } from '@ts/types/app'; +import { slugify } from '@utils/helpers/slugify'; +import useHeadingsTree from '@utils/hooks/useHeadingsTree'; + +const ToC = () => { + const headingsTree = useHeadingsTree('article'); + const title = t`Table of contents`; + + const getItems = (headings: Heading[]) => { + return headings.map((heading) => { + if (heading.id === slugify(title)) return; + + return ( +
  • + {heading.title} + {heading.children.length > 0 &&
      {getItems(heading.children)}
    } +
  • + ); + }); + }; + + return ( + <> +

    {title}

    +
      {getItems(headingsTree)}
    + + ); +}; + +export default ToC; diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx index 621b2e2..1fa65fa 100644 --- a/src/pages/article/[slug].tsx +++ b/src/pages/article/[slug].tsx @@ -3,6 +3,7 @@ import CommentsList from '@components/CommentsList/CommentsList'; import { getLayout } from '@components/Layouts/Layout'; import PostFooter from '@components/PostFooter/PostFooter'; import PostHeader from '@components/PostHeader/PostHeader'; +import ToC from '@components/ToC/ToC'; import { t } from '@lingui/macro'; import { getAllPostsSlug, getPostBySlug } from '@services/graphql/queries'; import { NextPageWithLayout } from '@ts/types/app'; @@ -39,6 +40,7 @@ const SingleArticle: NextPageWithLayout = ({ post }) => { title={title} thematics={thematics} /> +
    diff --git a/src/pages/cv.tsx b/src/pages/cv.tsx index de63ec6..44d943c 100644 --- a/src/pages/cv.tsx +++ b/src/pages/cv.tsx @@ -1,4 +1,5 @@ import { getLayout } from '@components/Layouts/Layout'; +import ToC from '@components/ToC/ToC'; import { seo } from '@config/seo'; import { getPageByUri } from '@services/graphql/queries'; import { NextPageWithLayout } from '@ts/types/app'; @@ -17,9 +18,16 @@ const CV: NextPageWithLayout = ({ page }) => {

    {page.title}

    -
    + {page.content && ( +
    + )}
    -
    + +
    ); diff --git a/src/pages/mentions-legales.tsx b/src/pages/mentions-legales.tsx index 6155132..41e9a0c 100644 --- a/src/pages/mentions-legales.tsx +++ b/src/pages/mentions-legales.tsx @@ -1,4 +1,5 @@ import { getLayout } from '@components/Layouts/Layout'; +import ToC from '@components/ToC/ToC'; import { seo } from '@config/seo'; import { getPageByUri } from '@services/graphql/queries'; import { NextPageWithLayout } from '@ts/types/app'; @@ -17,9 +18,16 @@ const LegalNotice: NextPageWithLayout = ({ page }) => {

    {page.title}

    -
    + {page.content && ( +
    + )}
    -
    + +
    ); diff --git a/src/ts/types/app.ts b/src/ts/types/app.ts index ba28416..e1d8917 100644 --- a/src/ts/types/app.ts +++ b/src/ts/types/app.ts @@ -76,6 +76,13 @@ export type Dates = { update: string; }; +export type Heading = { + depth: number; + id: string; + children: Heading[]; + title: string; +}; + export type PageInfo = { endCursor: string; hasNextPage: boolean; diff --git a/src/utils/hooks/useHeadingsTree.tsx b/src/utils/hooks/useHeadingsTree.tsx index 8bb70c8..94d3b4b 100644 --- a/src/utils/hooks/useHeadingsTree.tsx +++ b/src/utils/hooks/useHeadingsTree.tsx @@ -1,13 +1,7 @@ +import { Heading } from '@ts/types/app'; import { slugify } from '@utils/helpers/slugify'; import { useCallback, useEffect, useMemo, useState } from 'react'; -type Heading = { - depth: number; - id: string; - children: Heading[]; - title: string; -}; - const useHeadingsTree = (wrapper: string) => { const [headingsTree, setHeadingsTree] = useState([]); const depths = useMemo(() => ['h2', 'h3', 'h4', 'h5', 'h6'], []); -- cgit v1.2.3