diff --git a/src/components/docs/DocsSidebar.tsx b/src/components/docs/DocsSidebar.tsx
index 7ddf9929..9284e81d 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} from 'lucide-react';
import { RelatedProjects } from './RelatedProjects';
import { useDocsMenu } from './DocsProvider';
+import { SidebarFooter } from './SidebarFooter';
interface MenuItem {
name: string;
@@ -48,31 +49,47 @@ 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;
+ if (!navbar) return;
+
+ const navbarBottomY = navbar.getBoundingClientRect().bottom;
+
+ setLayoutValues({
+ top: `${navbarBottomY}px`,
+ height: `calc(100vh - ${navbarBottomY}px)`
+ });
+ };
+
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;
+ let ticking = false;
+
+ const onScroll = () => {
+ if (!ticking) {
+ ticking = true;
+ requestAnimationFrame(() => {
+ calculateOffsets();
+ ticking = false;
+ });
}
};
- // Calculate on mount and when banner state changes
- // Use setTimeout to allow DOM to update after banner dismiss
- const timeoutId = setTimeout(calculateOffsets, 50);
+ const t = setTimeout(calculateOffsets, 300);
window.addEventListener('resize', calculateOffsets);
+ window.addEventListener('scroll', onScroll, { passive: true });
+
return () => {
- clearTimeout(timeoutId);
+ clearTimeout(t);
window.removeEventListener('resize', calculateOffsets);
+ window.removeEventListener('scroll', onScroll);
};
}, [bannerDismissed]);
+
+
// Store initial pathname for initialization
const initialPathnameRef = useRef(pathname);
@@ -128,7 +145,7 @@ export function DocsSidebar({ pageMap, className }: DocsSidebarProps) {
findActivePath(pageMap);
collapseAll(pageMap);
setCollapsed(initialCollapsed);
- }, [pageMap]);
+ }, [pageMap, navInitialized, setCollapsed]);
const toggleCollapse = (itemKey: string) => {
toggleNavCollapsed(itemKey);
@@ -233,12 +250,9 @@ export function DocsSidebar({ pageMap, className }: DocsSidebarProps) {
+
-
- {/* Related Projects - fixed at bottom, shrink-0 prevents shrinking */}
-
-
-
+
>
);
@@ -249,7 +263,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..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
@@ -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
);
})}