- Published on
- ·9 min read
Next.js 블로그에 Tocbot 추가하기
개요
글을 읽을 때 목차가 있으면 좋습니다. 그리고 목차가 계속 옆에 보이면 더 좋겠다고 생각했습니다.
그래서 Tocbot 라이브러리를 이용하여 목차가 따라다닐 수 있도록 추가했습니다.
참고로 Tailwind CSS Blog Starter 템플릿에는 컨텐츠 내에 보여지는 목차가 있습니다.
이와는 별도로 Tocbot을 이용하여 우측에 고정된 목차를 추가하였습니다.
최종적으로,
1280px 이상
의 화면에서는 컨텐츠 내에 보여지는 목차가 숨겨지고, 우측에 고정된 목차가 보여집니다.1280px 미만
의 화면에서는 컨텐츠 내에 보여지는 목차가 보여지고, 우측에 고정된 목차는 숨겨집니다.
아래 이미지에서 좌측에 보여지는 목차는 1280 이상일 때, 우측에는 1280 미만일때입니다.
Tocbot 추가
Tocbot Install
npm install --save tocbot
Tocbot 컴포넌트 추가
/components/Tocbot.js 추가: 내용은 아래와 같습니다.
import { useEffect } from 'react'
import tocbot from 'tocbot'
const TocSide = () => {
useEffect(() => {
tocbot.init({
tocSelector: '.toc',
contentSelector: 'article',
headingSelector: 'h2, h3',
ignoreSelector: '.toc-ignore',
})
return () => tocbot.destroy()
}, [])
return (
<div>
<div className="lg-block hidden pt-6 pb-10 text-gray-500 dark:text-gray-400 xl:border-b xl:border-gray-200 xl:pt-11 xl:dark:border-gray-700">
<span className="font-bold text-gray-600 dark:text-gray-300">Table of Contents</span>
<div className="toc"></div>
</div>
</div>
)
}
export default TocSide
hidden
으로 기본은 숨김이고,lg-block
으로 1280px 이상의 화면에서 보여지도록 합니다.lg-block
는 아래 tocbot.css에서 정의합니다.
Tocbot CSS 추가
https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.18.2/tocbot.css에서 기본 css는 가져왔습니다. 거기에 추가로 몇 가지를 수정하였습니다.
/css/tocbot.css
추가: 내용은 아래와 같습니다.
.toc {
overflow-y: auto;
}
.toc > .toc-list {
overflow: hidden;
position: relative;
font-size: 0.9em;
margin-top: 16px;
}
.toc > .toc-list li {
list-style: none;
line-height: 2em;
}
.js-toc {
overflow-y: hidden;
}
.toc-list {
margin: 0;
padding-left: 10px;
}
a.toc-link {
/*color:currentColor;*/
height: 100%;
}
.is-collapsible {
max-height: 1000px;
overflow: hidden;
transition: all 300ms ease-in-out;
}
.is-collapsed {
max-height: 0;
}
.is-position-fixed {
position: fixed !important;
top: 0;
}
.is-active-link {
font-weight: 700;
color: #37c3b3;
}
.toc-link::before {
background-color: #e5e5e5;
content: ' ';
display: inline-block;
height: inherit;
left: 0;
margin-top: -1px;
position: absolute;
width: 2px;
}
.is-active-link::before {
background-color: #37c3b3;
}
/*
.toc-link:hover {
color: white;
}
*/
@media (min-width: 1280px) {
.lg-block {
display: block;
}
}
@media (max-width: 1280px) {
.sm-show {
display: block;
}
}
.lg-block
으로 1280px 이상의 화면에서 보여지도록 합니다..sm-show
으로 1280px 미만의 화면에서 보여지도록 합니다.
Tocbot을 우측에 보여줄 Layout 추가
/layouts/PostToc.js
추가: 내용은 아래와 같습니다.
import PageTitle from '@/components/PageTitle'
import SectionContainer from '@/components/SectionContainer'
import { BlogSEO } from '@/components/SEO'
import Tag from '@/components/Tag'
import siteMetadata from '@/data/siteMetadata'
import Comments from '@/components/comments'
import ScrollTopAndComment from '@/components/ScrollTopAndComment'
import TocSide from '@/components/Tocbot'
const postDateTemplate = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }
export default function PostLayout({ frontMatter, authorDetails, children }) {
const { slug, date, title, tags } = frontMatter
return (
<SectionContainer>
<BlogSEO
url={`${siteMetadata.siteUrl}/blog/${slug}`}
authorDetails={authorDetails}
{...frontMatter}
/>
<ScrollTopAndComment />
<article>
<div className="xl:divide-y xl:divide-gray-200 xl:dark:divide-gray-700">
<header className="pt-6 xl:pb-6">
<div className="space-y-1 text-center">
<dl className="space-y-10">
<div>
<dt className="sr-only">Published on</dt>
<dd className="text-base font-medium leading-6 text-gray-500 dark:text-gray-400">
<time dateTime={date}>
{new Date(date).toLocaleDateString(siteMetadata.locale, postDateTemplate)}
</time>
</dd>
</div>
</dl>
<div>
<PageTitle>{title}</PageTitle>
</div>
</div>
</header>
<div
className="divide-y divide-gray-200 pb-8 dark:divide-gray-700 xl:grid xl:grid-cols-4 xl:gap-x-6 xl:divide-y-0"
style={{ gridTemplateRows: 'auto 1fr' }}
>
<div className="divide-y divide-gray-200 dark:divide-gray-700 xl:col-span-3 xl:row-span-2 xl:pb-0">
<div className="prose max-w-none pt-10 pb-8 dark:prose-dark">{children}</div>
<Comments frontMatter={frontMatter} />
</div>
<footer style={{ position: 'sticky', top: '32px' }}>
<TocSide />
<div className="divide-gray-200 text-sm font-medium leading-5 dark:divide-gray-700 xl:col-start-1 xl:row-start-2 xl:divide-y">
{tags && (
<div className="py-4 xl:py-8">
<h2 className="toc-ignore text-xs uppercase tracking-wide text-gray-500 dark:text-gray-400">
Tags
</h2>
<div className="flex flex-wrap">
{tags.map((tag) => (
<Tag key={tag} text={tag} />
))}
</div>
</div>
)}
</div>
</footer>
</div>
</div>
</article>
</SectionContainer>
)
}
Tocbot 적용 위한 수정
TocInline 컴포넌트 수정
Tailwind CSS Blog 템플릿에 있는 기본 TocInline 컴포넌트를 수정합니다.
detail
태그에className="sm-show hidden"
을 추가합니다.
(1280px 미만의 화면에서만 보여지도록 합니다.)asDisclosure
로 사용할 경우 적용되며, 그렇지 않을 경우 ul 태그에 적용하시면 될겁니다.
<details open className="sm-show hidden">
<summary className="ml-6 pt-2 pb-2 text-xl font-bold">Table of Contents</summary>
<div className="ml-6">{tocList}</div>
</details>
css 적용되도록 수정
/pages/\_app.js
에tocbot.css
import
import '@/css/tocbot.css'
글 작성시 레이아웃 적용
글 마다 적용하려면 frontMatter에 layout을 추가하고, 해당 layout을 적용하면 됩니다.
---
...생략...
layout: PostToc
---
또는 모든 글에 기본으로 적용하려면 /pages/blog/[...slug].js
파일의 DEFAULT_LAYOUT
을 수정합니다.
const DEFAULT_LAYOUT = 'PostToc'
- layout 파일 추가의 경우 module을 못 찾아 오류가 납니다. 개발 서버 중지 후 재시작 해줍니다 (
npm start
) - 컨텐츠 내에 보여지는 목차는 따로
<TocInline />
컴포넌트를 내용에 추가해주어야 합니다. 없어도 무방합니다. 다만 1280px 미만의 화면에서는 목차가 보이지 않을 뿐입니다.
<TOCInline toc={props.toc} exclude="Overview" asDisclosure />
마무리
다음글, 이전글, 작성자 정보 등 제 기준에서 불필요 한 부분들은 제거하였습니다. 필요한 내용들은 PostLayout
을 참고하여 추가하시면 됩니다.
코드는 add_tocbot 브랜치 또는 commit history로 확인하실 수 있습니다.
태그와 연관된 글
2023. 09. 27.
Next.js - 블로그 다국어(i18n)로 만들기 Part 42023. 09. 26.
Next.js - 블로그 다국어(i18n)로 만들기 Part 32023. 09. 25.
Next.js - 블로그 다국어(i18n)로 만들기 Part 22023. 09. 24.
Next.js - 블로그 다국어(i18n)로 만들기 Part 12023. 09. 19.
Next.js - 다국어(i18n) 설정 및 static html로 내보내기 Part 2