Skip to content

Commit 07e8713

Browse files
authored
Merge pull request #5068 from codeharborhub/dev-6
update UI of home page
2 parents 218f110 + dcfc9af commit 07e8713

22 files changed

Lines changed: 7665 additions & 1118 deletions

File tree

‎src/components/ContributorList/contributors.css‎

Lines changed: 907 additions & 61 deletions
Large diffs are not rendered by default.
Lines changed: 276 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,325 @@
1-
import React, { useEffect, useState } from "react";
2-
import { Octokit } from "@octokit/rest";
3-
import "./contributors.css";
1+
import React, { useEffect, useMemo, useState } from "react";
42
import Translate from "@docusaurus/Translate";
3+
import {
4+
ArrowUpRight,
5+
GitBranch,
6+
Github,
7+
Heart,
8+
Users,
9+
} from "lucide-react";
10+
11+
import "./contributors.css";
512

613
type Contributor = {
714
login: string;
815
contributions: number;
916
html_url: string;
1017
avatar_url: string;
18+
type?: string;
1119
};
1220

13-
// per page max 99 items
14-
type ContibutorProps = {
15-
contributorsPerPage: number;
16-
contributorsIgnore: Array<string>;
21+
type ContributorProps = {
22+
contributorsPerPage?: number;
23+
contributorsIgnore?: string[];
1724
};
1825

19-
const defaultIgnoreContributors: string[] = [
26+
const DEFAULT_IGNORE_CONTRIBUTORS = [
2027
"restyled-commits",
2128
"dependabot",
2229
"renovate",
2330
];
24-
const ContributorList: React.FC<ContibutorProps> = ({
31+
32+
const GITHUB_OWNER = "CodeHarborHub";
33+
const GITHUB_REPO = "codeharborhub.github.io";
34+
35+
const ContributorList: React.FC<ContributorProps> = ({
2536
contributorsPerPage = 99,
26-
contributorsIgnore = defaultIgnoreContributors,
27-
}: ContibutorProps) => {
28-
const [contributors, setContributors] = useState<Contributor>([]);
37+
contributorsIgnore = DEFAULT_IGNORE_CONTRIBUTORS,
38+
}) => {
39+
const [contributors, setContributors] = useState<Contributor[]>([]);
40+
const [loading, setLoading] = useState(true);
41+
const [error, setError] = useState(false);
42+
2943
useEffect(() => {
44+
const controller = new AbortController();
45+
3046
const fetchContributors = async () => {
31-
const octokit = new Octokit();
3247
try {
33-
const response = await octokit.request(
34-
`GET /repos/{owner}/{repo}/contributors?per_page=${contributorsPerPage + contributorsIgnore.length}`,
48+
setLoading(true);
49+
setError(false);
50+
51+
const perPage = Math.min(
52+
Math.max(contributorsPerPage + contributorsIgnore.length, 1),
53+
100,
54+
);
55+
56+
const response = await fetch(
57+
`https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contributors?per_page=${perPage}`,
3558
{
36-
owner: "codeharborhub",
37-
repo: "codeharborhub.github.io",
3859
headers: {
60+
Accept: "application/vnd.github+json",
3961
"X-GitHub-Api-Version": "2022-11-28",
4062
},
63+
signal: controller.signal,
4164
},
4265
);
43-
const filteredContributors = response.data.filter(
44-
(contribuidor: Contributor) =>
45-
!contributorsIgnore.some((element) =>
46-
contribuidor.login.toLowerCase().includes(element.toLowerCase()),
47-
),
66+
67+
if (!response.ok) {
68+
throw new Error(`GitHub API error: ${response.status}`);
69+
}
70+
71+
const data: Contributor[] = await response.json();
72+
73+
const ignored = contributorsIgnore.map((login) =>
74+
login.toLowerCase(),
4875
);
4976

50-
setContributors(filteredContributors);
51-
} catch (error) {
52-
console.error("Error fetching contributors:", error);
77+
const filtered = data
78+
.filter((contributor) => {
79+
const login = contributor.login.toLowerCase();
80+
81+
return (
82+
!ignored.includes(login) &&
83+
!ignored.some((ignoredLogin) =>
84+
login.includes(ignoredLogin),
85+
)
86+
);
87+
})
88+
.slice(0, contributorsPerPage);
89+
90+
setContributors(filtered);
91+
} catch (fetchError) {
92+
if (
93+
fetchError instanceof DOMException &&
94+
fetchError.name === "AbortError"
95+
) {
96+
return;
97+
}
98+
99+
console.error("Failed to fetch CodeHarborHub contributors:", fetchError);
100+
setError(true);
101+
} finally {
102+
if (!controller.signal.aborted) {
103+
setLoading(false);
104+
}
53105
}
54106
};
55107

56108
fetchContributors();
57-
}, []);
109+
110+
return () => {
111+
controller.abort();
112+
};
113+
}, [contributorsPerPage, contributorsIgnore]);
114+
115+
const contributorRows = useMemo(() => {
116+
const rows: Contributor[][] = [[], [], []];
117+
118+
contributors.forEach((contributor, index) => {
119+
rows[index % 3].push(contributor);
120+
});
121+
122+
return rows;
123+
}, [contributors]);
124+
125+
const githubContributorsUrl = `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/graphs/contributors`;
58126

59127
return (
60-
<>
61-
<div className="father-flex-div mb-6">
62-
<p className="intro">
63-
<Translate
64-
id="contributors.thankYouMessage"
65-
description="Thank you message for contributors"
66-
values={{
67-
projectName: (
68-
<a href="https://codeharborhub.github.io">
69-
<i>CodeHarborHub</i>
70-
</a>
71-
),
72-
}}
128+
<section
129+
className="contributors-section"
130+
aria-labelledby="contributors-title"
131+
>
132+
<div className="contributors-section__container">
133+
{/* Decorative background */}
134+
<div
135+
className="contributors-section__glow contributors-section__glow--one"
136+
aria-hidden="true"
137+
/>
138+
139+
<div
140+
className="contributors-section__glow contributors-section__glow--two"
141+
aria-hidden="true"
142+
/>
143+
144+
{/* Header */}
145+
<header className="contributors-section__header">
146+
<div className="contributors-section__eyebrow">
147+
<GitBranch size={15} aria-hidden="true" />
148+
<span>OPEN SOURCE COMMUNITY</span>
149+
</div>
150+
151+
<h2
152+
id="contributors-title"
153+
className="contributors-section__title"
73154
>
74-
{`Our heartfelt thanks to the incredible contributors making {projectName} a premier destination for developers. From code to documentation, your expertise
75-
shapes this harbor. Together, we're building a faster, better, and more
76-
inclusive open-source ecosystem.`}
77-
</Translate>
78-
</p>
79-
<div className="grid">
80-
{[0, 1, 2].map((value) => {
81-
const middle = Math.ceil(contributors.length / 3);
82-
const start = value === 0 ? 0 : middle * value;
83-
const end =
84-
value === 0
85-
? middle
86-
: value === 1
87-
? middle * 2
88-
: contributors.length;
155+
Built by{" "}
156+
<span>contributors</span>,
157+
powered by community.
158+
</h2>
89159

90-
return (
91-
<div className="grid-item fade-horizontal" key={value}>
92-
{contributors.slice(start, end).map((contributor) => (
93-
<div className="circle">
160+
<p className="contributors-section__description">
161+
CodeHarborHub grows because developers, writers, designers,
162+
and open-source contributors come together to build something
163+
useful for everyone.
164+
</p>
165+
</header>
166+
167+
{/* Main contributor panel */}
168+
<div className="contributors-section__panel">
169+
<div className="contributors-section__panel-header">
170+
<div className="contributors-section__panel-title">
171+
<div className="contributors-section__icon">
172+
<Users size={20} aria-hidden="true" />
173+
</div>
174+
175+
<div>
176+
<h3>Our contributors</h3>
177+
178+
<p>
179+
Every contribution helps make the harbor stronger.
180+
</p>
181+
</div>
182+
</div>
183+
184+
{!loading && !error && (
185+
<div className="contributors-section__count">
186+
<strong>{contributors.length}</strong>
187+
<span>featured contributors</span>
188+
</div>
189+
)}
190+
</div>
191+
192+
{/* Loading */}
193+
{loading && (
194+
<div
195+
className="contributors-section__loading"
196+
aria-label="Loading contributors"
197+
>
198+
{[...Array(42)].map((_, index) => (
199+
<span
200+
key={index}
201+
className="contributors-section__skeleton"
202+
/>
203+
))}
204+
</div>
205+
)}
206+
207+
{/* Error */}
208+
{!loading && error && (
209+
<div className="contributors-section__error">
210+
<div className="contributors-section__error-icon">
211+
<Github size={22} aria-hidden="true" />
212+
</div>
213+
214+
<div>
215+
<strong>Contributors couldn't be loaded.</strong>
216+
<p>
217+
Please visit our GitHub repository to see the latest
218+
contributor list.
219+
</p>
220+
</div>
221+
222+
<a
223+
href={githubContributorsUrl}
224+
target="_blank"
225+
rel="noopener noreferrer"
226+
className="contributors-section__error-link"
227+
>
228+
View on GitHub
229+
<ArrowUpRight size={16} aria-hidden="true" />
230+
</a>
231+
</div>
232+
)}
233+
234+
{/* Contributors */}
235+
{!loading && !error && contributors.length > 0 && (
236+
<div className="contributors-section__avatars">
237+
{contributorRows.map((row, rowIndex) => (
238+
<div
239+
className="contributors-section__avatar-row"
240+
key={`row-${rowIndex}`}
241+
>
242+
{row.map((contributor) => (
94243
<a
95244
href={contributor.html_url}
96245
target="_blank"
246+
rel="noopener noreferrer"
247+
className="contributor-avatar"
97248
key={contributor.login}
249+
title={`${contributor.login} · ${contributor.contributions} contributions`}
250+
aria-label={`View ${contributor.login} on GitHub`}
98251
>
99252
<img
100-
className="circle"
101253
src={contributor.avatar_url}
102-
alt={`${contributor.login}'s avatar`}
254+
alt=""
255+
loading="lazy"
256+
width="48"
257+
height="48"
103258
/>
259+
260+
<span className="contributor-avatar__tooltip">
261+
<strong>{contributor.login}</strong>
262+
<small>
263+
{contributor.contributions} contributions
264+
</small>
265+
</span>
104266
</a>
105-
</div>
106-
))}
107-
</div>
108-
);
109-
})}
267+
))}
268+
</div>
269+
))}
270+
</div>
271+
)}
272+
273+
{/* Empty */}
274+
{!loading && !error && contributors.length === 0 && (
275+
<div className="contributors-section__empty">
276+
No contributors are currently available.
277+
</div>
278+
)}
279+
280+
{/* Footer */}
281+
<div className="contributors-section__panel-footer">
282+
<div className="contributors-section__thanks">
283+
<Heart size={16} aria-hidden="true" />
284+
285+
<span>
286+
<Translate
287+
id="contributors.thankYouMessage"
288+
description="Thank you message for CodeHarborHub contributors"
289+
values={{
290+
projectName: (
291+
<a
292+
href="https://codeharborhub.github.io"
293+
target="_blank"
294+
rel="noopener noreferrer"
295+
>
296+
CodeHarborHub
297+
</a>
298+
),
299+
}}
300+
>
301+
{
302+
"Thank you to every contributor helping {projectName} become a better place to learn, build, and collaborate."
303+
}
304+
</Translate>
305+
</span>
306+
</div>
307+
308+
<a
309+
href={githubContributorsUrl}
310+
target="_blank"
311+
rel="noopener noreferrer"
312+
className="contributors-section__github-button"
313+
>
314+
<Github size={17} aria-hidden="true" />
315+
<span>View all contributors</span>
316+
<ArrowUpRight size={16} aria-hidden="true" />
317+
</a>
318+
</div>
110319
</div>
111320
</div>
112-
</>
321+
</section>
113322
);
114323
};
115324

116-
export default ContributorList;
325+
export default ContributorList;

0 commit comments

Comments
 (0)