Skip to content

Commit 1c710b3

Browse files
Merge pull request #172 from mindfiredigital/dev
add top contributors
2 parents 80519be + 118cb69 commit 1c710b3

File tree

7 files changed

+423
-228
lines changed

7 files changed

+423
-228
lines changed

next.config.js

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,36 @@
1-
// /** @type {import('next').NextConfig} */
2-
// const nextConfig = {
3-
// images: {
4-
// unoptimized: true,
5-
// },
6-
// output: "export",
7-
// // distDir: "build" // Optional: Change the output directory `out` -> `build`
8-
// };
9-
10-
// module.exports = nextConfig;
11-
12-
const { PHASE_PRODUCTION_BUILD } = require("next/constants");
13-
14-
module.exports = (phase, { defaultConfig }) => {
15-
if (phase === PHASE_PRODUCTION_BUILD) {
16-
return {
17-
images: {
18-
unoptimized: true,
19-
},
20-
output: "export",
21-
distDir: "build"
22-
};
23-
}
24-
25-
return {};
26-
};
1+
// /** @type {import('next').NextConfig} */
2+
// const nextConfig = {
3+
// images: {
4+
// unoptimized: true,
5+
// },
6+
// output: "export",
7+
// // distDir: "build" // Optional: Change the output directory `out` -> `build`
8+
// };
9+
10+
// module.exports = nextConfig;
11+
12+
const { PHASE_PRODUCTION_BUILD } = require("next/constants");
13+
14+
module.exports = (phase, { defaultConfig }) => {
15+
const images = {
16+
unoptimized: true,
17+
remotePatterns: [
18+
{
19+
protocol: 'https',
20+
hostname: 'avatars.githubusercontent.com',
21+
},
22+
],
23+
};
24+
25+
if (phase === PHASE_PRODUCTION_BUILD) {
26+
return {
27+
images,
28+
output: "export",
29+
distDir: "build"
30+
};
31+
}
32+
33+
return {
34+
images,
35+
};
36+
};
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"use client";
2+
3+
import React from "react";
4+
import Image from "next/image";
5+
import Link from "next/link";
6+
7+
interface Contributor {
8+
login: string;
9+
avatar_url: string;
10+
html_url: string;
11+
contributions: number;
12+
lastActiveDays: number | null;
13+
}
14+
15+
interface TopContributorsProps {
16+
contributors: Contributor[];
17+
}
18+
19+
const TopContributors = ({ contributors }: TopContributorsProps) => {
20+
const getLastActiveText = (days: number | null): string => {
21+
if (days === null) return "No recent activity";
22+
if (days === 0) return "Active today";
23+
if (days === 1) return "Active yesterday";
24+
return `Active ${days} days ago`;
25+
};
26+
27+
return (
28+
<div className='relative items-center max-w-5xl mx-auto px-4 py-8'>
29+
{/* Contributors scroll container */}
30+
<div className='flex gap-6 overflow-x-auto scrollbar-hide snap-x snap-mandatory scroll-px-6 px-8'>
31+
{contributors.slice(0, 6).map((contributor) => (
32+
<Link
33+
key={contributor.login}
34+
href={contributor.html_url}
35+
target='_blank'
36+
className='flex-shrink-0 snap-center group'
37+
>
38+
<div className='flex flex-col items-center gap-2'>
39+
{/* Avatar with gradient border */}
40+
<div className='p-1 rounded-full bg-gradient-to-tr from-mindfire-text-red via-orange-500 to-yellow-500'>
41+
<div className='p-0.5 rounded-full bg-white'>
42+
<div className='relative w-20 h-20 rounded-full overflow-hidden group-hover:scale-105 transition-transform'>
43+
<Image
44+
src={contributor.avatar_url}
45+
alt={contributor.login}
46+
fill
47+
className='object-cover'
48+
/>
49+
</div>
50+
</div>
51+
</div>
52+
{/* Username and contributions */}
53+
<div className='text-center'>
54+
<p className='font-medium text-sm text-gray-800 truncate max-w-[100px]'>
55+
{contributor.login}
56+
</p>
57+
<p className='text-xs text-gray-500'>
58+
{contributor.contributions} contributions
59+
</p>
60+
<p className='text-xs text-gray-400'>
61+
{getLastActiveText(contributor.lastActiveDays)}
62+
</p>
63+
</div>
64+
</div>
65+
</Link>
66+
))}
67+
</div>
68+
</div>
69+
);
70+
};
71+
72+
export default TopContributors;

