Skip to content
Merged
Show file tree
Hide file tree
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
227 changes: 111 additions & 116 deletions src/pages/Contributors.jsx
Original file line number Diff line number Diff line change
@@ -1,154 +1,149 @@
import React, { useState, useEffect } from 'react';
import { Users, GitFork, Star, ExternalLink } from 'lucide-react';
// Re-importing icons for the stats
import { Users, GitFork, Star } from 'lucide-react';

export default function ContributorsWall() {
const [contributors, setContributors] = useState([]);
const [repoInfo, setRepoInfo] = useState(null); // State for repo info
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [repoInfo, setRepoInfo] = useState(null);

useEffect(() => {
fetchContributors();
fetchRepoInfo();
}, []);
// Fetch both contributors and repo info at the same time
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const [repoRes, contributorsRes] = await Promise.all([
fetch('https://api.github.com/repos/commitra/react-verse'),
fetch('https://api.github.com/repos/commitra/react-verse/contributors?per_page=100')
]);

const fetchRepoInfo = async () => {
try {
const response = await fetch('https://api.github.com/repos/commitra/react-verse');
const data = await response.json();
setRepoInfo(data);
} catch (err) {
console.error('Error fetching repo info:', err);
}
};
// Check both responses
if (!repoRes.ok) {
throw new Error(`Failed to fetch repo info: ${repoRes.statusText}`);
}
if (!contributorsRes.ok) {
throw new Error(`Failed to fetch contributors: ${contributorsRes.statusText}`);
}

const fetchContributors = async () => {
try {
setLoading(true);
const response = await fetch(
'https://api.github.com/repos/commitra/react-verse/contributors?per_page=100'
);

if (!response.ok) {
throw new Error('Failed to fetch contributors');
const repoData = await repoRes.json();
const contributorsData = await contributorsRes.json();

setRepoInfo(repoData); // Set the repo info
setContributors(contributorsData);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}

const data = await response.json();
setContributors(data);
setLoading(false);
} catch (err) {
setError(err.message);
setLoading(false);
}
};

fetchData();
}, []); // Empty dependency array ensures this runs once on mount

// Style object for the new stat boxes
// This uses variables from your main stylesheet
const statBoxStyle = {
background: 'var(--bg-alt)',
border: '1px solid var(--border)',
padding: '0.5rem 1rem',
borderRadius: 'var(--radius)',
display: 'flex',
alignItems: 'center',
gap: '0.5rem',
fontSize: '0.9rem',
fontWeight: 500,
color: 'var(--text)'
};

if (loading) {
return (
<div className="min-h-screen bg-gradient-to-br from-purple-900 via-blue-900 to-indigo-900 flex items-center justify-center">
<div className="text-center">
<div className="animate-spin rounded-full h-16 w-16 border-t-4 border-b-4 border-purple-400 mx-auto mb-4"></div>
<p className="text-white text-xl">Loading contributors...</p>
</div>
<div className="container" style={{ textAlign: 'center', paddingTop: '5rem' }}>
<h2 className="loading">Loading contributors...</h2>
</div>
);
}

if (error) {
return (
<div className="min-h-screen bg-gradient-to-br from-purple-900 via-blue-900 to-indigo-900 flex items-center justify-center">
<div className="bg-red-500 bg-opacity-20 border border-red-400 rounded-lg p-6 max-w-md">
<p className="text-red-200 text-center">Error: {error}</p>
</div>
<div className="container" style={{ textAlign: 'center', paddingTop: '5rem' }}>
<h2 className="error">Error: {error}</h2>
<p>You may have hit the GitHub API rate limit. Please try again later.</p>
</div>
);
}

