Skip to content

Commit a94f617

Browse files
authored
feat(contributors): added contributors page (#444)
* added contributors page * added debounce to prefetch, acked PR comments
1 parent c5727ef commit a94f617

File tree

10 files changed

+1135
-20
lines changed

10 files changed

+1135
-20
lines changed
Lines changed: 165 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use server'
22

3+
import { env } from '@/lib/env'
4+
35
/**
46
* Format a number to a human-readable format (e.g., 1000 -> 1k, 1100 -> 1.1k)
57
*/
@@ -8,10 +10,8 @@ function formatNumber(num: number): string {
810
return num.toString()
911
}
1012

11-
// Convert to one decimal place and remove trailing 0
1213
const formatted = (Math.round(num / 100) / 10).toFixed(1)
1314

14-
// Remove .0 if the decimal is 0
1515
return formatted.endsWith('.0') ? `${formatted.slice(0, -2)}k` : `${formatted}k`
1616
}
1717

@@ -20,7 +20,7 @@ function formatNumber(num: number): string {
2020
*/
2121
export async function getFormattedGitHubStars(): Promise<string> {
2222
try {
23-
const token = process.env.GITHUB_TOKEN
23+
const token = env.GITHUB_TOKEN
2424

2525
const response = await fetch('https://api.github.com/repos/simstudioai/sim', {
2626
headers: {
@@ -29,18 +29,176 @@ export async function getFormattedGitHubStars(): Promise<string> {
2929
'User-Agent': 'SimStudio/1.0',
3030
...(token ? { Authorization: `Bearer ${token}` } : {}),
3131
},
32-
next: { revalidate: 3600 }, // Revalidate every hour
32+
next: { revalidate: 3600 },
3333
})
3434

3535
if (!response.ok) {
3636
console.error(`GitHub API error: ${response.status} ${response.statusText}`)
37-
return formatNumber(1200)
37+
return formatNumber(3867)
3838
}
3939

4040
const data = await response.json()
41-
return formatNumber(data.stargazers_count || 1200)
41+
return formatNumber(data.stargazers_count || 3867)
4242
} catch (error) {
4343
console.error('Error fetching GitHub stars:', error)
44-
return formatNumber(1200)
44+
return formatNumber(3867)
45+
}
46+
}
47+
48+
interface Contributor {
49+
login: string
50+
avatar_url: string
51+
contributions: number
52+
html_url: string
53+
}
54+
55+
interface CommitData {
56+
sha: string
57+
commit: {
58+
author: {
59+
name: string
60+
email: string
61+
date: string
62+
}
63+
message: string
64+
}
65+
html_url: string
66+
}
67+
68+
interface RepoStats {
69+
stars: number
70+
forks: number
71+
watchers: number
72+
openIssues: number
73+
openPRs: number
74+
}
75+
76+
/**
77+
* Server action to fetch repository statistics
78+
*/
79+
export async function getRepositoryStats(): Promise<RepoStats> {
80+
try {
81+
const token = env.GITHUB_TOKEN
82+
83+
const headers = {
84+
Accept: 'application/vnd.github+json',
85+
'X-GitHub-Api-Version': '2022-11-28',
86+
'User-Agent': 'SimStudio/1.0',
87+
...(token ? { Authorization: `Bearer ${token}` } : {}),
88+
}
89+
90+
const repoResponse = await fetch('https://api.github.com/repos/simstudioai/sim', {
91+
headers,
92+
next: { revalidate: 3600 },
93+
})
94+
95+
const prsResponse = await fetch(
96+
'https://api.github.com/repos/simstudioai/sim/pulls?state=open',
97+
{
98+
headers,
99+
next: { revalidate: 3600 },
100+
}
101+
)
102+
103+
if (!repoResponse.ok || !prsResponse.ok) {
104+
console.error('GitHub API error fetching repo stats')
105+
return {
106+
stars: 3867,
107+
forks: 581,
108+
watchers: 26,
109+
openIssues: 23,
110+
openPRs: 3,
111+
}
112+
}
113+
114+
const repoData = await repoResponse.json()
115+
const prsData = await prsResponse.json()
116+
117+
return {
118+
stars: repoData.stargazers_count || 3867,
119+
forks: repoData.forks_count || 581,
120+
watchers: repoData.subscribers_count || 26,
121+
openIssues: (repoData.open_issues_count || 26) - prsData.length,
122+
openPRs: prsData.length || 3,
123+
}
124+
} catch (error) {
125+
console.error('Error fetching repository stats:', error)
126+
return {
127+
stars: 3867,
128+
forks: 581,
129+
watchers: 26,
130+
openIssues: 23,
131+
openPRs: 3,
132+
}
133+
}
134+
}
135+
136+
/**
137+
* Server action to fetch contributors
138+
*/
139+
export async function getContributors(): Promise<Contributor[]> {
140+
try {
141+
const token = env.GITHUB_TOKEN
142+
143+
const headers = {
144+
Accept: 'application/vnd.github+json',
145+
'X-GitHub-Api-Version': '2022-11-28',
146+
'User-Agent': 'SimStudio/1.0',
147+
...(token ? { Authorization: `Bearer ${token}` } : {}),
148+
}
149+
150+
const response = await fetch(
151+
'https://api.github.com/repos/simstudioai/sim/contributors?per_page=100',
152+
{
153+
headers,
154+
next: { revalidate: 3600 },
155+
}
156+
)
157+
158+
if (!response.ok) {
159+
console.error('GitHub API error fetching contributors')
160+
return []
161+
}
162+
163+
const contributors = await response.json()
164+
return contributors || []
165+
} catch (error) {
166+
console.error('Error fetching contributors:', error)
167+
return []
168+
}
169+
}
170+
171+
/**
172+
* Server action to fetch recent commits for timeline data
173+
*/
174+
export async function getCommitsData(): Promise<CommitData[]> {
175+
try {
176+
const token = env.GITHUB_TOKEN
177+
178+
const headers = {
179+
Accept: 'application/vnd.github+json',
180+
'X-GitHub-Api-Version': '2022-11-28',
181+
'User-Agent': 'SimStudio/1.0',
182+
...(token ? { Authorization: `Bearer ${token}` } : {}),
183+
}
184+
185+
const response = await fetch(
186+
'https://api.github.com/repos/simstudioai/sim/commits?per_page=100',
187+
{
188+
headers,
189+
next: { revalidate: 3600 },
190+
}
191+
)
192+
193+
if (!response.ok) {
194+
console.error('GitHub API error fetching commits')
195+
return []
196+
}
197+
198+
const commits = await response.json()
199+
return commits || []
200+
} catch (error) {
201+
console.error('Error fetching commits:', error)
202+
return []
45203
}
46204
}

apps/sim/app/(landing)/components/nav-client.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ import {
1515
SheetTitle,
1616
SheetTrigger,
1717
} from '@/components/ui/sheet'
18-
import { createLogger } from '@/lib/logs/console-logger'
19-
20-
const _logger = createLogger('NavClient')
18+
import { usePrefetchOnHover } from '../utils/prefetch'
2119

2220
// --- Framer Motion Variants ---
2321
const desktopNavContainerVariants = {
@@ -90,9 +88,11 @@ const NavLinks = ({
9088
...(currentPath !== '/' ? [{ href: '/', label: 'Home' }] : []),
9189
{ href: 'https://docs.simstudio.ai/', label: 'Docs', external: true },
9290
// { href: '/', label: 'Blog' },
93-
{ href: 'https://github.com/simstudioai/sim', label: 'Contributors', external: true },
91+
{ href: '/contributors', label: 'Contributors' },
9492
]
9593

94+
const handleContributorsHover = usePrefetchOnHover()
95+
9696
// Common CSS class for navigation items
9797
const navItemClass = `text-white/60 hover:text-white/100 text-base ${
9898
mobile ? 'p-2.5 text-lg font-medium text-left' : 'p-1.5'
@@ -106,6 +106,7 @@ const NavLinks = ({
106106
<Link
107107
href={link.href}
108108
className={navItemClass}
109+
onMouseEnter={link.label === 'Contributors' ? handleContributorsHover : undefined}
109110
{...(link.external ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
110111
>
111112
{link.label}

apps/sim/app/(landing)/components/sections/footer.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useRouter } from 'next/navigation'
66
import { DiscordIcon, GithubIcon, xIcon as XIcon } from '@/components/icons'
77
import { Button } from '@/components/ui/button'
88
import { useSession } from '@/lib/auth-client'
9+
import { usePrefetchOnHover } from '../../utils/prefetch'
910
import useIsMobile from '../hooks/use-is-mobile'
1011

1112
function Footer() {
@@ -14,6 +15,8 @@ function Footer() {
1415
const { data: session, isPending } = useSession()
1516
const isAuthenticated = !isPending && !!session?.user
1617

18+
const handleContributorsHover = usePrefetchOnHover()
19+
1720
const handleNavigate = () => {
1821
if (typeof window !== 'undefined') {
1922
// Check if user has an active session
@@ -95,10 +98,9 @@ function Footer() {
9598
Docs
9699
</Link>
97100
<Link
98-
href={'https://github.com/simstudioai/sim'}
99-
target='_blank'
100-
rel='noopener noreferrer'
101+
href={'/contributors'}
101102
className='font-light text-[#9E91AA] text-xl transition-all duration-500 hover:text-[#bdaecb] md:text-2xl'
103+
onMouseEnter={handleContributorsHover}
102104
>
103105
Contributors
104106
</Link>
@@ -274,10 +276,9 @@ function Footer() {
274276
Docs
275277
</Link>
276278
<Link
277-
href={'https://github.com/simstudioai/sim'}
278-
target='_blank'
279-
rel='noopener noreferrer'
279+
href={'/contributors'}
280280
className='font-light text-[#9E91AA] text-xl transition-all duration-500 hover:text-[#bdaecb] md:text-2xl'
281+
onMouseEnter={handleContributorsHover}
281282
>
282283
Contributors
283284
</Link>

0 commit comments

Comments
 (0)