diff --git a/src/components/ui/Markdown/overrides/headings/headings.tsx b/src/components/ui/Markdown/overrides/headings/headings.tsx
index 30b45e2..c6c5669 100644
--- a/src/components/ui/Markdown/overrides/headings/headings.tsx
+++ b/src/components/ui/Markdown/overrides/headings/headings.tsx
@@ -1,5 +1,6 @@
import React from "react";
+import { removeSpecialCharacters } from "@utils/getToc";
import { getChildrenText } from "@utils/getChildrenText";
interface IProps {
@@ -9,7 +10,7 @@ interface IProps {
const Heading = ({ children, tagname }: IProps) => {
const text = getChildrenText(children);
- const id = `${tagname}_${text.replace(/\s/g, "_").trim()}`;
+ const id = removeSpecialCharacters(text);
return React.createElement(tagname, { id }, children);
};
diff --git a/src/components/ui/client/post/PostContent/Toc/item.tsx b/src/components/ui/client/post/PostContent/Toc/item.tsx
index be9418d..fb7a090 100644
--- a/src/components/ui/client/post/PostContent/Toc/item.tsx
+++ b/src/components/ui/client/post/PostContent/Toc/item.tsx
@@ -1,5 +1,7 @@
import React, { memo } from "react";
+import NextLink from "next/link";
+
import { IToc } from "@/types/base";
interface IProps {
@@ -18,14 +20,15 @@ const TocItem = ({ item, isActive, onClick }: IProps) => {
style={{ paddingLeft: `${level * 0.8}rem` }}
className={`${className} w-full [&.active>a]:text-effect1`}
>
-
{text}
-
+
);
};
diff --git a/src/hooks/useIntersectionObserver.ts b/src/hooks/useIntersectionObserver.ts
index 98b3ce0..b4b6b47 100644
--- a/src/hooks/useIntersectionObserver.ts
+++ b/src/hooks/useIntersectionObserver.ts
@@ -1,5 +1,7 @@
import { useEffect, useRef } from "react";
+import { MARKDOWN_HEADING_SELECTOR } from "@utils/constant/toc";
+
interface IHeadingElement {
[key: string]: IntersectionObserverEntry;
}
@@ -44,7 +46,7 @@ export const useIntersectionObserver = (
const observer = new IntersectionObserver(callback, { rootMargin: "-72px 0px -90% 0px" });
- const headingElements = Array.from(document.querySelectorAll("h1, h2, h3, h4, h5, h6"));
+ const headingElements = Array.from(document.querySelectorAll(MARKDOWN_HEADING_SELECTOR));
headingElements.forEach((element) => observer.observe(element));
diff --git a/src/hooks/useTocEvent.ts b/src/hooks/useTocEvent.ts
index 7f293b2..211093f 100644
--- a/src/hooks/useTocEvent.ts
+++ b/src/hooks/useTocEvent.ts
@@ -1,20 +1,21 @@
import { useEffect } from "react";
+import { MARKDOWN_HEADING_SELECTOR } from "@utils/constant/toc";
import { IToc } from "@/types/base";
const useTocEvent = (toc: IToc[]) => {
const scroll = (id: string, behavior: ScrollBehavior = "smooth") => {
- const targetHeading = document.getElementById(id);
+ const headingElements = Array.from(document.querySelectorAll(MARKDOWN_HEADING_SELECTOR));
+
+ if (!headingElements.length) return;
+
+ const targetHeading = headingElements.find((heading) => heading.id === id);
if (!targetHeading) return;
const scrollY = window.scrollY + targetHeading.getBoundingClientRect().top - 80;
- window.scrollTo({
- top: scrollY,
- behavior,
- left: 0,
- });
+ window.scrollTo({ top: scrollY, behavior, left: 0 });
};
const scrollToTargetItem: React.MouseEventHandler = (e) => {
@@ -34,7 +35,7 @@ const useTocEvent = (toc: IToc[]) => {
if (!decodedHash) return;
- const item = toc.find((item) => item.text === decodedHash);
+ const item = toc.find((item) => item.id === decodedHash);
if (!item) return;
diff --git a/src/styles/globals.css b/src/styles/globals.css
index e44dc07..54f4902 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -151,7 +151,7 @@
}
& td {
- @apply border-[1px] border-solid border-gray-500;
+ @apply border border-solid border-gray-300 !transition-[border-color,color] dark:border-gray-700;
}
& pre {
diff --git a/src/utils/constant/toc.ts b/src/utils/constant/toc.ts
new file mode 100644
index 0000000..93a022d
--- /dev/null
+++ b/src/utils/constant/toc.ts
@@ -0,0 +1,3 @@
+const MARKDOWN_HEADING_SELECTOR = ".markdown > h1,.markdown > h2,.markdown > h3";
+
+export { MARKDOWN_HEADING_SELECTOR };
diff --git a/src/utils/getToc.ts b/src/utils/getToc.ts
index 92384f9..4d22ecb 100644
--- a/src/utils/getToc.ts
+++ b/src/utils/getToc.ts
@@ -3,6 +3,15 @@ import { ReactNode, JSX } from "react";
import { getChildrenText } from "@utils/getChildrenText";
import { IToc } from "@/types/base";
+const removeSpecialCharacters = (text: string) => {
+ return text
+ .replace(/[^a-zA-Z0-9가-힣\s]/g, "")
+ .replace(/\s+/g, " ")
+ .replace(/\s/g, "-")
+ .toLowerCase()
+ .trim();
+};
+
const getToc = (markdown: ReactNode) => {
const toc: IToc[] = [];
@@ -16,13 +25,15 @@ const getToc = (markdown: ReactNode) => {
const children = el?.props?.children;
const text = getChildrenText(children);
- const id = `${tagname}_${text.replace(/\s/g, "_").trim()}`;
+ const id = removeSpecialCharacters(text);
const level = Number(tagname.replace("h", "")) - 1;
+ if (level > 2) return;
+
toc.push({ text, id, level });
});
return toc;
};
-export { getToc };
+export { getToc, removeSpecialCharacters };