diff --git a/src/pages/HomePage.jsx b/src/pages/HomePage.jsx index 7021cd3..314674e 100644 --- a/src/pages/HomePage.jsx +++ b/src/pages/HomePage.jsx @@ -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 { @@ -11,6 +11,7 @@ import { FiLayers, FiLoader, FiBookmark, + FiTrendingUp, } from "react-icons/fi"; import { formatNumber } from '@/utils/format'; @@ -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); @@ -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); @@ -360,6 +384,67 @@ export default function HomePage() { + {/* ═══════ TRENDING REPOS ═══════ */} + + + + + + Trending Repos + + + 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 + + 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 + + + + + {trendingError ? ( + + + ⚠️ {trendingError} + + + ) : ( + + {loadingTrending + ? Array.from({ length: 4 }).map((_, i) => ( + + + + )) + : trendingRepos.map((repo) => ( + + + + 🔥 Trending + + + + + ))} + + )} + + + {/* ═══════ FILTERS + GRID ═══════ */} {/* Tabs */}