From 4be5644ee7892e3f9737a400bd0327d5590f519e Mon Sep 17 00:00:00 2001 From: Prem Dhakad Date: Tue, 26 May 2026 16:47:26 +0530 Subject: [PATCH 1/2] feat: add GitHub repository comparison feature --- src/Routes/Router.tsx | 2 + src/components/Navbar.tsx | 41 +++--- src/pages/RepoCompare/RepoCompare.tsx | 176 ++++++++++++++++++++++++++ src/utils/github.ts | 13 ++ 4 files changed, 208 insertions(+), 24 deletions(-) create mode 100644 src/pages/RepoCompare/RepoCompare.tsx create mode 100644 src/utils/github.ts diff --git a/src/Routes/Router.tsx b/src/Routes/Router.tsx index 874ef7e7..0972fa13 100644 --- a/src/Routes/Router.tsx +++ b/src/Routes/Router.tsx @@ -9,6 +9,7 @@ import ContributorProfile from "../pages/ContributorProfile/ContributorProfile.t import Home from "../pages/Home/Home.tsx"; import Activity from "../pages/Activity.tsx"; import PrivacyPolicy from "../pages/Privacy/PrivacyPolicy.tsx"; // โœ… Updated import path to match your new folder structure +import RepoCompare from "../pages/RepoCompare/RepoCompare.tsx"; const Router = () => { return ( @@ -22,6 +23,7 @@ const Router = () => { } /> } /> } /> + } /> {/* Privacy Policy page route */} } /> diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index fd5eac86..8c9ba820 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,13 +1,12 @@ import { NavLink, Link } from "react-router-dom"; import { useState, useContext } from "react"; import { ThemeContext } from "../context/ThemeContext"; -import { Moon, Sun, Menu, X, Github } from "lucide-react"; +import { Moon, Sun, Menu, X } from "lucide-react"; const Navbar: React.FC = () => { const [isOpen, setIsOpen] = useState(false); const themeContext = useContext(ThemeContext); - if (!themeContext) return null; const { toggleTheme, mode } = themeContext; @@ -35,7 +34,6 @@ const Navbar: React.FC = () => { alt="CRL Icon" className="h-8 w-8 object-contain" /> - GitHub Tracker @@ -49,6 +47,11 @@ const Navbar: React.FC = () => { Tracker + {/* โœ… NEW FEATURE */} + + Compare + + Contributors @@ -107,37 +110,27 @@ const Navbar: React.FC = () => {
- + Home - + Tracker - + {/* โœ… NEW FEATURE */} + + Compare + + + Contributors - + Login +
)} @@ -145,4 +138,4 @@ const Navbar: React.FC = () => { ); }; -export default Navbar; +export default Navbar; \ No newline at end of file diff --git a/src/pages/RepoCompare/RepoCompare.tsx b/src/pages/RepoCompare/RepoCompare.tsx new file mode 100644 index 00000000..d4a5a453 --- /dev/null +++ b/src/pages/RepoCompare/RepoCompare.tsx @@ -0,0 +1,176 @@ +import { useState } from "react"; + +type RepoData = { + full_name: string; + stargazers_count: number; + forks_count: number; + open_issues_count: number; + watchers_count: number; + language: string; + updated_at: string; + description: string; +}; + +const RepoCompare = () => { + const [repo1, setRepo1] = useState(""); + const [repo2, setRepo2] = useState(""); + + const [data1, setData1] = useState(null); + const [data2, setData2] = useState(null); + + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + + const fetchRepo = async (repo: string): Promise => { + const res = await fetch(`https://api.github.com/repos/${repo}`); + + if (!res.ok) { + throw new Error(`Repository not found: ${repo}`); + } + + return res.json(); + }; + + const handleCompare = async () => { + if (!repo1 || !repo2) { + setError("Please enter both repositories"); + return; + } + + try { + setLoading(true); + setError(""); + + const [r1, r2] = await Promise.all([ + fetchRepo(repo1), + fetchRepo(repo2), + ]); + + setData1(r1); + setData2(r2); + } catch (err: any) { + setError(err.message || "Something went wrong"); + } finally { + setLoading(false); + } + }; + + const formatDate = (date: string) => { + return new Date(date).toLocaleDateString(); + }; + + return ( +
+

๐Ÿ” GitHub Repo Comparison

+ + {/* INPUT SECTION */} +
+ setRepo1(e.target.value)} + style={{ flex: 1, padding: "10px" }} + /> + + setRepo2(e.target.value)} + style={{ flex: 1, padding: "10px" }} + /> + + +
+ + {/* ERROR */} + {error && ( +
{error}
+ )} + + {/* LOADING */} + {loading &&

Loading comparison...

} + + {/* RESULT TABLE */} + {data1 && data2 && ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Metric{data1.full_name}{data2.full_name}
โญ Stars{data1.stargazers_count}{data2.stargazers_count}
๐Ÿด Forks{data1.forks_count}{data2.forks_count}
๐Ÿ› Issues{data1.open_issues_count}{data2.open_issues_count}
๐Ÿ‘€ Watchers{data1.watchers_count}{data2.watchers_count}
๐Ÿ’ป Language{data1.language}{data2.language}
๐Ÿ“… Last Updated{formatDate(data1.updated_at)}{formatDate(data2.updated_at)}
๐Ÿงพ Description{data1.description}{data2.description}
+
+ )} +
+ ); +}; + +const thStyle: React.CSSProperties = { + border: "1px solid #ddd", + padding: "10px", + background: "#f4f4f4", +}; + +const tdStyle: React.CSSProperties = { + border: "1px solid #ddd", + padding: "10px", +}; + +export default RepoCompare; \ No newline at end of file diff --git a/src/utils/github.ts b/src/utils/github.ts new file mode 100644 index 00000000..2b08dfe5 --- /dev/null +++ b/src/utils/github.ts @@ -0,0 +1,13 @@ +export async function fetchRepo(repo: string) { + const res = await fetch(`https://api.github.com/repos/${repo}`); + return res.json(); +} + +export async function compareRepos(repo1: string, repo2: string) { + const [a, b] = await Promise.all([ + fetchRepo(repo1), + fetchRepo(repo2), + ]); + + return { a, b }; +} \ No newline at end of file From 6e38e68f18040dc672cf49f868ffbb12671ed4a7 Mon Sep 17 00:00:00 2001 From: Prem Dhakad Date: Tue, 26 May 2026 22:17:11 +0530 Subject: [PATCH 2/2] Update src/utils/github.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/utils/github.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utils/github.ts b/src/utils/github.ts index 2b08dfe5..e3621fdd 100644 --- a/src/utils/github.ts +++ b/src/utils/github.ts @@ -1,7 +1,12 @@ export async function fetchRepo(repo: string) { - const res = await fetch(`https://api.github.com/repos/${repo}`); + const normalizedRepo = repo.trim(); + const res = await fetch(`https://api.github.com/repos/${normalizedRepo}`); + if (!res.ok) { + throw new Error(`Repository not found: ${normalizedRepo}`); + } return res.json(); } +} export async function compareRepos(repo1: string, repo2: string) { const [a, b] = await Promise.all([