@@ -8,6 +8,8 @@ import Image from "next/image"
8
8
import Link from "next/link"
9
9
import sponsorData from "./sponsors.json"
10
10
import { Check , CheckCheck , GithubIcon , Heart , Star } from "lucide-react"
11
+ import { cn } from "@/lib/utils"
12
+ import { TimeAgo } from "@/components/time-ago"
11
13
12
14
export function Pricing ( ) {
13
15
const current = 625
@@ -84,6 +86,65 @@ export function Pricing() {
84
86
)
85
87
}
86
88
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
+
87
148
export function TopSponsors ( {
88
149
title = "Top Sponsors" ,
89
150
scale = 1 ,
@@ -440,3 +501,37 @@ function BrowserStack() {
440
501
</ svg >
441
502
)
442
503
}
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