diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx
index ad52e2ab8..b0e466595 100644
--- a/components/Sidebar.tsx
+++ b/components/Sidebar.tsx
@@ -10,6 +10,7 @@ import CarbonAds from './CarbonsAds';
import { useTheme } from 'next-themes';
import ExternalLinkIcon from '../public/icons/external-link-black.svg';
import Image from 'next/image';
+import TableOfContents from './TableOfContents';
const DocLink = ({
uri,
label,
@@ -252,9 +253,17 @@ export const SidebarLayout = ({ children }: { children: React.ReactNode }) => {
/>
-
diff --git a/components/TableOfContents.tsx b/components/TableOfContents.tsx
new file mode 100644
index 000000000..86cfc65db
--- /dev/null
+++ b/components/TableOfContents.tsx
@@ -0,0 +1,95 @@
+import React, { useState, useEffect } from 'react';
+import { useRouter } from 'next/router';
+
+interface Heading {
+ id: string;
+ text: string;
+ level: number;
+}
+
+const TableOfContents: React.FC = () => {
+ const router = useRouter();
+ const [headings, setHeadings] = useState([]);
+ const [activeId, setActiveId] = useState(null);
+
+ useEffect(() => {
+ const mainContent = document.getElementById('main-content');
+ const elements = mainContent
+ ? mainContent.querySelectorAll('h1, h2, h3, h4')
+ : [];
+ const newHeadings: Heading[] = [];
+
+ elements.forEach((el) => {
+ const text = el.textContent || '';
+ if (text.trim().toLowerCase() === 'on this page') return;
+ if (el.closest('#sidebar')) return;
+
+ const currentFolder = router.pathname.split('/').pop()?.toLowerCase();
+ if (text.trim().toLowerCase() === currentFolder) return;
+ if (
+ text.includes('/') ||
+ text.includes('\\') ||
+ /\.md$|\.tsx$|\.jsx$|\.js$/i.test(text.trim())
+ )
+ return;
+ const level = parseInt(el.tagName.replace('H', ''));
+ if (!el.id) {
+ const generatedId = text
+ .toLowerCase()
+ .trim()
+ .replace(/\s+/g, '-')
+ .replace(/[^\w-]+/g, '');
+ if (generatedId) {
+ el.id = generatedId;
+ }
+ }
+
+ newHeadings.push({
+ id: el.id,
+ text,
+ level,
+ });
+ });
+
+ setHeadings(newHeadings);
+
+ const handleScroll = () => {
+ let currentId: string | null = null;
+ elements.forEach((el) => {
+ const rect = (el as HTMLElement).getBoundingClientRect();
+ if (rect.top <= 100) {
+ currentId = el.id;
+ }
+ });
+ setActiveId(currentId);
+ };
+
+ window.addEventListener('scroll', handleScroll);
+ handleScroll();
+ return () => window.removeEventListener('scroll', handleScroll);
+ }, [router.asPath]);
+
+ return (
+
+ );
+};
+
+export default TableOfContents;