From 34a24f844471bc35a8954e4e035203d0bbdbceb2 Mon Sep 17 00:00:00 2001 From: theprakashkumar Date: Tue, 13 Jan 2026 14:54:46 +0530 Subject: [PATCH 1/6] fix: Added auto scroll in the content container on the blog page. --- app/globals.css | 31 ++++++++++ components/blog/BlogTableOfContents.tsx | 78 +++++++++++++++++++++++-- package-lock.json | 22 +------ 3 files changed, 105 insertions(+), 26 deletions(-) diff --git a/app/globals.css b/app/globals.css index 937123b..64d9dbb 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1344,3 +1344,34 @@ html:not(.dark) .text-amber-400 { .border-tip\/20 { border-color: var(--color-callout-tip-border) !important; } + +/* Global custom scrollbar styling */ +/* Firefox */ +* { + scrollbar-width: thin; + scrollbar-color: var(--color-border) transparent; +} + +/* WebKit browsers (Chrome, Safari, Edge) */ +*::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +*::-webkit-scrollbar-track { + background: transparent; +} + +*::-webkit-scrollbar-thumb { + background-color: var(--color-border); + border-radius: 4px; +} + +*::-webkit-scrollbar-thumb:hover { + background-color: var(--color-border-light); +} + +/* Horizontal scrollbars */ +*::-webkit-scrollbar:horizontal { + height: 8px; +} diff --git a/components/blog/BlogTableOfContents.tsx b/components/blog/BlogTableOfContents.tsx index 01a8adc..9dd59c2 100644 --- a/components/blog/BlogTableOfContents.tsx +++ b/components/blog/BlogTableOfContents.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; export interface TOCHeading { id: string; @@ -15,6 +15,62 @@ interface BlogTableOfContentsProps { export function BlogTableOfContents({ headings }: BlogTableOfContentsProps) { const [activeId, setActiveId] = useState(""); const [readProgress, setReadProgress] = useState(0); + const scrollContainerRef = useRef(null); + const activeButtonRef = useRef(null); + const isUserScrollingRef = useRef(false); + + // Auto-scroll active item into view + useEffect(() => { + if (!activeId || !activeButtonRef.current || !scrollContainerRef.current) { + return; + } + + // Don't auto-scroll if user is manually scrolling + if (isUserScrollingRef.current) { + return; + } + + const button = activeButtonRef.current; + const container = scrollContainerRef.current; + + // Check if button is visible in container + const buttonRect = button.getBoundingClientRect(); + const containerRect = container.getBoundingClientRect(); + + const isAboveViewport = buttonRect.top < containerRect.top; + const isBelowViewport = buttonRect.bottom > containerRect.bottom; + + if (isAboveViewport || isBelowViewport) { + // Scroll the button into view with some padding + button.scrollIntoView({ + behavior: "smooth", + block: "nearest", + }); + } + }, [activeId]); + + // Handle user scrolling in TOC container + useEffect(() => { + const container = scrollContainerRef.current; + if (!container) return; + + let scrollTimeout: NodeJS.Timeout; + + const handleTOCScroll = () => { + isUserScrollingRef.current = true; + // Reset flag after scrolling stops + clearTimeout(scrollTimeout); + scrollTimeout = setTimeout(() => { + isUserScrollingRef.current = false; + }, 500); + }; + + container.addEventListener("scroll", handleTOCScroll, { passive: true }); + return () => { + container.removeEventListener("scroll", handleTOCScroll); + clearTimeout(scrollTimeout); + }; + }, []); // Scroll spy and progress tracking useEffect(() => { @@ -53,6 +109,12 @@ export function BlogTableOfContents({ headings }: BlogTableOfContentsProps) { } const handleClick = (id: string) => { + // Prevent auto-scroll when user clicks + isUserScrollingRef.current = true; + setTimeout(() => { + isUserScrollingRef.current = false; + }, 1000); + const element = document.getElementById(id); if (element) { const offset = 100; @@ -68,9 +130,9 @@ export function BlogTableOfContents({ headings }: BlogTableOfContentsProps) { return (