diff --git a/package-lock.json b/package-lock.json
index 2c81d8f0..24b67cf3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,13 +24,13 @@
"idb-keyval": "^6.2.4",
"jspdf": "^4.2.1",
"jspdf-autotable": "^5.0.7",
- "lucide-react": "^0.475.0",
"next": "^14.2.35",
"next-auth": "^4.24.14",
"next-pwa": "^5.6.0",
"react": "^18",
"react-dom": "^18",
"react-markdown": "^10.1.0",
+ "lucide-react": "^1.17.0",
"recharts": "^2.12.7",
"rehype-sanitize": "^6.0.0",
"server-only": "^0.0.1",
diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx
index 52816e5a..da8cecc9 100644
--- a/src/app/dashboard/page.tsx
+++ b/src/app/dashboard/page.tsx
@@ -138,8 +138,48 @@ export default async function DashboardPage() {
-
+
+
+
+
+
+
+
+
+ {/* Row 3b: Discussion activity */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/DashboardSidebar.tsx b/src/components/DashboardSidebar.tsx
new file mode 100644
index 00000000..7edab85c
--- /dev/null
+++ b/src/components/DashboardSidebar.tsx
@@ -0,0 +1,122 @@
+"use client";
+import { useEffect, useState } from "react";
+import {
+ Menu,
+ X,
+ Flame,
+ GitPullRequest,
+ Target,
+ AlertCircle,
+ BarChart2,
+ GitCommit,
+ CalendarDays,
+ Bot,
+ Trophy,
+} from "lucide-react";
+
+const sections = [
+ { id: "weekly-summary", label: "Weekly Summary", icon: CalendarDays },
+ { id: "personal-records", label: "Personal Records", icon: Trophy },
+ { id: "contribution", label: "Contributions", icon: GitCommit },
+ { id: "pr-analytics", label: "PR Analytics", icon: GitPullRequest },
+ { id: "top-repos", label: "Top Repos & Goals", icon: Target },
+ { id: "recent-activity", label: "Recent Activity", icon: BarChart2 },
+];
+
+export default function DashboardSidebar() {
+ const [activeId, setActiveId] = useState("");
+ const [mobileOpen, setMobileOpen] = useState(false);
+
+ useEffect(() => {
+ const observers: IntersectionObserver[] = [];
+
+ sections.forEach(({ id }) => {
+ const el = document.getElementById(id);
+ if (!el) return;
+
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting) setActiveId(id);
+ },
+ { threshold: 0.3 }
+ );
+
+ observer.observe(el);
+ observers.push(observer);
+ });
+
+ return () => observers.forEach((o) => o.disconnect());
+ }, []);
+
+ const handleNavClick = () => {
+ setMobileOpen(false);
+ };
+
+ return (
+ <>
+
+
+ {mobileOpen && (
+ setMobileOpen(false)}
+ />
+ )}
+
+
+
+ Navigate
+
+
+
+
+ {sections.map(({ id, label, icon: Icon }) => (
+
+
+ {label}
+
+ ))}
+
+ >
+ );
+}
\ No newline at end of file