diff --git a/app/entities/post/detail/PostBody.tsx b/app/entities/post/detail/PostBody.tsx
index 6cd5d34..dda1532 100644
--- a/app/entities/post/detail/PostBody.tsx
+++ b/app/entities/post/detail/PostBody.tsx
@@ -1,6 +1,7 @@
'use client';
import LoadingIndicator from '@/app/entities/common/Loading/LoadingIndicator';
import MDEditor from '@uiw/react-md-editor';
+import PostTOC from '@/app/entities/post/detail/PostTOC';
interface Props {
content: string;
@@ -9,23 +10,28 @@ interface Props {
const PostBody = ({ content, loading }: Props) => {
return (
-
+
{loading ? (
) : (
-
+ <>
+
+
+ >
)}
);
diff --git a/app/entities/post/detail/PostTOC.tsx b/app/entities/post/detail/PostTOC.tsx
new file mode 100644
index 0000000..8039f90
--- /dev/null
+++ b/app/entities/post/detail/PostTOC.tsx
@@ -0,0 +1,60 @@
+import Link from 'next/link';
+
+const PostTOC = ({ postContent }: { postContent: string }) => {
+ const parseHeadings = (content: string) => {
+ const headings = content.match(/#{1,6} .+/g);
+
+ return (headings ?? []).map((heading: string) => ({
+ id: heading.replace(/#/g, '').trim(),
+ type: heading.lastIndexOf('#') + 1,
+ title: heading.replace(/#/g, '').trim(),
+ }));
+ };
+
+ return (
+
+
📌 Table of Contents
+
+ {parseHeadings(postContent).map((heading) => {
+ const href =
+ `#${heading.id
+ .toLowerCase()
+ .replaceAll('.', '')
+ .replaceAll(/[^a-zA-Z0-9가-힣]/g, '-')
+ .replaceAll(/-+/g, '-')
+ .replaceAll(/^-|-$/g, '')}` || '';
+ return (
+ -
+ {
+ e.preventDefault();
+ document.querySelector(href)?.scrollIntoView({
+ behavior: 'smooth',
+ });
+ }}
+ href={`#${heading.id
+ .toLowerCase()
+ .replaceAll('.', '')
+ .replaceAll(/[^a-zA-Z0-9가-힣]/g, '-')
+ .replaceAll(/-+/g, '-')
+ .replaceAll(/^-|-$/g, '')}`}
+ >
+ {'∟ ' + heading.title}
+
+
+ );
+ })}
+
+
+ );
+};
+
+export default PostTOC;
diff --git a/app/globals.css b/app/globals.css
index e0747b8..33c5e7c 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -49,6 +49,10 @@ article.post li {
list-style: circle;
}
+.post-toc ul > li {
+ list-style: none;
+}
+
article.post h1,
article.post h2,
article.post h3,
@@ -73,12 +77,6 @@ article.post h3 {
margin-bottom: 1rem;
}
-article.post h4 {
- font-size: 1rem;
- font-weight: bold;
- margin-bottom: 1rem;
-}
-
/* Footer Style */
footer {
diff --git a/app/posts/[slug]/page.tsx b/app/posts/[slug]/page.tsx
index a8124fb..7891792 100644
--- a/app/posts/[slug]/page.tsx
+++ b/app/posts/[slug]/page.tsx
@@ -6,6 +6,7 @@ import { Metadata } from 'next';
import dbConnect from '@/app/lib/dbConnect';
import Post from '@/app/models/Post';
import PostJSONLd from '@/app/entities/post/detail/PostJSONLd';
+import PostTOC from '@/app/entities/post/detail/PostTOC';
async function getPostDetail(slug: string) {
await dbConnect();
diff --git a/app/public/googlee045d7c5db6fc750.html b/app/public/googlee045d7c5db6fc750.html
new file mode 100644
index 0000000..40825bd
--- /dev/null
+++ b/app/public/googlee045d7c5db6fc750.html
@@ -0,0 +1 @@
+google-site-verification: googlee045d7c5db6fc750.html
\ No newline at end of file