Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 86 additions & 1 deletion src/pages/HomePage.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useRef, useEffect, useCallback } from "react";
import { useApp } from "@/context/AppContext";
import { searchRepos } from "@/api/github";
import { searchRepos, getTrendingRepos } from "@/api/github";
import RepoCard from "@/components/RepoCard";
import FilterChips from "@/components/FilterChips";
import {
Expand All @@ -11,6 +11,7 @@ import {
FiLayers,
FiLoader,
FiBookmark,
FiTrendingUp,
} from "react-icons/fi";
import { formatNumber } from '@/utils/format';

Expand Down Expand Up @@ -58,6 +59,12 @@ export default function HomePage() {
});
const [stats, setStats] = useState({ repos: 0, languages: 0, topics: 0 });

// Trending section state
const [trendingTimeRange, setTrendingTimeRange] = useState('weekly');
const [trendingRepos, setTrendingRepos] = useState([]);
const [loadingTrending, setLoadingTrending] = useState(true);
const [trendingError, setTrendingError] = useState(null);

const fetchRepos = useCallback(
async (searchQuery, searchFilters, searchPage = 1) => {
setLoading(true);
Expand Down Expand Up @@ -165,6 +172,23 @@ export default function HomePage() {
fetchRepos("", filters, 1);
}, []); // eslint-disable-line react-hooks/exhaustive-deps

// Fetch trending repos
useEffect(() => {
async function fetchTrendingData() {
setLoadingTrending(true);
setTrendingError(null);
try {
const data = await getTrendingRepos(trendingTimeRange, '', 1, 10);
setTrendingRepos(data?.items || []);
} catch (err) {
setTrendingError(err.message || "Failed to fetch trending repos");
} finally {
setLoadingTrending(false);
}
}
fetchTrendingData();
}, [trendingTimeRange]);

// Refetch when filters change
const handleFiltersChange = (newFilters) => {
setFilters(newFilters);
Expand Down Expand Up @@ -360,6 +384,67 @@ export default function HomePage() {
</div>
</section>

{/* ═══════ TRENDING REPOS ═══════ */}
<section className="bg-surface dark:bg-[#0F1117] py-10 border-b border-gray-200/40 dark:border-gray-800/40">
<div className="max-w-7xl mx-auto px-4 sm:px-6">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
<h2 className="text-xl sm:text-2xl font-extrabold text-gray-900 dark:text-gray-50 flex items-center gap-2">
<FiTrendingUp className="text-orange-500" />
Trending Repos
</h2>
<div className="inline-flex bg-gray-100 dark:bg-[#161A22] p-1 rounded-xl">
<button
onClick={() => setTrendingTimeRange('weekly')}
className={`px-4 py-1.5 text-sm font-bold rounded-lg transition-all duration-200 ${
trendingTimeRange === 'weekly'
? 'bg-white dark:bg-gray-800 text-orange-600 shadow-sm'
: 'text-gray-500 hover:text-gray-700 dark:text-gray-400'
}`}
>
This Week
</button>
<button
onClick={() => setTrendingTimeRange('monthly')}
className={`px-4 py-1.5 text-sm font-bold rounded-lg transition-all duration-200 ${
trendingTimeRange === 'monthly'
? 'bg-white dark:bg-gray-800 text-orange-600 shadow-sm'
: 'text-gray-500 hover:text-gray-700 dark:text-gray-400'
}`}
>
This Month
</button>
</div>
</div>

{trendingError ? (
<div className="text-center py-8">
<div className="inline-flex items-center gap-2 px-4 py-3 bg-red-50 dark:bg-red-950/20 border border-red-200 text-red-600 text-sm font-medium rounded-xl">
⚠️ {trendingError}
</div>
</div>
) : (
<div className="flex overflow-x-auto gap-5 pb-4 snap-x hide-scrollbar">
{loadingTrending
? Array.from({ length: 4 }).map((_, i) => (
<div key={i} className="min-w-[300px] sm:min-w-[350px] snap-center">
<RepoCardSkeleton />
</div>
))
: trendingRepos.map((repo) => (
<div key={repo.id} className="min-w-[300px] sm:min-w-[350px] snap-center">
<div className="relative">
<div className="absolute -top-2.5 -right-2.5 z-10 flex items-center gap-1 px-2.5 py-1 bg-orange-500 text-white text-[10px] font-extrabold uppercase tracking-wider rounded-full shadow-lg">
🔥 Trending
</div>
<RepoCard repo={repo} />
</div>
</div>
))}
</div>
)}
</div>
</section>

{/* ═══════ FILTERS + GRID ═══════ */}
<section className="max-w-7xl mx-auto px-4 sm:px-6 py-10">
{/* Tabs */}
Expand Down