diff --git a/src/components/ContributorsWall.tsx b/src/components/ContributorsWall.tsx
new file mode 100644
index 000000000..920c9bec4
--- /dev/null
+++ b/src/components/ContributorsWall.tsx
@@ -0,0 +1,40 @@
+import { type Library } from '~/libraries'
+
+export function ContributorsWall({ library }: { library: Library }) {
+ return (
+
diff --git a/src/components/MaintainerCard.tsx b/src/components/MaintainerCard.tsx
new file mode 100644
index 000000000..f727f2869
--- /dev/null
+++ b/src/components/MaintainerCard.tsx
@@ -0,0 +1,282 @@
+import { Library, Framework, frameworkOptions } from '~/libraries'
+import {
+ getRoleInLibrary,
+ Maintainer,
+ getPersonsMaintainerOf,
+} from '~/libraries/maintainers'
+import { useState } from 'react'
+
+function RoleBadge({
+ maintainer,
+ libraryId,
+}: {
+ maintainer: Maintainer
+ libraryId?: Library['id']
+}) {
+ const role = libraryId ? getRoleInLibrary(maintainer, libraryId) : ''
+ const isCreator = role.toLowerCase().includes('creator')
+ const isMaintainer = role.toLowerCase().includes('maintainer')
+ const isCoreMaintainer = isMaintainer && maintainer.isCoreMaintainer
+
+ if (isCreator) {
+ return (
+
+ {role}
+
+ )
+ }
+
+ if (isMaintainer) {
+ return (
+
+ {role}
+
+ )
+ }
+
+ return
{role}
+}
+
+function FrameworkChip({ framework }: { framework: Framework }) {
+ const frameworkOption = frameworkOptions.find((f) => f.value === framework)
+ const bgColor = frameworkOption?.color || 'bg-gray-500'
+ return (
+
+
+ {frameworkOption?.label || framework}
+
+ )
+}
+
+function SpecialtyChip({ specialty }: { specialty: string }) {
+ return (
+
+
+ {specialty}
+
+ )
+}
+
+function LibraryBadge({ library }: { library: Library }) {
+ if (library.to) {
+ return (
+
e.stopPropagation()}
+ title={`View all contributors for ${library.name}`}
+ >
+ {library.name.replace('TanStack', '🌴')}
+
+ )
+ }
+ return (
+
+ {library.name.replace('TanStack', '🌴')}
+
+ )
+}
+
+interface MaintainerCardProps {
+ maintainer: Maintainer
+ libraryId?: Library['id']
+}
+
+export function MaintainerCard({ maintainer, libraryId }: MaintainerCardProps) {
+ const libraries = getPersonsMaintainerOf(maintainer)
+ const [showAllLibraries, setShowAllLibraries] = useState(false)
+
+ return (
+
+ )
+}
diff --git a/src/libraries/index.tsx b/src/libraries/index.tsx
index 0c146a92b..c9e49ad90 100644
--- a/src/libraries/index.tsx
+++ b/src/libraries/index.tsx
@@ -57,9 +57,10 @@ export type Library = {
| 'db'
| 'config'
| 'react-charts'
+ | 'create-tsrouter-app'
name: string
cardStyles: string
- to: string
+ to?: string
tagline: string
description: string
ogImage?: string
@@ -89,6 +90,7 @@ export type Library = {
}[]
docsRoot?: string
embedEditor?: 'codesandbox' | 'stackblitz'
+ visible?: boolean
}
export type LibraryMenuItem = {
@@ -109,6 +111,16 @@ export const libraries = [
rangerProject,
dbProject,
configProject,
+ {
+ id: 'react-charts',
+ name: 'React Charts',
+ repo: 'tanstack/react-charts',
+ } as Library,
+ {
+ id: 'create-tsrouter-app',
+ name: 'Create TS Router App',
+ repo: 'tanstack/create-tsrouter-app',
+ } as Library,
] satisfies Library[]
export const librariesByGroup = {
@@ -125,7 +137,6 @@ export const librariesByGroup = {
}
export const librariesGroupNamesMap = {
- app: 'Application Building',
state: 'Data and State Management',
headlessUI: 'Headless UI',
other: 'Other',
diff --git a/src/libraries/maintainers.ts b/src/libraries/maintainers.ts
new file mode 100644
index 000000000..d7564bf8f
--- /dev/null
+++ b/src/libraries/maintainers.ts
@@ -0,0 +1,453 @@
+import { Framework, getLibrary, Library } from '.'
+
+export interface Maintainer {
+ name: string
+ avatar: string
+ github: string
+ isCoreMaintainer?: boolean
+ creatorOf?: Library['id'][]
+ maintainerOf?: Library['id'][] // inherits from creatorOf
+ contributorOf?: Library['id'][] // inherits from maintainerOf
+ consultantOf?: Library['id'][] // inherits from maintainerOf
+ frameworkExpertise?: Framework[]
+ specialties?: string[]
+ social?: {
+ twitter?: string
+ bluesky?: string
+ website?: string
+ }
+}
+
+// order matters
+export const allMaintainers: Maintainer[] = [
+ {
+ name: 'Tanner Linsley',
+ isCoreMaintainer: true,
+ avatar: 'https://github.com/tannerlinsley.png',
+ github: 'tannerlinsley',
+ creatorOf: [
+ 'start',
+ 'router',
+ 'query',
+ 'table',
+ 'form',
+ 'virtual',
+ 'ranger',
+ 'store',
+ 'pacer',
+ 'react-charts',
+ ],
+ frameworkExpertise: ['react', 'solid'],
+ specialties: ['Architecture', 'Core API', 'Documentation'],
+ social: {
+ twitter: 'https://x.com/tannerlinsley',
+ bluesky: 'https://bsky.app/profile/tannerlinsley.com',
+ website: 'https://tannerlinsley.com',
+ },
+ },
+ {
+ name: 'Dominik Dorfmeister',
+ isCoreMaintainer: true,
+ avatar: 'https://github.com/tkdodo.png',
+ github: 'tkdodo',
+ maintainerOf: ['query'],
+ contributorOf: ['router'],
+ frameworkExpertise: ['react'],
+ specialties: ['Core API', 'TypeScript', 'Documentation'],
+ social: {
+ bluesky: 'https://bsky.app/profile/tkdodo.eu',
+ website: 'https://tkdodo.eu',
+ },
+ },
+ {
+ name: 'Corbin Crutchley',
+ isCoreMaintainer: true,
+ avatar: 'https://github.com/crutchcorn.png',
+ github: 'crutchcorn',
+ creatorOf: ['form'],
+ maintainerOf: ['store', 'config'],
+ frameworkExpertise: ['react', 'solid', 'vue', 'angular'],
+ specialties: ['Forms', 'Validation', 'State Management'],
+ social: {
+ twitter: 'https://x.com/crutchcorn',
+ bluesky: 'https://bsky.app/profile/crutchcorn.dev',
+ website: 'https://playfulprogramming.com/people/crutchcorn',
+ },
+ },
+ {
+ name: 'Manuel Schiller',
+ isCoreMaintainer: true,
+ avatar: 'https://github.com/schiller-manuel.png',
+ github: 'schiller-manuel',
+ maintainerOf: ['start', 'router'],
+ frameworkExpertise: ['react'],
+ specialties: ['Architecture', 'Core API', 'Documentation'],
+ social: {
+ twitter: 'https://x.com/schanuelmiller',
+ bluesky: 'https://bsky.app/profile/manuelschiller.bsky.social',
+ },
+ },
+ {
+ name: 'Kevin Van Cott',
+ isCoreMaintainer: true,
+ avatar: 'https://github.com/kevinvandy.png',
+ github: 'kevinvandy',
+ creatorOf: ['pacer'],
+ maintainerOf: ['table'],
+ contributorOf: ['virtual'],
+ consultantOf: ['query'],
+ frameworkExpertise: ['react', 'solid', 'svelte'],
+ specialties: ['Tables', 'Data Grids', 'Dashboards'],
+ social: {
+ twitter: 'https://x.com/kevinvancott',
+ bluesky: 'https://bsky.app/profile/kevinvancott.dev',
+ website: 'https://kevinvancott.dev',
+ },
+ },
+ {
+ name: 'Sean Cassiere',
+ isCoreMaintainer: true,
+ avatar: 'https://github.com/seancassiere.png',
+ github: 'seancassiere',
+ maintainerOf: ['start', 'router'],
+ frameworkExpertise: ['react'],
+ specialties: ['Architecture', 'Core API', 'Documentation'],
+ social: {
+ twitter: 'https://x.com/seancassiere',
+ bluesky: 'https://bsky.app/profile/seancassiere.com',
+ website: 'https://seancassiere.com',
+ },
+ },
+ {
+ name: 'Chris Horobin',
+ isCoreMaintainer: true,
+ avatar: 'https://github.com/chorobin.png',
+ github: 'chorobin',
+ maintainerOf: ['start', 'router'],
+ frameworkExpertise: ['react'],
+ specialties: ['TypeScript'],
+ social: {
+ twitter: 'https://x.com/c_horobin',
+ bluesky: 'https://bsky.app/profile/chorobin.bsky.social',
+ },
+ },
+ {
+ name: 'Damian Pieczynski',
+ isCoreMaintainer: true,
+ avatar: 'https://github.com/piecyk.png',
+ github: 'piecyk',
+ maintainerOf: ['virtual'],
+ frameworkExpertise: ['react'],
+ specialties: ['Virtualization', 'Performance'],
+ },
+ {
+ name: 'Jack Herrington',
+ isCoreMaintainer: true,
+ avatar: 'https://github.com/jherr.png',
+ github: 'jherr',
+ creatorOf: ['create-tsrouter-app'],
+ frameworkExpertise: ['react'],
+ specialties: ['Templates'],
+ },
+ {
+ name: 'Kyle Mathews',
+ isCoreMaintainer: true,
+ avatar: 'https://github.com/KyleAMathews.png',
+ github: 'KyleAMathews',
+ creatorOf: ['db'],
+ frameworkExpertise: ['react'],
+ specialties: ['Sync Engines'],
+ },
+ {
+ name: 'Lachlan Collins',
+ isCoreMaintainer: true,
+ avatar: 'https://github.com/lachlancollins.png',
+ github: 'lachlancollins',
+ maintainerOf: ['config', 'query'],
+ frameworkExpertise: ['react', 'svelte'],
+ specialties: ['Architecture'],
+ },
+ {
+ name: 'Leonardo Montini',
+ avatar: 'https://github.com/Balastrong.png',
+ github: 'Balastrong',
+ maintainerOf: ['form'],
+ frameworkExpertise: ['react'],
+ social: {
+ website: 'https://leonardomontini.dev/',
+ twitter: 'https://x.com/Balastrong',
+ bluesky: 'https://bsky.app/profile/leonardomontini.dev',
+ },
+ },
+ {
+ name: 'Fredrik Höglund',
+ avatar: 'https://github.com/ephem.png',
+ github: 'ephem',
+ maintainerOf: ['query'],
+ frameworkExpertise: ['react'],
+ specialties: ['Data Management', 'SSR', 'Hydration'],
+ social: {
+ bluesky: 'https://bsky.app/profile/ephem.dev',
+ twitter: 'https://x.com/ephemjs',
+ website: 'https://www.ephem.dev',
+ },
+ },
+ {
+ name: 'Aadit Olkar',
+ avatar: 'https://github.com/aadito123.png',
+ github: 'aadito123',
+ maintainerOf: ['form'],
+ frameworkExpertise: ['solid'],
+ social: {
+ twitter: 'https://x.com/swagdoctor19',
+ },
+ },
+ {
+ name: 'Luca Jakob',
+ avatar: 'https://github.com/LeCarbonator.png',
+ github: 'LeCarbonator',
+ maintainerOf: ['form'],
+ frameworkExpertise: ['react'],
+ },
+ {
+ name: 'Jonghyeon Ko',
+ avatar: 'https://github.com/manudeli.png',
+ github: 'manudeli',
+ maintainerOf: ['query'],
+ frameworkExpertise: ['react'],
+ specialties: ['TypeScript', 'Backport', 'Test'],
+ social: {
+ twitter: 'https://x.com/manudeli_',
+ bluesky: 'https://bsky.app/profile/manudeli.bsky.social',
+ website: 'https://www.linkedin.com/in/jonghyeonko',
+ },
+ },
+ {
+ name: 'Riccardo Perra',
+ avatar:
+ 'https://cdn.bsky.app/img/avatar/plain/did:plc:gtnigsmgu7jyrc4tnkvn62qw/bafkreiceysbj4o6jrbbniudtwj3tcsns6rvwcxyjsqiaumeojurwbkki5a@jpeg',
+ github: 'riccardoperra',
+ maintainerOf: ['table'],
+ frameworkExpertise: ['angular', 'solid'],
+ specialties: [],
+ social: {
+ twitter: 'https://x.com/riccardoperra0',
+ bluesky: 'https://bsky.app/profile/riccardoperra.bsky.social',
+ website: 'https://riccardoperra.com',
+ },
+ },
+ {
+ name: 'Birk Skyum',
+ avatar: 'https://github.com/birkskyum.png',
+ github: 'birkskyum',
+ maintainerOf: ['start'],
+ contributorOf: ['pacer'],
+ frameworkExpertise: ['solid'],
+ specialties: [],
+ social: {
+ twitter: 'https://x.com/birkskyum',
+ bluesky: 'https://bsky.app/profile/bskyum.bsky.social',
+ },
+ },
+ {
+ name: 'Arnoud de Vries',
+ avatar: 'https://github.com/arnoud-dv.png',
+ github: 'arnoud-dv',
+ maintainerOf: ['query'],
+ frameworkExpertise: ['angular', 'react'],
+ specialties: [
+ 'Architecture',
+ 'Developer Experience',
+ 'TypeScript',
+ 'Reactivity',
+ ],
+ social: {
+ twitter: 'https://x.com/Arnoud_dv',
+ bluesky: 'https://bsky.app/profile/arnoud.dev',
+ website: 'https://www.linkedin.com/in/arnouddv/',
+ },
+ },
+ {
+ name: 'Fülöp Kovács',
+ avatar: 'https://github.com/fulopkovacs.png',
+ github: 'fulopkovacs',
+ maintainerOf: ['form'],
+ frameworkExpertise: ['react'],
+ social: {
+ website: 'https://fulop.dev/',
+ twitter: 'https://x.com/notacheetah',
+ bluesky: 'https://bsky.app/profile/notacheetah.bsky.social',
+ },
+ },
+ {
+ name: 'Aryan Deora',
+ avatar: 'https://github.com/ardeora.png',
+ github: 'ardeora',
+ maintainerOf: ['query'],
+ frameworkExpertise: ['solid'],
+ specialties: ['Dev Tools'],
+ social: {
+ twitter: 'https://x.com/aryan__deora',
+ website: 'https://www.aryandeora.com/',
+ },
+ },
+ {
+ name: 'Mokshit Jain',
+ avatar: 'https://github.com/Mokshit06.png',
+ contributorOf: ['table'],
+ frameworkExpertise: ['svelte', 'solid', 'vue'],
+ github: 'Mokshit06',
+ social: {
+ twitter: 'https://x.com/mokshit06',
+ website: 'https://mokshitjain.co',
+ },
+ },
+ {
+ name: 'Walker Lockard',
+ github: 'walker-tx',
+ avatar: 'https://github.com/walker-tx.png',
+ contributorOf: ['table'],
+ frameworkExpertise: ['svelte', 'react'],
+ social: {
+ twitter: 'https://x.com/walker_lockard',
+ website: 'https://walker.dev',
+ },
+ },
+ {
+ name: 'Tom',
+ github: 'tombuntus',
+ avatar: 'https://github.com/tombuntus.png',
+ contributorOf: ['table'],
+ frameworkExpertise: ['react'],
+ social: {},
+ },
+]
+
+export const coreMaintainers = allMaintainers.filter(
+ (maintainer) => maintainer.isCoreMaintainer
+)
+
+export function getLibraryCreators(libraryId: string): Maintainer[] {
+ return allMaintainers.filter((maintainer) =>
+ maintainer.creatorOf?.includes(libraryId as Library['id'])
+ )
+}
+
+export function getLibraryMaintainers(
+ libraryId: string,
+ includeCreators = true
+): Maintainer[] {
+ const creators = getLibraryCreators(libraryId)
+ const maintainers = allMaintainers.filter((maintainer) =>
+ maintainer.maintainerOf?.includes(libraryId as Library['id'])
+ )
+
+ // Use Set to dedupe while preserving order
+ return includeCreators
+ ? [...new Set([...creators, ...maintainers])]
+ : maintainers
+}
+
+export function getLibraryContributors(
+ libraryId: string,
+ includeMaintainers = true
+): Maintainer[] {
+ const maintainers = getLibraryMaintainers(libraryId)
+ const contributors = allMaintainers.filter((maintainer) =>
+ maintainer.contributorOf?.includes(libraryId as Library['id'])
+ )
+
+ return includeMaintainers
+ ? [...new Set([...maintainers, ...contributors])]
+ : contributors
+}
+
+export function getLibraryConsultants(
+ libraryId: string,
+ includeMaintainers = true
+): Maintainer[] {
+ const maintainers = getLibraryMaintainers(libraryId)
+ const consultants = allMaintainers.filter((maintainer) =>
+ maintainer.consultantOf?.includes(libraryId as Library['id'])
+ )
+
+ return includeMaintainers
+ ? [...new Set([...maintainers, ...consultants])]
+ : consultants
+}
+
+export function getPersonsCreatorOf(person: Maintainer): Library[] {
+ return person.creatorOf?.map((libraryId) => getLibrary(libraryId)) || []
+}
+
+export function getPersonsMaintainerOf(
+ person: Maintainer,
+ includeCreatorOf = true
+): Library[] {
+ const creatorOf = getPersonsCreatorOf(person)
+ const maintainerOf =
+ person.maintainerOf?.map((libraryId) => getLibrary(libraryId)) || []
+
+ return includeCreatorOf
+ ? [...new Set([...creatorOf, ...maintainerOf])]
+ : maintainerOf
+}
+
+export function getPersonsContributorOf(
+ person: Maintainer,
+ includeMaintainers = true
+): Library[] {
+ const maintainers = getPersonsMaintainerOf(person)
+ const contributors =
+ person.contributorOf?.map((libraryId) => getLibrary(libraryId)) || []
+
+ return includeMaintainers
+ ? [...new Set([...maintainers, ...contributors])]
+ : contributors
+}
+
+export function getPersonsConsultantOf(
+ person: Maintainer,
+ includeMaintainers = true
+): Library[] {
+ const maintainers = getPersonsMaintainerOf(person)
+ const consultants =
+ person.consultantOf?.map((libraryId) => getLibrary(libraryId)) || []
+
+ return includeMaintainers
+ ? [...new Set([...maintainers, ...consultants])]
+ : consultants
+}
+
+export function getIsCreatorOfLibrary(person: Maintainer, libraryId: string) {
+ return person.creatorOf?.includes(libraryId as Library['id'])
+}
+
+export function getIsMaintainerOfLibrary(
+ person: Maintainer,
+ libraryId: string
+) {
+ return person.maintainerOf?.includes(libraryId as Library['id'])
+}
+
+export function getIsContributorOfLibrary(
+ person: Maintainer,
+ libraryId: string
+) {
+ return person.contributorOf?.includes(libraryId as Library['id'])
+}
+
+export function getIsConsultantOfLibrary(
+ person: Maintainer,
+ libraryId: string
+) {
+ return person.consultantOf?.includes(libraryId as Library['id'])
+}
+
+export function getRoleInLibrary(person: Maintainer, libraryId: string) {
+ if (getIsCreatorOfLibrary(person, libraryId)) return 'Creator'
+ if (getIsMaintainerOfLibrary(person, libraryId)) return 'Maintainer'
+ if (getIsContributorOfLibrary(person, libraryId)) return 'Contributor'
+ if (getIsConsultantOfLibrary(person, libraryId)) return 'Consultant'
+ return 'Contributor'
+}
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index 15f7e0cc8..5603f1dd3 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -46,6 +46,7 @@ import { Route as LibrariesFormVersionIndexRouteImport } from './routes/_librari
import { Route as LibrariesDbVersionIndexRouteImport } from './routes/_libraries/db.$version.index'
import { Route as LibrariesConfigVersionIndexRouteImport } from './routes/_libraries/config.$version.index'
import { Route as LibraryIdVersionDocsIndexRouteImport } from './routes/$libraryId/$version.docs.index'
+import { Route as LibraryIdVersionDocsContributorsRouteImport } from './routes/$libraryId/$version.docs.contributors'
import { Route as LibraryIdVersionDocsSplatRouteImport } from './routes/$libraryId/$version.docs.$'
import { Route as LibraryIdVersionDocsFrameworkIndexRouteImport } from './routes/$libraryId/$version.docs.framework.index'
import { Route as LibraryIdVersionDocsFrameworkFrameworkIndexRouteImport } from './routes/$libraryId/$version.docs.framework.$framework.index'
@@ -263,6 +264,13 @@ const LibraryIdVersionDocsIndexRoute =
getParentRoute: () => LibraryIdVersionDocsRoute,
} as any)
+const LibraryIdVersionDocsContributorsRoute =
+ LibraryIdVersionDocsContributorsRouteImport.update({
+ id: '/contributors',
+ path: '/contributors',
+ getParentRoute: () => LibraryIdVersionDocsRoute,
+ } as any)
+
const LibraryIdVersionDocsSplatRoute =
LibraryIdVersionDocsSplatRouteImport.update({
id: '/$',
@@ -456,6 +464,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof LibraryIdVersionDocsSplatRouteImport
parentRoute: typeof LibraryIdVersionDocsRouteImport
}
+ '/$libraryId/$version/docs/contributors': {
+ id: '/$libraryId/$version/docs/contributors'
+ path: '/contributors'
+ fullPath: '/$libraryId/$version/docs/contributors'
+ preLoaderRoute: typeof LibraryIdVersionDocsContributorsRouteImport
+ parentRoute: typeof LibraryIdVersionDocsRouteImport
+ }
'/$libraryId/$version/docs/': {
id: '/$libraryId/$version/docs/'
path: '/'
@@ -771,6 +786,15 @@ declare module './routes/$libraryId/$version.docs.$' {
FileRoutesByPath['/$libraryId/$version/docs/$']['fullPath']
>
}
+declare module './routes/$libraryId/$version.docs.contributors' {
+ const createFileRoute: CreateFileRoute<
+ '/$libraryId/$version/docs/contributors',
+ FileRoutesByPath['/$libraryId/$version/docs/contributors']['parentRoute'],
+ FileRoutesByPath['/$libraryId/$version/docs/contributors']['id'],
+ FileRoutesByPath['/$libraryId/$version/docs/contributors']['path'],
+ FileRoutesByPath['/$libraryId/$version/docs/contributors']['fullPath']
+ >
+}
declare module './routes/$libraryId/$version.docs.index' {
const createFileRoute: CreateFileRoute<
'/$libraryId/$version/docs/',
@@ -920,6 +944,7 @@ declare module './routes/$libraryId/$version.docs.framework.$framework.examples.
interface LibraryIdVersionDocsRouteChildren {
LibraryIdVersionDocsSplatRoute: typeof LibraryIdVersionDocsSplatRoute
+ LibraryIdVersionDocsContributorsRoute: typeof LibraryIdVersionDocsContributorsRoute
LibraryIdVersionDocsIndexRoute: typeof LibraryIdVersionDocsIndexRoute
LibraryIdVersionDocsFrameworkIndexRoute: typeof LibraryIdVersionDocsFrameworkIndexRoute
LibraryIdVersionDocsFrameworkFrameworkSplatRoute: typeof LibraryIdVersionDocsFrameworkFrameworkSplatRoute
@@ -929,6 +954,7 @@ interface LibraryIdVersionDocsRouteChildren {
const LibraryIdVersionDocsRouteChildren: LibraryIdVersionDocsRouteChildren = {
LibraryIdVersionDocsSplatRoute: LibraryIdVersionDocsSplatRoute,
+ LibraryIdVersionDocsContributorsRoute: LibraryIdVersionDocsContributorsRoute,
LibraryIdVersionDocsIndexRoute: LibraryIdVersionDocsIndexRoute,
LibraryIdVersionDocsFrameworkIndexRoute:
LibraryIdVersionDocsFrameworkIndexRoute,
@@ -1053,6 +1079,7 @@ export interface FileRoutesByFullPath {
'/blog/': typeof LibrariesBlogIndexRoute
'/stats/npm': typeof StatsNpmIndexRoute
'/$libraryId/$version/docs/$': typeof LibraryIdVersionDocsSplatRoute
+ '/$libraryId/$version/docs/contributors': typeof LibraryIdVersionDocsContributorsRoute
'/$libraryId/$version/docs/': typeof LibraryIdVersionDocsIndexRoute
'/config/$version': typeof LibrariesConfigVersionIndexRoute
'/db/$version': typeof LibrariesDbVersionIndexRoute
@@ -1090,6 +1117,7 @@ export interface FileRoutesByTo {
'/blog': typeof LibrariesBlogIndexRoute
'/stats/npm': typeof StatsNpmIndexRoute
'/$libraryId/$version/docs/$': typeof LibraryIdVersionDocsSplatRoute
+ '/$libraryId/$version/docs/contributors': typeof LibraryIdVersionDocsContributorsRoute
'/$libraryId/$version/docs': typeof LibraryIdVersionDocsIndexRoute
'/config/$version': typeof LibrariesConfigVersionIndexRoute
'/db/$version': typeof LibrariesDbVersionIndexRoute
@@ -1132,6 +1160,7 @@ export interface FileRoutesById {
'/_libraries/blog/': typeof LibrariesBlogIndexRoute
'/stats/npm/': typeof StatsNpmIndexRoute
'/$libraryId/$version/docs/$': typeof LibraryIdVersionDocsSplatRoute
+ '/$libraryId/$version/docs/contributors': typeof LibraryIdVersionDocsContributorsRoute
'/$libraryId/$version/docs/': typeof LibraryIdVersionDocsIndexRoute
'/_libraries/config/$version/': typeof LibrariesConfigVersionIndexRoute
'/_libraries/db/$version/': typeof LibrariesDbVersionIndexRoute
@@ -1175,6 +1204,7 @@ export interface FileRouteTypes {
| '/blog/'
| '/stats/npm'
| '/$libraryId/$version/docs/$'
+ | '/$libraryId/$version/docs/contributors'
| '/$libraryId/$version/docs/'
| '/config/$version'
| '/db/$version'
@@ -1211,6 +1241,7 @@ export interface FileRouteTypes {
| '/blog'
| '/stats/npm'
| '/$libraryId/$version/docs/$'
+ | '/$libraryId/$version/docs/contributors'
| '/$libraryId/$version/docs'
| '/config/$version'
| '/db/$version'
@@ -1251,6 +1282,7 @@ export interface FileRouteTypes {
| '/_libraries/blog/'
| '/stats/npm/'
| '/$libraryId/$version/docs/$'
+ | '/$libraryId/$version/docs/contributors'
| '/$libraryId/$version/docs/'
| '/_libraries/config/$version/'
| '/_libraries/db/$version/'
@@ -1410,6 +1442,7 @@ export const routeTree = rootRoute
"parent": "/$libraryId/$version",
"children": [
"/$libraryId/$version/docs/$",
+ "/$libraryId/$version/docs/contributors",
"/$libraryId/$version/docs/",
"/$libraryId/$version/docs/framework/",
"/$libraryId/$version/docs/framework/$framework/$",
@@ -1432,6 +1465,10 @@ export const routeTree = rootRoute
"filePath": "$libraryId/$version.docs.$.tsx",
"parent": "/$libraryId/$version/docs"
},
+ "/$libraryId/$version/docs/contributors": {
+ "filePath": "$libraryId/$version.docs.contributors.tsx",
+ "parent": "/$libraryId/$version/docs"
+ },
"/$libraryId/$version/docs/": {
"filePath": "$libraryId/$version.docs.index.tsx",
"parent": "/$libraryId/$version/docs"
diff --git a/src/routes/$libraryId/$version.docs.contributors.tsx b/src/routes/$libraryId/$version.docs.contributors.tsx
new file mode 100644
index 000000000..40c2d1f56
--- /dev/null
+++ b/src/routes/$libraryId/$version.docs.contributors.tsx
@@ -0,0 +1,55 @@
+import { twMerge } from 'tailwind-merge'
+import { DocContainer } from '~/components/DocContainer'
+import { DocTitle } from '~/components/DocTitle'
+import { getLibrary } from '~/libraries'
+import { ContributorsWall } from '~/components/ContributorsWall'
+import {} from '@tanstack/react-router'
+import { getLibraryContributors } from '~/libraries/maintainers'
+import { MaintainerCard } from '~/components/MaintainerCard'
+
+export const Route = createFileRoute({
+ component: RouteComponent,
+})
+
+function RouteComponent() {
+ const { libraryId } = Route.useParams()
+ const library = getLibrary(libraryId)
+
+ // Get the maintainers for this library
+ const libraryContributors = getLibraryContributors(libraryId)
+
+ return (
+
+
+
+
{library.name} Maintainers and Contributors
+
+
+
+ {libraryContributors.map((maintainer) => (
+
+ ))}
+
+
+
+
+
+
+
All-Time Contributors
+
+
+
+
+
+ )
+}
diff --git a/src/routes/_libraries/index.tsx b/src/routes/_libraries/index.tsx
index d613a6807..deba766b8 100644
--- a/src/routes/_libraries/index.tsx
+++ b/src/routes/_libraries/index.tsx
@@ -15,6 +15,8 @@ import splashLightImg from '~/images/splash-light.png'
import splashDarkImg from '~/images/splash-dark.png'
import { GadFooter } from '~/components/GoogleScripts'
import LandingPageGad from '~/components/LandingPageGad'
+import { MaintainerCard } from '~/components/MaintainerCard'
+import { coreMaintainers } from '~/libraries/maintainers'
export const textColors = [
`text-rose-500`,
@@ -382,6 +384,15 @@ function Index() {
+