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