@@ -8,6 +8,8 @@ import Image from "next/image"
88import Link from "next/link"
99import sponsorData from "./sponsors.json"
1010import { Check , CheckCheck , GithubIcon , Heart , Star } from "lucide-react"
11+ import { cn } from "@/lib/utils"
12+ import { TimeAgo } from "@/components/time-ago"
1113
1214export function Pricing ( ) {
1315 const current = 625
@@ -84,6 +86,65 @@ export function Pricing() {
8486 )
8587}
8688
89+ export async function LatestSponsor ( { className } : { className ?: string } ) {
90+ const GITHUB_TOKEN = process . env . GITHUB_TOKEN
91+ if ( ! GITHUB_TOKEN ) {
92+ throw new Error ( "Missing process.env.GITHUB_TOKEN" )
93+ }
94+
95+ const r = await fetch ( "https://api.github.com/graphql" , {
96+ method : "POST" ,
97+ body : JSON . stringify ( { query : latestSponsorsQuery } ) ,
98+ headers : { Authorization : "bearer " + GITHUB_TOKEN } ,
99+ } )
100+ if ( ! r . ok ) {
101+ throw new Error ( `Failed to fetch: ${ r . status } ${ r . statusText } ` )
102+ }
103+ const { data, errors } = await r . json ( )
104+ if ( errors ) {
105+ throw new Error ( JSON . stringify ( errors ) )
106+ }
107+
108+ const sponsors = data . organization . sponsorshipsAsMaintainer . edges
109+ if ( ! sponsors . length ) {
110+ throw new Error ( "No sponsors found" )
111+ }
112+
113+ const latest = sponsors [ 0 ] . node
114+
115+ return (
116+ < a
117+ href = { `https://github.com/${ latest . sponsorEntity . login } ` }
118+ className = { cn (
119+ className ,
120+ "rounded bg-zinc-50 dark:bg-zinc-900 p-3 flex gap-3 border border-zinc-200/50 dark:border-zinc-700/50 hover:border-zinc-200 dark:hover:border-zinc-700 transition-colors w-96 md:w-full mx-auto" ,
121+ ) }
122+ >
123+ < Image
124+ className = "rounded my-0 max-h-20"
125+ src = { `${ latest . sponsorEntity . avatarUrl } ` }
126+ alt = { latest . sponsorEntity . name }
127+ height = { 80 }
128+ width = { 80 }
129+ placeholder = "empty"
130+ />
131+ < div className = "flex-1 flex flex-col justify-between" >
132+ { /* <div>{new Date().toString()}</div> */ }
133+ < div className = "text-primary/70 text-sm" >
134+ Latest sponsor · < TimeAgo date = { latest . createdAt } />
135+ </ div >
136+ < div className = "text-2xl font-bold" >
137+ { latest . sponsorEntity . name || latest . sponsorEntity . login }
138+ </ div >
139+ < div className = "text-primary/90 text-sm" >
140+ Sponsoring < strong > { latest . tier . name } </ strong > { " " }
141+ </ div >
142+ </ div >
143+ { /* <pre>{JSON.stringify(latest, null, 2)}</pre> */ }
144+ </ a >
145+ )
146+ }
147+
87148export function TopSponsors ( {
88149 title = "Top Sponsors" ,
89150 scale = 1 ,
@@ -440,3 +501,37 @@ function BrowserStack() {
440501 </ svg >
441502 )
442503}
504+
505+ const latestSponsorsQuery = `query {
506+ organization(login: "code-hike") {
507+ sponsorshipsAsMaintainer(first: 50, orderBy: {field: CREATED_AT, direction: DESC}, activeOnly: false) {
508+ edges {
509+ node {
510+ createdAt
511+ privacyLevel
512+ tier {
513+ name
514+ monthlyPriceInDollars
515+ }
516+ sponsorEntity {
517+ ... on User {
518+ login
519+ name
520+ avatarUrl
521+ websiteUrl
522+ location
523+ }
524+ ... on Organization {
525+ login
526+ name
527+ avatarUrl
528+ websiteUrl
529+ location
530+ }
531+ }
532+ }
533+ }
534+ }
535+ }
536+ }
537+ `
0 commit comments