#8 목차(TOC)와 breadcrumb 만들기

글을 더 편리하게 볼 수 있도록 만들어보자


Table Of Contents


들어가기


  • 포스트에 목차가 있으면 좋을 것 같다. Velog나 Notion에도 이런 기능이 있어서 유용하게 이용하고 있는데, 여기 블로그에도 추가하면 좋지 않을까?
  • 그리고 노션처럼 포스트가 중첩되는 구조다 보니 특정 페이지에 들어간 경우에 부모 페이지로 나갈 수 있는 길이 없어 불편했다. breadcrumb를 만들어서 부모 페이지가 무엇인지 알 수 있게 해보자.

remark-toc 설치하고 적용하기


현재 블로그는 react-markdown을 이용해 마크다운 파일을 파싱, 렌더하고 있다. remark-toc 라이브러리를 import해서 prop에 전달해 주는 것만으로 쉽게 TOC를 만들 수 있다.

사실 파싱 결과를 받아서 내가 직접 헤딩만 분리하는 작업을 수행할 수도 있을 텐데, 지금은 시간이 없으니 그냥 구현체를 사용하자...

npm install remark-toc

로 설치해준 다음,

import remarkToc from "remark-toc";

처럼 import해준다.

그리고 기존에 사용하던 <ReactMarkdown/> 태그 안에

<ReactMarkdown remarkPlugins={[ [remarkMath], [remarkGfm], [remarkToc, { tight: true, maxDepth: 3, ordered: true }], ]} rehypePlugins={[rehypeKatex]} components={components} > {"# Table of Contents\n" + content} </ReactMarkdown>

remarkPlugins에 prop으로 전달해 주면 된다.

기본적으로 reamck-toc

Table of Contents

라는 헤딩이 있으면 해당 헤딩 아래로 목차를 렌더링해준다.

나는 모든 글의 맨 위에 목차를 추가해 주고 싶으므로 content 앞에 Table of Contents라는 헤딩을 넣어줬다.

toc result

그러면 글 처음에 이렇게 목차가 생긴다.

스타일링은 내가 적용한 ol, ul, li를 그대로 사용한다. 원래는 ol, ul, li, p 태그 등에 임의로 패딩/마진을 좀 주고 있었는데 toc가 렌더되고 나니 너무 안 예뻐서 스타일을 조금 손봤다.

옵션

  • 참고로, [remarkToc, { tight: false }]처럼 tight를 주면 각 아이템 주변에 조금의 여백이 생긴다. 기본값은 true이다.
  • 또한 maxDepth 옵션은 h1부터, h몇까지를 목차에 포함시킬 지 선택할 수 있다. 나는 { maxDepth: 3 }으로, h3까지만 목차에 포함시킨다. h4부터는 헤딩 스타일은 적용되어도 목차에는 보이지 않는다! 기본적으로는 h6까지 모두 포함한다.
  • ordered 옵션은 목차를 렌더할 때 ol을 사용할지, ul을 사용할지를 결정한다. 기본값은 false이다.
  • 이외에도 목차의 헤딩을 바꾸는 옵션, 헤딩의 내용에 따라서 스킵하는 옵션 등이 있다.
  • GitHub에서 찾아보자.

Breadcrumb 만들기


우선 breadcrumb이 무엇인가 하면, 웹 사이트에서 현재 위치를 표시해주는 요소이다. 마치 빵 부스러기를 따라가듯이 사용자가 웹 사이트의 어디에 있는지를 시각적으로 표시해 준다.

홈 > 1차 카테고리 > 2차 카테고리 > 현재 페이지

이런 식으로 표시해주는 요소를 생각하면 된다.

현재 블로그는 노션처럼 페이지 아래 페이지 아래 페이지... 아래 페이지가 있을 수 있기 때문에 현재 위치를 알기 어렵다. 따라서 breadcrumb을 추가하고자 한다.

const breadcrumbData = useMemo(() => { return getAncestors({ categoryData: plainCategoryData, id }); }, [id]);

이렇게 현재 게시글의 id가 바뀔 때마다, breadcrumb 데이터를 구했다. plainCategoryData는 아래와 같은 타입을 가지고 있어서 id로 접근이 가능하다. 만약

getAncestors 함수를 통해 현재 id를 가지는 포스트로부터 부모가 null인 포스트에 이를 때까지 탐색을 하게 된다. 그리고 해당 데이터를 배열로 저장한다.

breadcrumb

말 줄이기

모바일의 경우에는 breadcrumb이 전부 들어갈 길이가 없을 수도 있다. css를 이용하여 텍스트를 줄여 보자.

overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis",

텍스트에 이런 스타일을 적용시키면 1줄을 넘어가는 텍스트는 자동으로 ... 처리된다.

final

모바일로 봐도 꽤 잘 보인다!