From 7747a86600302bf9b81c155c1dd01ad26f0141c9 Mon Sep 17 00:00:00 2001 From: xonas1101 Date: Thu, 15 Jan 2026 11:42:16 +0000 Subject: [PATCH 1/6] prevent footer controls from being pushed off-screen when banner is active Signed-off-by: xonas1101 --- src/components/docs/DocsBanner.tsx | 2 +- src/components/docs/DocsSidebar.tsx | 50 +++++++++++++------------ src/components/docs/RelatedProjects.tsx | 47 +---------------------- 3 files changed, 29 insertions(+), 70 deletions(-) diff --git a/src/components/docs/DocsBanner.tsx b/src/components/docs/DocsBanner.tsx index b08a8e58..9e008010 100644 --- a/src/components/docs/DocsBanner.tsx +++ b/src/components/docs/DocsBanner.tsx @@ -22,7 +22,7 @@ export function DocsBanner() { const isDark = resolvedTheme === 'dark' return ( -
+
diff --git a/src/components/docs/DocsSidebar.tsx b/src/components/docs/DocsSidebar.tsx index 7ddf9929..ad237f59 100644 --- a/src/components/docs/DocsSidebar.tsx +++ b/src/components/docs/DocsSidebar.tsx @@ -4,9 +4,10 @@ import { useState, useEffect, useRef } from 'react'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; import { useTheme } from 'next-themes'; -import { ChevronRight, ChevronDown, FileText } from 'lucide-react'; +import { ChevronRight, ChevronDown, FileText, Sidebar } from 'lucide-react'; import { RelatedProjects } from './RelatedProjects'; import { useDocsMenu } from './DocsProvider'; +import { SidebarFooter } from './SidebarFooter'; interface MenuItem { name: string; @@ -50,28 +51,34 @@ export function DocsSidebar({ pageMap, className }: DocsSidebarProps) { const [layoutValues, setLayoutValues] = useState({ top: '4rem', height: 'calc(100vh - 4rem)' }); const layoutCalculatedRef = useRef(false); - useEffect(() => { - const calculateOffsets = () => { - const navbar = document.querySelector('.nextra-nav-container'); - if (navbar) { - const navbarHeight = (navbar as HTMLElement).offsetHeight; - const newTop = `${navbarHeight}px`; - const newHeight = `calc(100vh - ${navbarHeight}px)`; - setLayoutValues({ top: newTop, height: newHeight }); - layoutCalculatedRef.current = true; - } - }; + const calculateOffsets = () => { + const navbar = document.querySelector('.nextra-nav-container') as HTMLElement | null; + const banner = document.querySelector('.docs-banner') as HTMLElement | null; + + const navbarHeight = navbar?.offsetHeight || 0; + const bannerHeight = banner?.offsetHeight || 0; + + const totalTop = navbarHeight + bannerHeight; + + setLayoutValues({ + top: `${totalTop}px`, + height: `calc(100vh - ${totalTop}px)` + }); +}; - // Calculate on mount and when banner state changes - // Use setTimeout to allow DOM to update after banner dismiss - const timeoutId = setTimeout(calculateOffsets, 50); + + useEffect(() => { + // Wait for layout (banner + navbar) to fully render + const t = setTimeout(calculateOffsets, 500); window.addEventListener('resize', calculateOffsets); + return () => { - clearTimeout(timeoutId); + clearTimeout(t); window.removeEventListener('resize', calculateOffsets); }; - }, [bannerDismissed]); +}, [bannerDismissed]); + // Store initial pathname for initialization const initialPathnameRef = useRef(pathname); @@ -233,12 +240,9 @@ export function DocsSidebar({ pageMap, className }: DocsSidebarProps) { +
- - {/* Related Projects - fixed at bottom, shrink-0 prevents shrinking */} -
- -
+ ); @@ -249,7 +253,7 @@ export function DocsSidebar({ pageMap, className }: DocsSidebarProps) {
{/* Footer with icon buttons */} - +
); diff --git a/src/components/docs/RelatedProjects.tsx b/src/components/docs/RelatedProjects.tsx index 47bcf86c..f018455d 100644 --- a/src/components/docs/RelatedProjects.tsx +++ b/src/components/docs/RelatedProjects.tsx @@ -25,7 +25,7 @@ interface RelatedProjectsProps { bannerActive?: boolean; } -export function RelatedProjects({ variant = 'full', onCollapse, isMobile = false, bannerActive = false }: RelatedProjectsProps) { +export function RelatedProjects({ variant = 'full', onCollapse, bannerActive = false }: RelatedProjectsProps) { const [isExpanded, setIsExpanded] = useState(true); const [mounted, setMounted] = useState(false); const pathname = usePathname(); @@ -180,51 +180,6 @@ export function RelatedProjects({ variant = 'full', onCollapse, isMobile = false ); })}
- - {/* Footer Controls */} - {mounted && ( -
- {/* Theme Toggle Button */} - - - {/* Collapse Sidebar Button - Hidden on mobile */} - {onCollapse && !isMobile && ( - - )} -
- )}
); } From d48dda882e907858fe81f34c1e6a97f702b1c4c7 Mon Sep 17 00:00:00 2001 From: xonas1101 Date: Thu, 15 Jan 2026 11:46:33 +0000 Subject: [PATCH 2/6] removed unnecessary extralines Signed-off-by: xonas1101 --- src/components/docs/DocsSidebar.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/components/docs/DocsSidebar.tsx b/src/components/docs/DocsSidebar.tsx index ad237f59..7ae3d7bd 100644 --- a/src/components/docs/DocsSidebar.tsx +++ b/src/components/docs/DocsSidebar.tsx @@ -54,32 +54,25 @@ export function DocsSidebar({ pageMap, className }: DocsSidebarProps) { const calculateOffsets = () => { const navbar = document.querySelector('.nextra-nav-container') as HTMLElement | null; const banner = document.querySelector('.docs-banner') as HTMLElement | null; - const navbarHeight = navbar?.offsetHeight || 0; const bannerHeight = banner?.offsetHeight || 0; - const totalTop = navbarHeight + bannerHeight; - setLayoutValues({ top: `${totalTop}px`, height: `calc(100vh - ${totalTop}px)` }); }; - useEffect(() => { // Wait for layout (banner + navbar) to fully render const t = setTimeout(calculateOffsets, 500); - window.addEventListener('resize', calculateOffsets); - return () => { clearTimeout(t); window.removeEventListener('resize', calculateOffsets); }; }, [bannerDismissed]); - // Store initial pathname for initialization const initialPathnameRef = useRef(pathname); From aff1d498b8e407a0026cf92efa5daf753f982521 Mon Sep 17 00:00:00 2001 From: xonas1101 Date: Thu, 15 Jan 2026 17:40:49 +0000 Subject: [PATCH 3/6] fixed linting errors Signed-off-by: xonas1101 --- src/components/docs/DocsSidebar.tsx | 5 ++--- src/components/docs/RelatedProjects.tsx | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/docs/DocsSidebar.tsx b/src/components/docs/DocsSidebar.tsx index 7ae3d7bd..27edac04 100644 --- a/src/components/docs/DocsSidebar.tsx +++ b/src/components/docs/DocsSidebar.tsx @@ -4,7 +4,7 @@ import { useState, useEffect, useRef } from 'react'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; import { useTheme } from 'next-themes'; -import { ChevronRight, ChevronDown, FileText, Sidebar } from 'lucide-react'; +import { ChevronRight, ChevronDown, FileText} from 'lucide-react'; import { RelatedProjects } from './RelatedProjects'; import { useDocsMenu } from './DocsProvider'; import { SidebarFooter } from './SidebarFooter'; @@ -49,7 +49,6 @@ export function DocsSidebar({ pageMap, className }: DocsSidebarProps) { const textColor = isDark ? '#e5e7eb' : '#374151'; // gray-200 : gray-700 // Stable layout values - only recalculate on resize or banner change const [layoutValues, setLayoutValues] = useState({ top: '4rem', height: 'calc(100vh - 4rem)' }); - const layoutCalculatedRef = useRef(false); const calculateOffsets = () => { const navbar = document.querySelector('.nextra-nav-container') as HTMLElement | null; @@ -128,7 +127,7 @@ export function DocsSidebar({ pageMap, className }: DocsSidebarProps) { findActivePath(pageMap); collapseAll(pageMap); setCollapsed(initialCollapsed); - }, [pageMap]); + }, [pageMap, navInitialized, setCollapsed]); const toggleCollapse = (itemKey: string) => { toggleNavCollapsed(itemKey); diff --git a/src/components/docs/RelatedProjects.tsx b/src/components/docs/RelatedProjects.tsx index f018455d..90b220bf 100644 --- a/src/components/docs/RelatedProjects.tsx +++ b/src/components/docs/RelatedProjects.tsx @@ -3,7 +3,7 @@ import { useState, useEffect } from 'react'; import { usePathname } from 'next/navigation'; import { useTheme } from 'next-themes'; -import { ChevronRight, ChevronDown, Moon, Sun, PanelRightOpenIcon, PanelLeftOpen } from 'lucide-react'; +import { ChevronRight, ChevronDown, Moon, Sun, PanelLeftOpen } from 'lucide-react'; import { useSharedConfig } from '@/hooks/useSharedConfig'; // Production URL - all cross-project links go here From f4f23fc36940348998c4229f5a7bb4bf6adfbfbc Mon Sep 17 00:00:00 2001 From: xonas1101 Date: Fri, 16 Jan 2026 16:56:09 +0000 Subject: [PATCH 4/6] Fixed bug where sidebar height wont recalculate on scroll Signed-off-by: xonas1101 --- src/components/docs/DocsSidebar.tsx | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/components/docs/DocsSidebar.tsx b/src/components/docs/DocsSidebar.tsx index 27edac04..c5d1e66e 100644 --- a/src/components/docs/DocsSidebar.tsx +++ b/src/components/docs/DocsSidebar.tsx @@ -50,17 +50,16 @@ export function DocsSidebar({ pageMap, className }: DocsSidebarProps) { // Stable layout values - only recalculate on resize or banner change const [layoutValues, setLayoutValues] = useState({ top: '4rem', height: 'calc(100vh - 4rem)' }); + const calculateOffsets = () => { - const navbar = document.querySelector('.nextra-nav-container') as HTMLElement | null; - const banner = document.querySelector('.docs-banner') as HTMLElement | null; - const navbarHeight = navbar?.offsetHeight || 0; - const bannerHeight = banner?.offsetHeight || 0; - const totalTop = navbarHeight + bannerHeight; - setLayoutValues({ - top: `${totalTop}px`, - height: `calc(100vh - ${totalTop}px)` - }); -}; + const navbar = document.querySelector('.nextra-nav-container') as HTMLElement | null; + if (!navbar) return; + const navbarBottomY = navbar.getBoundingClientRect().bottom; + setLayoutValues({ + top: `${navbarBottomY}px`, + height: `calc(100vh - ${navbarBottomY}px)` + }); + }; useEffect(() => { // Wait for layout (banner + navbar) to fully render From eec662de21a1eebcbbaf47f96c504426cd6aef22 Mon Sep 17 00:00:00 2001 From: xonas1101 Date: Fri, 16 Jan 2026 17:00:57 +0000 Subject: [PATCH 5/6] Removed unnecessary empty line Signed-off-by: xonas1101 --- src/components/docs/DocsSidebar.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/docs/DocsSidebar.tsx b/src/components/docs/DocsSidebar.tsx index c5d1e66e..8e347a64 100644 --- a/src/components/docs/DocsSidebar.tsx +++ b/src/components/docs/DocsSidebar.tsx @@ -50,7 +50,6 @@ export function DocsSidebar({ pageMap, className }: DocsSidebarProps) { // Stable layout values - only recalculate on resize or banner change const [layoutValues, setLayoutValues] = useState({ top: '4rem', height: 'calc(100vh - 4rem)' }); - const calculateOffsets = () => { const navbar = document.querySelector('.nextra-nav-container') as HTMLElement | null; if (!navbar) return; From b26a795405172671a4c64f62cb44f1510da84dc1 Mon Sep 17 00:00:00 2001 From: xonas1101 Date: Sun, 18 Jan 2026 00:03:28 +0000 Subject: [PATCH 6/6] Fix sidebar resizing when scroll Signed-off-by: xonas1101 --- src/components/docs/DocsSidebar.tsx | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/components/docs/DocsSidebar.tsx b/src/components/docs/DocsSidebar.tsx index 8e347a64..9284e81d 100644 --- a/src/components/docs/DocsSidebar.tsx +++ b/src/components/docs/DocsSidebar.tsx @@ -53,22 +53,42 @@ export function DocsSidebar({ pageMap, className }: DocsSidebarProps) { const calculateOffsets = () => { const navbar = document.querySelector('.nextra-nav-container') as HTMLElement | null; if (!navbar) return; + const navbarBottomY = navbar.getBoundingClientRect().bottom; + setLayoutValues({ top: `${navbarBottomY}px`, height: `calc(100vh - ${navbarBottomY}px)` }); }; + useEffect(() => { - // Wait for layout (banner + navbar) to fully render - const t = setTimeout(calculateOffsets, 500); + let ticking = false; + + const onScroll = () => { + if (!ticking) { + ticking = true; + requestAnimationFrame(() => { + calculateOffsets(); + ticking = false; + }); + } + }; + + const t = setTimeout(calculateOffsets, 300); + window.addEventListener('resize', calculateOffsets); + window.addEventListener('scroll', onScroll, { passive: true }); + return () => { clearTimeout(t); window.removeEventListener('resize', calculateOffsets); + window.removeEventListener('scroll', onScroll); }; -}, [bannerDismissed]); + }, [bannerDismissed]); + + // Store initial pathname for initialization const initialPathnameRef = useRef(pathname);