#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라는 헤딩을 넣어줬다.
그러면 글 처음에 이렇게 목차가 생긴다.
스타일링은 내가 적용한 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을 추가하고자 한다.
breadcrumb 데이터 구하기
const breadcrumbData = useMemo(() => { return getAncestors({ categoryData: plainCategoryData, id }); }, [id]);
이렇게 현재 게시글의 id가 바뀔 때마다, breadcrumb 데이터를 구했다. plainCategoryData
는 아래와 같은 타입을 가지고 있어서 id로 접근이 가능하다. 만약
getAncestors
함수를 통해 현재 id를 가지는 포스트로부터 부모가 null인 포스트에 이를 때까지 탐색을 하게 된다. 그리고 해당 데이터를 배열로 저장한다.
말 줄이기
모바일의 경우에는 breadcrumb이 전부 들어갈 길이가 없을 수도 있다. css를 이용하여 텍스트를 줄여 보자.
overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis",
텍스트에 이런 스타일을 적용시키면 1줄을 넘어가는 텍스트는 자동으로 ... 처리된다.
모바일로 봐도 꽤 잘 보인다!