From 7ed8ffd1ad7315c4cb2aa1ed5d73079d9f1ed2ca Mon Sep 17 00:00:00 2001 From: Ayush kumar gupta Date: Sat, 26 Sep 2026 16:11:07 +0530 Subject: [PATCH 1/2] fix: add read progress to blog sidebar --- src/css/custom.css | 1 - src/theme/BlogPostItem/Footer/index.tsx | 10 +-- src/theme/TOC/index.tsx | 93 +++++++++++++++++++++++++ src/theme/TOC/styles.module.css | 64 +++++++++++++++++ 4 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 src/theme/TOC/index.tsx create mode 100644 src/theme/TOC/styles.module.css diff --git a/src/css/custom.css b/src/css/custom.css index 18383d28..f84fb842 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -2480,7 +2480,6 @@ html[data-theme="dark"] { top: calc(var(--ifm-navbar-height, 60px) + 1rem) !important; max-height: calc(100vh - var(--ifm-navbar-height, 60px) - 2rem) !important; overflow-y: auto !important; - border-left: 2px solid var(--ifm-toc-border-color) !important; scrollbar-width: none !important; } diff --git a/src/theme/BlogPostItem/Footer/index.tsx b/src/theme/BlogPostItem/Footer/index.tsx index 5c0f04ca..d42cd4e3 100644 --- a/src/theme/BlogPostItem/Footer/index.tsx +++ b/src/theme/BlogPostItem/Footer/index.tsx @@ -8,7 +8,7 @@ import type { WrapperProps } from "@docusaurus/types"; import GiscusComments from "../../../components/giscus"; import SocialShare from "../../../components/SocialShare"; import { getAuthorProfile } from "../../../utils/authors"; -import ReadingTimeIndicator from "../../../components/ReadingTimeIndicator"; + import styles from "./styles.module.css"; @@ -100,13 +100,7 @@ export default function BlogPostItemFooterWrapper(props: Props): JSX.Element { {!isBlogPostPage && } {isBlogPostPage && ( - )} - {isBlogPostPage && ( - - )} + )} {showAuthorCard && (
diff --git a/src/theme/TOC/index.tsx b/src/theme/TOC/index.tsx new file mode 100644 index 00000000..06ce934b --- /dev/null +++ b/src/theme/TOC/index.tsx @@ -0,0 +1,93 @@ +import React, { useEffect, useState, useCallback, useRef } from "react"; +import clsx from "clsx"; +import { useLocation } from "@docusaurus/router"; +import TOCItems from "@theme/TOCItems"; +import type { Props } from "@theme/TOC"; + +import styles from "./styles.module.css"; + +const LINK_CLASS_NAME = "table-of-contents__link toc-highlight"; +const LINK_ACTIVE_CLASS_NAME = "table-of-contents__link--active"; + +function ReadingProgress(): JSX.Element { + const [progress, setProgress] = useState(0); + const rafRef = useRef(null); + + const computeProgress = useCallback(() => { + const scrollY = window.scrollY; + const winHeight = window.innerHeight; + const docHeight = document.documentElement.scrollHeight; + const maxScroll = docHeight - winHeight; + const percent = + maxScroll > 0 ? Math.min(100, Math.max(0, (scrollY / maxScroll) * 100)) : 0; + setProgress(Math.round(percent)); + }, []); + + const handleScroll = useCallback(() => { + if (rafRef.current !== null) return; + rafRef.current = requestAnimationFrame(() => { + rafRef.current = null; + computeProgress(); + }); + }, [computeProgress]); + + useEffect(() => { + window.addEventListener("scroll", handleScroll, { passive: true }); + computeProgress(); + return () => { + window.removeEventListener("scroll", handleScroll); + if (rafRef.current !== null) cancelAnimationFrame(rafRef.current); + }; + }, [handleScroll, computeProgress]); + + return ( +
+
+ + + Reading Progress + + {progress}% +
+
+
+
+
+ ); +} + +export default function TOC({ className, ...props }: Props): JSX.Element { + const { pathname } = useLocation(); + const isBlogPost = pathname.includes("/blog/") && pathname !== "/blog/"; + + return ( +
+ {isBlogPost && } + +
+ ); +} \ No newline at end of file diff --git a/src/theme/TOC/styles.module.css b/src/theme/TOC/styles.module.css new file mode 100644 index 00000000..0982da29 --- /dev/null +++ b/src/theme/TOC/styles.module.css @@ -0,0 +1,64 @@ +.tableOfContents { + max-height: calc(100vh - (var(--ifm-navbar-height) + 2rem)); + overflow-y: auto; + position: sticky; + top: calc(var(--ifm-navbar-height) + 1rem); + border: 1px solid var(--ifm-toc-border-color); + border-radius: 10px; + background: var(--ifm-background-surface-color); + padding: 12px; +} + +@media (max-width: 996px) { + .tableOfContents { + display: none; + } +} + +.progressContainer { + padding-bottom: 10px; + margin-bottom: 10px; + border-bottom: 1px solid var(--ifm-toc-border-color); +} + +.progressHeader { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 8px; +} + +.progressLabel { + display: flex; + align-items: center; + gap: 6px; + font-size: 0.8rem; + font-weight: 600; + color: var(--ifm-font-color-base); +} + +.progressIcon { + flex-shrink: 0; + color: var(--ifm-color-primary); +} + +.progressPercent { + font-size: 0.8rem; + font-weight: 600; + color: var(--ifm-color-emphasis-600); +} + +.progressTrack { + width: 100%; + height: 6px; + border-radius: 999px; + background: var(--ifm-color-emphasis-200); + overflow: hidden; +} + +.progressFill { + height: 100%; + border-radius: 999px; + background: var(--ifm-color-primary); + transition: width 0.1s linear; +} \ No newline at end of file From c5d9c042e0b5ecf334c2fa7a71cf082c7dce3426 Mon Sep 17 00:00:00 2001 From: Ayush kumar gupta Date: Sun, 27 Sep 2026 11:47:47 +0530 Subject: [PATCH 2/2] fix: match docker sidebar color --- src/css/custom.css | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/css/custom.css b/src/css/custom.css index f84fb842..7991a5bf 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -209,11 +209,11 @@ /* Force high visibility for active sidebar items - Blue Theme */ .menu__link--active { - background-color: #eff6ff; + background-color: transparent; /* Light blue background */ - color: #1d4ed8; + color: #2f855a; /* Strong blue text */ - font-weight: bold; + font-weight: 500; position: relative; box-shadow: 0 2px 8px rgba(37, 99, 235, 0.2); } @@ -221,39 +221,39 @@ /* Make the active icon stand out in the sidebar */ .menu__link--active .categoryIcon, .menu__link--active .linkIcon { - color: #2563eb; + color: #2f855a; } /* Make active text bold and larger */ .menu__link--active span { - font-weight: 700; - color: #1d4ed8; + font-weight: 500; + color: #2f855a; /* Strong blue color */ - font-size: 1.05em; + font-size: 1em; } /* ================= SECTION 3: ACTIVE INDICATORS ================= */ /* Style the existing dot for active pages */ a.menu__link.menu__link--active div span:first-child { - background-color: #2563eb !important; + background-color: #38a169 !important; /* Blue dot */ opacity: 1 !important; - width: 8px !important; - height: 8px !important; - box-shadow: 0 0 6px #2563eb !important; + width: 6px !important; + height: 6px !important; + box-shadow: 0 0 6px #38a169 !important; /* Add glow effect */ animation: breatheBlue 2s infinite; } /* Add arrow indicator to the right */ .menu__link--active::after { - content: "→"; + content: ""; position: absolute; right: 8px; top: 50%; transform: translateY(-50%); - color: #2563eb; + color: #38a169; font-weight: bold; } @@ -339,24 +339,24 @@ a.menu__link.menu__link--active div span:first-child { /* Dark mode styles for active items */ html[data-theme="dark"] .menu__link--active { - background-color: rgba(96, 165, 250, 0.15); - color: #93c5fd; + background-color: transparent; + color: #9ae6b4; } /* Dark mode text color */ html[data-theme="dark"] .menu__link--active span { - color: #93c5fd; + color: #9ae6b4; } /* Dark mode dot styling */ html[data-theme="dark"] a.menu__link.menu__link--active div span:first-child { - background-color: #93c5fd !important; - box-shadow: 0 0 8px #60a5fa !important; + background-color: #9ae6b4 !important; + box-shadow: 0 0 8px #68d391 !important; } /* Dark mode indicator colors */ html[data-theme="dark"] .menu__link--active::after { - color: #60a5fa; + color: #9ae6b4; } /* Ensure blog and markdown content is readable in dark mode */