src/app/contributors/page.tsx

Lines changed: 142 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,32 @@ import issueImg from "../../../public/images/social-media/git-issue.svg";
77
import Image from "next/image";
88
import contributorList from "../projects/assets/contributors.json";
99
import ContributorCount from "./components/ContributorCount";
10+
import TopContributors from "./components/TopContributors";
11+
12+
interface Contributor {
13+
id: number;
14+
contributions: number;
15+
html_url: string;
16+
avatar_url: string;
17+
login: string;
18+
lastActiveDays: number | null;
19+
}
1020

1121
const Contributors = () => {
12-
const contributorsArray = Object.values(contributorList);
22+
const contributorsArray = Object.values(contributorList) as Contributor[];
23+
24+
// Filter and sort contributors for top section (active in last 30 days)
25+
const activeTopContributors = [...contributorsArray]
26+
.filter(
27+
(contributor) =>
28+
contributor.lastActiveDays === null || contributor.lastActiveDays <= 30
29+
)
30+
.sort((a, b) => b.contributions - a.contributions);
31+
32+
// Sort all contributors by contributions for the main grid
33+
const sortedAllContributors = [...contributorsArray].sort(
34+
(a, b) => b.contributions - a.contributions
35+
);
1336

1437
return (
1538
<>
@@ -21,110 +44,129 @@ const Contributors = () => {
2144
</h1>
2245
<ContributorCount totalContributors={contributorsArray.length} />
2346
</div>
24-
<p className='mt-6 text-xl text-mf-light-grey tracking-wide mb-10'>
25-
We’re a dynamic group of individuals who are passionate about what
26-
we do.
27-
</p>
28-
{contributorsArray ? (
29-
<div className='grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4'>
30-
{contributorsArray.map((contributor) => (
31-
<div
32-
key={contributor.id}
33-
className='bg-white border border-gray-200 rounded-lg shadow-lg transition-transform duration-300 transform hover:scale-105'
34-
>
35-
<div className='p-4'>
36-
<img
37-
className='w-24 h-24 mb-3 rounded-full shadow-lg mx-auto transition-transform duration-300 transform hover:scale-105'
38-
src={contributor.avatar_url}
39-
alt={`Contributor ${contributor.login}`}
40-
/>
41-
<div className='flex justify-center items-center gap-2 mt-4 '>
42-
<Link href={contributor.html_url!} target='_blank'>
43-
<Image
44-
src={github}
45-
height={20}
46-
width={20}
47-
alt='github_img'
48-
loading='lazy'
49-
quality={75}
50-
/>
51-
</Link>
52-
<Link href={contributor.html_url!} target='_blank'>
53-
<h5 className='text-xl font-medium text-gray-900 text-center'>
54-
{contributor.login}
55-
</h5>
56-
</Link>
57-
</div>
58-
<footer>
59-
<div className='grid grid-cols-3 divide-x'>
60-
<div className='flex justify-center items-center gap-1 mt-4 '>
61-
<div>
62-
<Image
63-
src={contributorImg}
64-
height={20}
65-
width={20}
66-
alt='contributor'
67-
loading='lazy'
68-
quality={75}
69-
title='Contributions'
70-
/>
47+
48+
{/* Top Contributors Section */}
49+
<div className='mt-12 flex flex-col items-center justify-center'>
50+
<h2 className='text-2xl font-medium text-gray-800 mb-6'>
51+
Top Active Contributors
52+
</h2>
53+
<p className='text-xl text-mf-light-grey tracking-wide mb-2'>
54+
Meet our top six contributors — the people who help turn ideas
55+
into impact.
56+
</p>
57+
<TopContributors contributors={activeTopContributors} />
58+
</div>
59+
60+
{/* All Contributors Section */}
61+
<div className='mt-12 flex flex-col items-center justify-center'>
62+
<h2 className='text-2xl font-medium text-gray-800 mb-6'>
63+
All Contributors
64+
</h2>
65+
<p className='text-xl text-mf-light-grey tracking-wide mb-10'>
66+
We&apos;re a dynamic group of individuals who are passionate about
67+
what we do.
68+
</p>
69+
{contributorsArray ? (
70+
<div className='grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4'>
71+
{sortedAllContributors.map((contributor) => (
72+
<div
73+
key={contributor.id}
74+
className='bg-white border border-gray-200 rounded-lg shadow-lg transition-transform duration-300 transform hover:scale-105'
75+
>
76+
<div className='p-4'>
77+
<img
78+
className='w-24 h-24 mb-3 rounded-full shadow-lg mx-auto transition-transform duration-300 transform hover:scale-105'
79+
src={contributor.avatar_url}
80+
alt={`Contributor ${contributor.login}`}
81+
/>
82+
<div className='flex justify-center items-center gap-2 mt-4 '>
83+
<Link href={contributor.html_url!} target='_blank'>
84+
<Image
85+
src={github}
86+
height={20}
87+
width={20}
88+
alt='github_img'
89+
loading='lazy'
90+
quality={75}
91+
/>
92+
</Link>
93+
<Link href={contributor.html_url!} target='_blank'>
94+
<h5 className='text-xl font-medium text-gray-900 text-center'>
95+
{contributor.login}
96+
</h5>
97+
</Link>
98+
</div>
99+
<footer>
100+
<div className='grid grid-cols-3 divide-x'>
101+
<div className='flex justify-center items-center gap-1 mt-4 '>
102+
<div>
103+
<Image
104+
src={contributorImg}
105+
height={20}
106+
width={20}
107+
alt='contributor'
108+
loading='lazy'
109+
quality={75}
110+
title='Contributions'
111+
/>
112+
</div>
113+
<p className='text-sm text-gray-500 text-center'>
114+
{contributor.contributions}
115+
</p>
71116
</div>
72-
<p className='text-sm text-gray-500 text-center'>
73-
{contributor.contributions}
74-
</p>
75-
</div>
76-
<div className='flex justify-center items-center gap-1 mt-4 '>
77-
<div>
78-
<Image
79-
src={prImg}
80-
height={20}
81-
width={20}
82-
alt='pull request'
83-
loading='lazy'
84-
quality={75}
85-
title='Pull Requests'
86-
/>
117+
<div className='flex justify-center items-center gap-1 mt-4 '>
118+
<div>
119+
<Image
120+
src={prImg}
121+
height={20}
122+
width={20}
123+
alt='pull request'
124+
loading='lazy'
125+
quality={75}
126+
title='Pull Requests'
127+
/>
128+
</div>
129+
<p className='text-sm text-gray-500 text-center'>
130+
{Math.floor(contributor.contributions / 2)}
131+
</p>
87132
</div>
88-
<p className='text-sm text-gray-500 text-center'>
89-
{Math.floor(contributor.contributions / 2)}
90-
</p>
91-
</div>
92-
<div className='flex justify-center items-center gap-1 mt-4 '>
93-
<div>
94-
<Image
95-
src={issueImg}
96-
height={20}
97-
width={20}
98-
alt='issue'
99-
loading='lazy'
100-
quality={75}
101-
title='Issues'
102-
/>
133+
<div className='flex justify-center items-center gap-1 mt-4 '>
134+
<div>
135+
<Image
136+
src={issueImg}
137+
height={20}
138+
width={20}
139+
alt='issue'
140+
loading='lazy'
141+
quality={75}
142+
title='Issues'
143+
/>
144+
</div>
145+
<p className='text-sm text-gray-500 text-center'>
146+
{Math.floor(contributor.contributions / 4)}
147+
</p>
103148
</div>
104-
<p className='text-sm text-gray-500 text-center'>
105-
{Math.floor(contributor.contributions / 4)}
106-
</p>
107149
</div>
108-
</div>
109-
</footer>
150+
</footer>
151+
</div>
110152
</div>
111-
</div>
112-
))}
113-
</div>
114-
) : (
115-
<div
116-
style={{
117-
display: "flex",
118-
justifyContent: "center",
119-
alignItems: "center",
120-
height: "50vh",
121-
}}
122-
>
123-
<p className='mt-6 text-xl text-mf-light-grey tracking-wide mb-10'>
124-
No records found!
125-
</p>
126-
</div>
127-
)}
153+
))}
154+
</div>
155+
) : (
156+
<div
157+
style={{
158+
display: "flex",
159+
justifyContent: "center",
160+
alignItems: "center",
161+
height: "50vh",
162+
}}
163+
>
164+
<p className='mt-6 text-xl text-mf-light-grey tracking-wide mb-10'>
165+
No records found!
166+
</p>
167+
</div>
168+
)}
169+
</div>
128170
</div>
129171
</section>
130172
</>

0 commit comments

Comments
 (0)