Skip to content

Commit 2c0dc68

Browse files
authored
add new root maintainers page with fun filtering and sorting (#449)
1 parent ab2b5c7 commit 2c0dc68

File tree

9 files changed

+1792
-87
lines changed

9 files changed

+1792
-87
lines changed

src/components/MaintainerCard.tsx

Lines changed: 189 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
getPersonsMaintainerOf,
66
} from '~/libraries/maintainers'
77
import { useState } from 'react'
8+
// import { FaCode, FaGitAlt, FaComment, FaEye } from 'react-icons/fa'
89

910
function RoleBadge({
1011
maintainer,
@@ -187,6 +188,69 @@ function MaintainerSocialLinks({ maintainer }: { maintainer: Maintainer }) {
187188
)
188189
}
189190

191+
// GitHub stats component - commented out due to performance/accuracy concerns
192+
/*
193+
function GitHubStats({
194+
username,
195+
stats,
196+
}: {
197+
username: string
198+
stats?: {
199+
totalCommits: number
200+
totalPullRequests: number
201+
totalIssues: number
202+
totalReviews: number
203+
}
204+
}) {
205+
if (!stats) return null
206+
207+
const totalContributions =
208+
stats.totalCommits +
209+
stats.totalPullRequests +
210+
stats.totalIssues +
211+
stats.totalReviews
212+
213+
return (
214+
<div className="flex items-center gap-4 text-sm text-gray-600 dark:text-gray-400">
215+
<div
216+
className="flex items-center gap-1"
217+
title="Total commits to TanStack repositories"
218+
>
219+
<FaCode className="w-3 h-3" />
220+
<span>{stats.totalCommits.toLocaleString()}</span>
221+
</div>
222+
<div
223+
className="flex items-center gap-1"
224+
title="Total pull requests to TanStack repositories"
225+
>
226+
<FaGitAlt className="w-3 h-3" />
227+
<span>{stats.totalPullRequests.toLocaleString()}</span>
228+
</div>
229+
<div
230+
className="flex items-center gap-1"
231+
title="Total issues opened in TanStack repositories"
232+
>
233+
<FaComment className="w-3 h-3" />
234+
<span>{stats.totalIssues.toLocaleString()}</span>
235+
</div>
236+
<div
237+
className="flex items-center gap-1"
238+
title="Total pull request reviews in TanStack repositories"
239+
>
240+
<FaEye className="w-3 h-3" />
241+
<span>{stats.totalReviews.toLocaleString()}</span>
242+
</div>
243+
<div
244+
className="text-xs text-gray-500 dark:text-gray-500"
245+
title="Total contributions to TanStack repositories"
246+
>
247+
{totalContributions.toLocaleString()} total
248+
</div>
249+
</div>
250+
)
251+
}
252+
*/
253+
190254
interface MaintainerCardProps {
191255
maintainer: Maintainer
192256
libraryId?: Library['id']
@@ -196,6 +260,17 @@ interface CompactMaintainerCardProps {
196260
maintainer: Maintainer
197261
}
198262

263+
interface MaintainerRowCardProps {
264+
maintainer: Maintainer
265+
libraryId?: Library['id']
266+
stats?: {
267+
totalCommits: number
268+
totalPullRequests: number
269+
totalIssues: number
270+
totalReviews: number
271+
}
272+
}
273+
199274
export function CompactMaintainerCard({
200275
maintainer,
201276
}: CompactMaintainerCardProps) {
@@ -226,6 +301,119 @@ export function CompactMaintainerCard({
226301
)
227302
}
228303

304+
export function MaintainerRowCard({
305+
maintainer,
306+
libraryId,
307+
stats,
308+
}: MaintainerRowCardProps) {
309+
const libraries = getPersonsMaintainerOf(maintainer)
310+
const [showAllLibraries, setShowAllLibraries] = useState(false)
311+
312+
return (
313+
<div
314+
className="group bg-white dark:bg-gray-800 rounded-lg overflow-hidden shadow-lg w-full"
315+
aria-label={`Maintainer row card for ${maintainer.name}`}
316+
>
317+
<div className="flex items-center gap-4 p-4">
318+
{/* Avatar Section */}
319+
<a
320+
href={`https://github.com/${maintainer.github}`}
321+
target="_blank"
322+
rel="noopener noreferrer"
323+
aria-label={`View ${maintainer.name}'s GitHub profile`}
324+
className="relative flex-shrink-0"
325+
tabIndex={0}
326+
>
327+
<div className="relative w-16 h-16 rounded-lg overflow-hidden">
328+
<img
329+
alt={`Avatar of ${maintainer.name}`}
330+
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-500"
331+
src={maintainer.avatar}
332+
loading="lazy"
333+
decoding="async"
334+
/>
335+
<div className="absolute inset-0 bg-gradient-to-t from-black/40 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
336+
</div>
337+
</a>
338+
339+
{/* Main Content */}
340+
<div className="flex-1 min-w-0 overflow-hidden">
341+
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
342+
<div className="flex items-center gap-3">
343+
<span
344+
className="text-lg font-bold truncate"
345+
id={`maintainer-name-${maintainer.github}`}
346+
>
347+
{maintainer.name}
348+
</span>
349+
{libraryId && (
350+
<RoleBadge maintainer={maintainer} libraryId={libraryId} />
351+
)}
352+
</div>
353+
354+
<div className="flex items-center gap-2">
355+
<MaintainerSocialLinks maintainer={maintainer} />
356+
</div>
357+
</div>
358+
359+
{/* All Pills Inline */}
360+
{((maintainer.frameworkExpertise &&
361+
maintainer.frameworkExpertise.length > 0) ||
362+
(maintainer.specialties && maintainer.specialties.length > 0) ||
363+
(!libraryId && libraries.length > 0)) && (
364+
<div className="flex flex-wrap gap-2 mt-2 max-w-full">
365+
{/* Framework chips */}
366+
{maintainer.frameworkExpertise &&
367+
maintainer.frameworkExpertise.length > 0 &&
368+
maintainer.frameworkExpertise.map((framework) => (
369+
<FrameworkChip key={framework} framework={framework} />
370+
))}
371+
372+
{/* Specialty chips */}
373+
{maintainer.specialties &&
374+
maintainer.specialties.length > 0 &&
375+
maintainer.specialties.map((specialty) => (
376+
<SpecialtyChip key={specialty} specialty={specialty} />
377+
))}
378+
379+
{/* Library badges */}
380+
{!libraryId &&
381+
libraries.length > 0 &&
382+
libraries
383+
.slice(0, showAllLibraries ? undefined : 2)
384+
.map((library) => (
385+
<LibraryBadge key={library.id} library={library} />
386+
))}
387+
388+
{/* Show more button */}
389+
{!libraryId && !showAllLibraries && libraries.length > 2 && (
390+
<button
391+
onClick={(e) => {
392+
e.preventDefault()
393+
e.stopPropagation()
394+
setShowAllLibraries(true)
395+
}}
396+
className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-colors focus:outline-none focus:ring-2 focus:ring-blue-400"
397+
aria-label={`Show ${libraries.length - 2} more libraries`}
398+
tabIndex={0}
399+
type="button"
400+
>
401+
+{libraries.length - 2} more
402+
</button>
403+
)}
404+
</div>
405+
)}
406+
407+
{/* GitHub Stats - commented out due to performance/accuracy concerns */}
408+
{/* <div className="mt-4">
409+
<GitHubStats username={maintainer.github} stats={stats} />
410+
</div> */}
411+
</div>
412+
</div>
413+
</div>
414+
)
415+
}
416+
229417
export function MaintainerCard({ maintainer, libraryId }: MaintainerCardProps) {
230418
const libraries = getPersonsMaintainerOf(maintainer)
231419
const [showAllLibraries, setShowAllLibraries] = useState(false)
@@ -240,7 +428,7 @@ export function MaintainerCard({ maintainer, libraryId }: MaintainerCardProps) {
240428
target="_blank"
241429
rel="noopener noreferrer"
242430
aria-label={`View ${maintainer.name}'s GitHub profile`}
243-
className="relative h-64 overflow block"
431+
className="relative h-64 overflow-hidden block"
244432
tabIndex={0}
245433
>
246434
<img

src/libraries/maintainers.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,15 @@ export const allMaintainers: Maintainer[] = [
164164
avatar: 'https://github.com/lachlancollins.png',
165165
github: 'lachlancollins',
166166
maintainerOf: ['config', 'query'],
167+
contributorOf: [
168+
'start',
169+
'router',
170+
'virtual',
171+
'table',
172+
'form',
173+
'db',
174+
'pacer',
175+
],
167176
frameworkExpertise: ['react', 'svelte'],
168177
specialties: ['Architecture'],
169178
},
@@ -484,3 +493,69 @@ export function getRoleInLibrary(person: Maintainer, libraryId: string) {
484493
if (getIsConsultantOfLibrary(person, libraryId)) return 'Consultant'
485494
return 'Contributor'
486495
}
496+
497+
export function getRoleForFilteredLibraries(
498+
person: Maintainer,
499+
libraryIds: Library['id'][] | undefined
500+
): 'creator' | 'maintainer' | 'contributor' | 'other' {
501+
// If no libraries are filtered, use global roles
502+
if (!libraryIds || libraryIds.length === 0) {
503+
if (person.creatorOf && person.creatorOf.length > 0) return 'creator'
504+
if (person.maintainerOf && person.maintainerOf.length > 0)
505+
return 'maintainer'
506+
if (person.contributorOf && person.contributorOf.length > 0)
507+
return 'contributor'
508+
return 'other'
509+
}
510+
511+
// Check roles only for the filtered libraries
512+
const isCreatorOfFiltered = libraryIds.some((lib) =>
513+
person.creatorOf?.includes(lib)
514+
)
515+
const isMaintainerOfFiltered = libraryIds.some((lib) =>
516+
person.maintainerOf?.includes(lib)
517+
)
518+
const isContributorOfFiltered = libraryIds.some((lib) =>
519+
person.contributorOf?.includes(lib)
520+
)
521+
522+
if (isCreatorOfFiltered) return 'creator'
523+
if (isMaintainerOfFiltered) return 'maintainer'
524+
if (isContributorOfFiltered) return 'contributor'
525+
return 'other'
526+
}
527+
528+
export function getRolePriorityForFilteredLibraries(
529+
person: Maintainer,
530+
libraryIds: Library['id'][] | undefined
531+
): number {
532+
const role = getRoleForFilteredLibraries(person, libraryIds)
533+
534+
// Higher numbers = higher priority (sorted first)
535+
switch (role) {
536+
case 'creator':
537+
return 4
538+
case 'maintainer':
539+
return 3
540+
case 'contributor':
541+
return 2
542+
case 'other':
543+
return 1
544+
default:
545+
return 0
546+
}
547+
}
548+
549+
export function getIsCoreMaintainerForFilteredLibraries(
550+
person: Maintainer,
551+
libraryIds: Library['id'][] | undefined
552+
): boolean {
553+
// If no libraries are filtered, use global core maintainer status
554+
if (!libraryIds || libraryIds.length === 0) {
555+
return person.isCoreMaintainer || false
556+
}
557+
558+
// When filtering, core maintainer status is only relevant if they have a role in filtered libraries
559+
const role = getRoleForFilteredLibraries(person, libraryIds)
560+
return role !== 'other' && (person.isCoreMaintainer || false)
561+
}

0 commit comments

Comments
 (0)