From 0b871e5c6afe62160dc17cf401b1bf19020874cb Mon Sep 17 00:00:00 2001 From: Steve Hoang <82992510+lotusk08@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:41:26 +0700 Subject: [PATCH] fix(back-to-top): back-to-top & toc works independently --- assets/js/progress.js | 164 ++++++++++++++++++++++-------------------- 1 file changed, 87 insertions(+), 77 deletions(-) diff --git a/assets/js/progress.js b/assets/js/progress.js index 60389eb85cb..a90e2d9a2d8 100644 --- a/assets/js/progress.js +++ b/assets/js/progress.js @@ -1,85 +1,95 @@ document.addEventListener('DOMContentLoaded', () => { + // Back-to-Top Button Logic const btn = document.getElementById('back-to-top'); - const tocWrapper = document.getElementById('toc-wrapper'); // Add reference to TOC wrapper - if (!btn || !tocWrapper) return; - - // Create SVG container and progress circle - const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); - const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle"); - - svg.setAttribute("id", "progress-circle"); - svg.setAttribute("width", "44"); - svg.setAttribute("height", "44"); - - circle.setAttribute("cx", "22"); - circle.setAttribute("cy", "22"); - circle.setAttribute("r", "20"); - circle.setAttribute("stroke-width", "1"); - circle.setAttribute("stroke-dasharray", `${2 * Math.PI * 20}`); - circle.setAttribute("stroke-dashoffset", `${2 * Math.PI * 20}`); - circle.setAttribute("fill", "none"); - circle.style.stroke = "var(--btn-backtotop-color)"; - - svg.appendChild(circle); - btn.appendChild(svg); - - // Create scroll percentage text - const percentageText = document.createElement("div"); - percentageText.id = "scroll-percentage"; - percentageText.textContent = "0%"; - btn.appendChild(percentageText); - - // Variables for scroll behavior - let scrollTimeout; - let tocTimeout; - const circumference = 2 * Math.PI * 20; - - // Show TOC for 1-2 seconds when the page loads - tocWrapper.classList.add('visible'); - setTimeout(() => { - tocWrapper.classList.remove('visible'); // Hide the TOC after 1.5s - }, 1500); // 1.5 seconds after the page loads - - // Update progress on scroll - const updateScrollProgress = () => { - const scrollTop = window.scrollY; - const docHeight = document.documentElement.scrollHeight - window.innerHeight; - - if (docHeight > 0) { - const scrollFraction = scrollTop / docHeight; - const drawLength = circumference * scrollFraction; - const scrollPercentage = Math.round(scrollFraction * 100); - - // Update the circle progress - circle.style.strokeDashoffset = circumference - drawLength; - - // Show the percentage text with background - percentageText.textContent = `${scrollPercentage}`; - - // Add the visible class to show the text and background - percentageText.classList.add('visible'); - - // Clear timeout to hide the text after a delay - clearTimeout(scrollTimeout); - - // Hide the percentage text after a delay (500ms) - scrollTimeout = setTimeout(() => { - percentageText.classList.remove('visible'); - }, 500); - - // Always show the TOC when scrolling + if (btn) { + // Create SVG container and progress circle + const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle"); + + svg.setAttribute("id", "progress-circle"); + svg.setAttribute("width", "44"); + svg.setAttribute("height", "44"); + + circle.setAttribute("cx", "22"); + circle.setAttribute("cy", "22"); + circle.setAttribute("r", "20"); + circle.setAttribute("stroke-width", "1"); + circle.setAttribute("stroke-dasharray", `${2 * Math.PI * 20}`); + circle.setAttribute("stroke-dashoffset", `${2 * Math.PI * 20}`); + circle.setAttribute("fill", "none"); + circle.style.stroke = "var(--btn-backtotop-color)"; + + svg.appendChild(circle); + btn.appendChild(svg); + + // Create scroll percentage text + const percentageText = document.createElement("div"); + percentageText.id = "scroll-percentage"; + percentageText.textContent = "0%"; + btn.appendChild(percentageText); + + const circumference = 2 * Math.PI * 20; + let scrollTimeout; + + const updateScrollProgress = () => { + const scrollTop = window.scrollY; + const docHeight = document.documentElement.scrollHeight - window.innerHeight; + + if (docHeight > 0) { + const scrollFraction = scrollTop / docHeight; + const drawLength = circumference * scrollFraction; + const scrollPercentage = Math.round(scrollFraction * 100); + + // Update the circle progress + circle.style.strokeDashoffset = circumference - drawLength; + + // Show the percentage text with background + percentageText.textContent = `${scrollPercentage}`; + percentageText.classList.add('visible'); + + // Hide the percentage text after a delay + clearTimeout(scrollTimeout); + scrollTimeout = setTimeout(() => { + percentageText.classList.remove('visible'); + }, 500); + } + }; + + // Use requestAnimationFrame to smooth scroll updates + window.addEventListener('scroll', () => { + window.requestAnimationFrame(updateScrollProgress); + }); + + // Scroll to top on click + btn.addEventListener('click', () => { + window.scrollTo({ top: 0, behavior: 'smooth' }); + }); + } + + // TOC Wrapper Logic + const tocWrapper = document.getElementById('toc-wrapper'); + if (tocWrapper) { + // Show TOC for a few seconds when the page loads + tocWrapper.classList.add('visible'); + setTimeout(() => { + tocWrapper.classList.remove('visible'); // Hide the TOC after 1.5s + }, 1500); // 1.5 seconds after the page loads + + let tocTimeout; + + // Show TOC on scroll + const showTOCOnScroll = () => { tocWrapper.classList.add('visible'); // Add visible class to the TOC - // Reset the timeout to hide TOC after some idle time (e.g., 1.2 seconds) + // Hide TOC after some idle time clearTimeout(tocTimeout); tocTimeout = setTimeout(() => { tocWrapper.classList.remove('visible'); // Hide the TOC after 1.2 seconds of inactivity - }, 500); // TOC hides after 1 seconds of inactivity - } - }; - - // Use requestAnimationFrame to smooth scroll updates - window.addEventListener('scroll', () => { - window.requestAnimationFrame(updateScrollProgress); - }); + }, 1200); // 1.2 seconds of inactivity + }; + + window.addEventListener('scroll', () => { + showTOCOnScroll(); + }); + } });