return (
<div className="min-h-screen bg-gradient-to-br from-purple-900 via-blue-900 to-indigo-900 py-12 px-4">
<div className="max-w-7xl mx-auto">
{/* Header */}
<div className="text-center mb-12">
<div className="inline-block bg-purple-500 bg-opacity-20 rounded-full px-6 py-2 mb-4">
<Users className="inline-block mr-2 text-purple-300" size={24} />
<span className="text-purple-200 font-semibold">Wall of Contributors</span>
<main className="container page-transition">

<h1 className="cards-title" style={{ marginTop: '2rem' }}>
React-Verse Contributors
</h1>
<p style={{ textAlign: 'center', fontSize: '1.1rem', opacity: 0.8, marginTop: '-2rem', marginBottom: '3rem' }}>
Honoring the amazing developers who made this project possible.
</p>

{/* --- NEW STATS SECTION --- */}
{repoInfo && (
// Uses .flex and .wrap from your stylesheet
<div
className="flex wrap"
style={{
justifyContent: 'center',
gap: '1rem', // .gap class is 1rem
marginBottom: '3rem'
}}
>
{/* Stat Box for Stars */}
<div style={statBoxStyle}>
<Star size={18} style={{ color: 'var(--primary)' }} />
<span>{repoInfo.stargazers_count} Stars</span>
</div>
<h1 className="text-5xl font-bold text-white mb-4">
React-Verse Contributors
</h1>
<p className="text-blue-200 text-lg mb-6">
Honoring the amazing developers who made this project possible
</p>

{repoInfo && (
<div className="flex justify-center gap-6 text-white">
<div className="flex items-center gap-2 bg-white bg-opacity-10 px-4 py-2 rounded-full">
<Star size={20} className="text-yellow-400" />
<span>{repoInfo.stargazers_count} Stars</span>
</div>
<div className="flex items-center gap-2 bg-white bg-opacity-10 px-4 py-2 rounded-full">
<GitFork size={20} className="text-blue-400" />
<span>{repoInfo.forks_count} Forks</span>
</div>
<div className="flex items-center gap-2 bg-white bg-opacity-10 px-4 py-2 rounded-full">
<Users size={20} className="text-green-400" />
<span>{contributors.length} Contributors</span>
</div>
</div>
)}
{/* Stat Box for Forks */}
<div style={statBoxStyle}>
<GitFork size={18} style={{ color: 'var(--primary)' }} />
<span>{repoInfo.forks_count} Forks</span>
</div>

{/* Stat Box for Contributors */}
<div style={statBoxStyle}>
<Users size={18} style={{ color: 'var(--primary)' }} />
<span>{contributors.length} Contributors</span>
</div>
</div>
)}
{/* --- END OF STATS SECTION --- */}

{/* Repository Link */}
<div className="text-center mb-12">
{/* Uses the .grid class from your stylesheet */}
<div className="grid">
{contributors.map((contributor) => (
<a
href="https://github.com/commitra/react-verse"
key={contributor.id}
href={contributor.html_url}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 bg-white bg-opacity-10 hover:bg-opacity-20 text-white px-6 py-3 rounded-lg transition-all duration-300 hover:scale-105"
style={{ textDecoration: 'none' }}
>
View Repository
<ExternalLink size={18} />
{/* Uses the .card class from your "Recipe" styles */}
<div className="card">
{/* Styled by your ".card img" rule */}
<img
src={contributor.avatar_url}
alt={`${contributor.login}'s avatar`}
loading="lazy"
/>

{/* Styled by your ".card h4" or ".card h3" rule */}
<h4>{contributor.login}</h4>

{/* Styled by your ".card p" rule */}
<p>{contributor.contributions} contributions</p>
</div>
</a>
</div>

{/* Contributors Grid */}
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-6">
{contributors.map((contributor, index) => (
<a
key={contributor.id}
href={contributor.html_url}
target="_blank"
rel="noopener noreferrer"
className="group"
>
<div className="bg-white bg-opacity-10 backdrop-blur-lg rounded-xl p-4 hover:bg-opacity-20 transition-all duration-300 hover:scale-105 hover:shadow-2xl border border-white border-opacity-20">
<div className="relative mb-3">
<img
src={contributor.avatar_url}
alt={contributor.login}
className="w-full aspect-square rounded-full border-4 border-purple-400 group-hover:border-pink-400 transition-colors duration-300"
/>
<div className="absolute -bottom-2 -right-2 bg-gradient-to-r from-purple-500 to-pink-500 text-white text-xs font-bold rounded-full w-8 h-8 flex items-center justify-center border-2 border-white">
#{index + 1}
</div>
</div>
<h3 className="text-white font-semibold text-sm text-center truncate mb-1">
{contributor.login}
</h3>
<p className="text-blue-200 text-xs text-center">
{contributor.contributions} contributions
</p>
</div>
</a>
))}
</div>

{/* Footer */}
<div className="text-center mt-12">
<p className="text-blue-300 text-sm">
Thank you to all our contributors for making React-Verse awesome! 🎉
</p>
</div>
))}
</div>
</div>
</main>
);
}
2 changes: 1 addition & 1 deletion src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -1366,4 +1366,4 @@ footer a {

footer a:hover {
color: var(--primary-hover);
}
}
Loading