Skip to content

Commit a324ab8

Browse files
committed
added stars and fork
1 parent 3b6cd4a commit a324ab8

1 file changed

Lines changed: 74 additions & 28 deletions

File tree

src/pages/Contributors.jsx

Lines changed: 74 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,65 @@
11
import React, { useState, useEffect } from 'react';
2+
// Re-importing icons for the stats
3+
import { Users, GitFork, Star } from 'lucide-react';
24

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

811
useEffect(() => {
9-
const fetchContributors = async () => {
12+
// Fetch both contributors and repo info at the same time
13+
const fetchData = async () => {
1014
setLoading(true);
1115
setError(null);
1216
try {
13-
const response = await fetch(
14-
'https://api.github.com/repos/commitra/react-verse/contributors?per_page=100'
15-
);
17+
const [repoRes, contributorsRes] = await Promise.all([
18+
fetch('https://api.github.com/repos/commitra/react-verse'),
19+
fetch('https://api.github.com/repos/commitra/react-verse/contributors?per_page=100')
20+
]);
1621

17-
if (!response.ok) {
18-
// This will catch API rate-limit errors (403)
19-
throw new Error(`Failed to fetch contributors: ${response.statusText}`);
22+
// Check both responses
23+
if (!repoRes.ok) {
24+
throw new Error(`Failed to fetch repo info: ${repoRes.statusText}`);
2025
}
26+
if (!contributorsRes.ok) {
27+
throw new Error(`Failed to fetch contributors: ${contributorsRes.statusText}`);
28+
}
29+
30+
const repoData = await repoRes.json();
31+
const contributorsData = await contributorsRes.json();
2132

22-
const data = await response.json();
23-
setContributors(data);
33+
setRepoInfo(repoData); // Set the repo info
34+
setContributors(contributorsData);
2435
} catch (err) {
2536
setError(err.message);
2637
} finally {
2738
setLoading(false);
2839
}
2940
};
3041

31-
fetchContributors();
42+
fetchData();
3243
}, []); // Empty dependency array ensures this runs once on mount
3344

45+
// Style object for the new stat boxes
46+
// This uses variables from your main stylesheet
47+
const statBoxStyle = {
48+
background: 'var(--bg-alt)',
49+
border: '1px solid var(--border)',
50+
padding: '0.5rem 1rem',
51+
borderRadius: 'var(--radius)',
52+
display: 'flex',
53+
alignItems: 'center',
54+
gap: '0.5rem',
55+
fontSize: '0.9rem',
56+
fontWeight: 500,
57+
color: 'var(--text)'
58+
};
59+
3460
if (loading) {
3561
return (
3662
<div className="container" style={{ textAlign: 'center', paddingTop: '5rem' }}>
37-
{/* Uses the .loading class from your stylesheet */}
3863
<h2 className="loading">Loading contributors...</h2>
3964
</div>
4065
);
@@ -43,56 +68,77 @@ export default function ContributorsWall() {
4368
if (error) {
4469
return (
4570
<div className="container" style={{ textAlign: 'center', paddingTop: '5rem' }}>
46-
{/* Uses the .error class from your stylesheet */}
4771
<h2 className="error">Error: {error}</h2>
4872
<p>You may have hit the GitHub API rate limit. Please try again later.</p>
4973
</div>
5074
);
5175
}
5276

5377
return (
54-
// Uses .container for padding and .page-transition for the animation
5578
<main className="container page-transition">
5679

57-
{/* Uses .cards-title from your "Recipe" styles for a nice centered header */}
5880
<h1 className="cards-title" style={{ marginTop: '2rem' }}>
5981
React-Verse Contributors
6082
</h1>
6183
<p style={{ textAlign: 'center', fontSize: '1.1rem', opacity: 0.8, marginTop: '-2rem', marginBottom: '3rem' }}>
6284
Honoring the amazing developers who made this project possible.
6385
</p>
6486

65-
{/* Uses the .grid class from your stylesheet for the responsive layout */}
87+
{/* --- NEW STATS SECTION --- */}
88+
{repoInfo && (
89+
// Uses .flex and .wrap from your stylesheet
90+
<div
91+
className="flex wrap"
92+
style={{
93+
justifyContent: 'center',
94+
gap: '1rem', // .gap class is 1rem
95+
marginBottom: '3rem'
96+
}}
97+
>
98+
{/* Stat Box for Stars */}
99+
<div style={statBoxStyle}>
100+
<Star size={18} style={{ color: 'var(--primary)' }} />
101+
<span>{repoInfo.stargazers_count} Stars</span>
102+
</div>
103+
104+
{/* Stat Box for Forks */}
105+
<div style={statBoxStyle}>
106+
<GitFork size={18} style={{ color: 'var(--primary)' }} />
107+
<span>{repoInfo.forks_count} Forks</span>
108+
</div>
109+
110+
{/* Stat Box for Contributors */}
111+
<div style={statBoxStyle}>
112+
<Users size={18} style={{ color: 'var(--primary)' }} />
113+
<span>{contributors.length} Contributors</span>
114+
</div>
115+
</div>
116+
)}
117+
{/* --- END OF STATS SECTION --- */}
118+
119+
{/* Uses the .grid class from your stylesheet */}
66120
<div className="grid">
67121
{contributors.map((contributor) => (
68122
<a
69123
key={contributor.id}
70124
href={contributor.html_url}
71125
target="_blank"
72126
rel="noopener noreferrer"
73-
style={{ textDecoration: 'none' }} // Prevents underline on the card
127+
style={{ textDecoration: 'none' }}
74128
>
75-
{/* Uses the .card class from your "Recipe" styles.
76-
Your CSS file already makes this:
77-
- text-align: center
78-
- have a background, border, and shadow
79-
- animate on hover
80-
*/}
129+
{/* Uses the .card class from your "Recipe" styles */}
81130
<div className="card">
82-
{/* This <img> tag will be styled by your ".card img" rule:
83-
- 130px width/height
84-
- 50% border-radius (a circle)
85-
*/}
131+
{/* Styled by your ".card img" rule */}
86132
<img
87133
src={contributor.avatar_url}
88134
alt={`${contributor.login}'s avatar`}
89135
loading="lazy"
90136
/>
91137

92-
{/* This <h3> will be styled by your ".card h4" or ".card h3" rule */}
138+
{/* Styled by your ".card h4" or ".card h3" rule */}
93139
<h4>{contributor.login}</h4>
94140

95-
{/* This <p> will be styled by your ".card p" rule */}
141+
{/* Styled by your ".card p" rule */}
96142
<p>{contributor.contributions} contributions</p>
97143
</div>
98144
</a>

0 commit comments

Comments
 (0)