diff --git a/assets/css/custom.css b/assets/css/custom.css
index c242704..5a46a09 100644
--- a/assets/css/custom.css
+++ b/assets/css/custom.css
@@ -17,9 +17,12 @@
}
.toc:has(#TableOfContents) {
- background-color: rgba(25, 25, 35, 0.45);
+ background-color: rgba(25, 25, 35, 0.3);
border-radius: 10px;
max-height: 70vh;
+ overflow-y: auto;
+ padding: 1rem;
+ scroll-behavior: smooth;
}
.background-container {
@@ -107,4 +110,45 @@ header button[id^="search-button"]:hover {
100% {
backdrop-filter: blur(8px) hue-rotate(-10deg);
}
+}
+
+/* TOC link styling */
+#TableOfContents a {
+ color: rgba(255, 255, 255, 0.8);
+ text-decoration: none;
+ transition: all 0.3s ease;
+ display: block;
+ padding: 0.25rem 0;
+}
+
+#TableOfContents a:hover {
+ color: white;
+ transform: translateX(4px);
+}
+
+/* Active TOC item */
+#TableOfContents a.active {
+ color: white;
+ font-weight: 600;
+ transform: translateX(4px);
+ position: relative;
+ transition: all 0.3s ease;
+}
+
+#TableOfContents a.active::before {
+ content: '';
+ position: absolute;
+ left: -1rem;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 4px;
+ height: 1rem;
+ background: linear-gradient(to bottom, #4a9eff, #2d7bda);
+ border-radius: 2px;
+ transition: all 0.3s ease;
+}
+
+/* Remove the default smooth scrolling behavior */
+html {
+ scroll-behavior: smooth;
}
\ No newline at end of file
diff --git a/assets/js/toc-highlight.js b/assets/js/toc-highlight.js
new file mode 100644
index 0000000..c1f680a
--- /dev/null
+++ b/assets/js/toc-highlight.js
@@ -0,0 +1,151 @@
+document.addEventListener('DOMContentLoaded', function() {
+ const tocLinks = document.querySelectorAll('#TableOfContents a');
+ const tocContainer = document.querySelector('.toc');
+ const sections = new Map(); // Store section elements with their corresponding TOC links
+ let lastActiveSection = null;
+ let scrollTimeout = null;
+ let isScrolling = false;
+
+ // Build a map of section IDs to their TOC links
+ tocLinks.forEach(link => {
+ const sectionId = decodeURIComponent(link.getAttribute('href').substring(1));
+ const section = document.getElementById(sectionId);
+ if (section) {
+ sections.set(section, link);
+ }
+ });
+
+ // Function to scroll TOC container to keep active item in view
+ const scrollTocToActive = (activeLink) => {
+ if (!tocContainer || !activeLink) return;
+
+ const containerRect = tocContainer.getBoundingClientRect();
+ const linkRect = activeLink.getBoundingClientRect();
+
+ // Check if the active link is outside the visible area
+ if (linkRect.top < containerRect.top || linkRect.bottom > containerRect.bottom) {
+ // Calculate the scroll position to center the active link
+ const scrollTop = activeLink.offsetTop - (containerRect.height / 2) + (linkRect.height / 2);
+
+ // Use CSS smooth scrolling if available, otherwise use JS
+ if ('scrollBehavior' in document.documentElement.style) {
+ tocContainer.scrollTo({
+ top: scrollTop,
+ behavior: 'smooth'
+ });
+ } else {
+ // Fallback for browsers that don't support smooth scrolling
+ tocContainer.scrollTop = scrollTop;
+ }
+ }
+ };
+
+ // Function to find the section closest to the center of the viewport
+ const findClosestSectionToCenter = () => {
+ let closestSection = null;
+ let closestDistance = Infinity;
+ const viewportHeight = window.innerHeight;
+ const viewportCenter = viewportHeight / 2;
+
+ sections.forEach((link, section) => {
+ const rect = section.getBoundingClientRect();
+ // Calculate the center of the section
+ const sectionCenter = rect.top + (rect.height / 2);
+ // Calculate distance from the center of the viewport
+ const distance = Math.abs(sectionCenter - viewportCenter);
+
+ // If this section is closer to the center than our current closest
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestSection = section;
+ }
+ });
+
+ return closestSection;
+ };
+
+ // Function to update the active section
+ const updateActiveSection = (activeSection) => {
+ if (!activeSection) return;
+
+ // Update active state
+ tocLinks.forEach(link => link.classList.remove('active'));
+
+ const activeLink = sections.get(activeSection);
+ if (activeLink) {
+ activeLink.classList.add('active');
+ lastActiveSection = activeSection;
+
+ // Use a small delay before scrolling to prevent rapid changes
+ if (scrollTimeout) {
+ clearTimeout(scrollTimeout);
+ }
+
+ scrollTimeout = setTimeout(() => {
+ scrollTocToActive(activeLink);
+ }, 100);
+ }
+ };
+
+ // Function to handle scroll events
+ const handleScroll = () => {
+ // Clear any pending scroll timeout
+ if (scrollTimeout) {
+ clearTimeout(scrollTimeout);
+ }
+
+ // Find the section closest to the center of the viewport
+ const closestSection = findClosestSectionToCenter();
+
+ // Update the active section
+ updateActiveSection(closestSection);
+ };
+
+ // Add scroll event listener with debouncing
+ let scrollDebounceTimer = null;
+ window.addEventListener('scroll', () => {
+ isScrolling = true;
+
+ // Debounce the scroll event
+ if (scrollDebounceTimer) {
+ clearTimeout(scrollDebounceTimer);
+ }
+
+ scrollDebounceTimer = setTimeout(() => {
+ isScrolling = false;
+ handleScroll();
+ }, 100);
+ });
+
+ // Initial check to ensure a section is highlighted
+ setTimeout(() => {
+ handleScroll();
+ }, 500);
+
+ // Smooth scroll to section when clicking TOC links
+ tocLinks.forEach(link => {
+ link.addEventListener('click', (e) => {
+ e.preventDefault();
+ const targetId = decodeURIComponent(link.getAttribute('href').substring(1));
+ const targetSection = document.getElementById(targetId);
+ if (targetSection) {
+ // Use our custom smooth scrolling function if available
+ if (window.smoothScrollTo) {
+ window.smoothScrollTo(targetSection);
+ } else {
+ // Fallback to standard smooth scrolling
+ targetSection.scrollIntoView({ behavior: 'smooth' });
+ }
+
+ // Also update the active section immediately
+ const activeLink = sections.get(targetSection);
+ if (activeLink) {
+ tocLinks.forEach(l => l.classList.remove('active'));
+ activeLink.classList.add('active');
+ lastActiveSection = targetSection;
+ scrollTocToActive(activeLink);
+ }
+ }
+ });
+ });
+});
\ No newline at end of file
diff --git a/layouts/partials/extend-footer.html b/layouts/partials/extend-footer.html
new file mode 100644
index 0000000..7ee539b
--- /dev/null
+++ b/layouts/partials/extend-footer.html
@@ -0,0 +1,4 @@
+{{ if .TableOfContents }}
+ {{ $tocHighlight := resources.Get "js/toc-highlight.js" | js.Build | fingerprint }}
+
+{{ end }}
\ No newline at end of file
diff --git a/layouts/partials/scripts.html b/layouts/partials/scripts.html
deleted file mode 100644
index 1560470..0000000
--- a/layouts/partials/scripts.html
+++ /dev/null
@@ -1,3 +0,0 @@
-{{ if .Params.showTableOfContents | default (.Site.Params.article.showTableOfContents | default false) }}
-
-{{ end }}
\ No newline at end of file