-
+ {/* Row 1: Contribution graph + Streak + Local Coding Time */}
+
+
+
+
+ }>
+
+
+
+
+ }>
+
+
+
-
-
- {/* Row 2: PR metrics, community metrics, PR breakdown & Time Chart */}
-
- {/* Row 2b: Activity Ring Chart */}
-
+ {/* Row 2: PR metrics, community metrics, PR breakdown & Time Chart */}
+
+ {/* Row 2b: Activity Ring Chart */}
+
-
-
-
+
+
+
-
+
- {/* Row 3: Issue metrics + CI analytics */}
-
-
-
+ {/* Row 3: Issue metrics + CI analytics */}
+
+ {/* Row 3b: Discussion activity */}
+
+ }>
+
+
-
-
- {/* Row 3b: Discussion activity */}
-
-
-
- {/* Row 4: Pinned repositories */}
-
+ {/* Row 4: Pinned repositories */}
+
- {/* Row 5: Inactive repository reminder */}
-
-
-
+ {/* Row 5: Inactive repository reminder */}
+
+ }>
+
+
+
- {/* Row 6: Top repos + Language breakdown + Goal tracker */}
-
-
-
-
-
+ {/* Row 6: Top repos + Language breakdown + Goal tracker */}
+
+ }>
+
+
+ }>
+
+
+
+
- {/* Row 7: Recent GitHub activity */}
-
-
+ {/* Row 7: Recent GitHub activity */}
+
+ }>
+
+
+
-
);
}
diff --git a/src/components/LazyWidget.tsx b/src/components/LazyWidget.tsx
new file mode 100644
index 00000000..21a8ec18
--- /dev/null
+++ b/src/components/LazyWidget.tsx
@@ -0,0 +1,65 @@
+"use client";
+
+import {ReactNode,useEffect,useRef,useState,memo} from "react";
+
+interface LazyWidgetProps {
+ children: ReactNode;
+ fallback: ReactNode;
+ rootMargin?: string;
+ threshold?: number;
+ className?: string;
+}
+
+function LazyWidget({
+ children,
+ fallback,
+ rootMargin = "300px",
+ threshold = 0.1,
+ className = "",
+}: LazyWidgetProps) {
+
+ const containerRef = useRef
(null);
+ const observerRef = useRef(null);
+ const [isVisible , setIsVisible] = useState(false);
+
+ useEffect(()=>{
+ const node = containerRef.current;
+ if(!node || isVisible) return;
+
+ observerRef.current = new IntersectionObserver(([entry])=>{
+ if(entry.isIntersecting){
+ setIsVisible(true);
+
+ if(observerRef.current){
+ observerRef.current.disconnect();
+ observerRef.current = null;
+ }
+ }
+ },{
+ root : null,
+ rootMargin,
+ threshold
+ });
+
+ observerRef.current.observe(node);
+
+ return ()=>{
+ if(observerRef.current){
+ observerRef.current.disconnect();
+ observerRef.current = null;
+ }
+ };
+ },[isVisible,rootMargin,threshold]);
+
+ return (
+
+
+ {isVisible ? children : fallback}
+
+ );
+}
+
+export default memo(LazyWidget);
\ No newline at end of file
From 594de9782f42acc8d2a32b3ef684f0b3c5bbe151 Mon Sep 17 00:00:00 2001
From: Akash Jadhav <142928804+Akash1510@users.noreply.github.com>
Date: Wed, 27 May 2026 13:58:03 +0530
Subject: [PATCH 2/2] perf: lazy load below-the-fold dashboard widgets
---
src/app/dashboard/page.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx
index a5c0da7d..42ac73b9 100644
--- a/src/app/dashboard/page.tsx
+++ b/src/app/dashboard/page.tsx
@@ -112,7 +112,7 @@ import ExportButton from "@/components/ExportButton";
import Link from "next/link";
import PersonalRecords from "@/components/PersonalRecords";
import LocalCodingTime from "@/components/LocalCodingTime";
-import CodingTimeCard from "@/components/CodingTimeCard";
+import CodingTimeWidget from "@/components/CodingTimeWidget";
import RecentActivity from "@/components/RecentActivity";
import { authOptions } from "@/lib/auth";
import { getServerSession } from "next-auth";
@@ -202,7 +202,7 @@ export default async function DashboardPage() {
-
+