11import type { Metadata } from "next" ;
22import Link from "next/link" ;
3+ import { LEADERBOARD_ENTRIES , type ResolvedLeaderboardEntry } from "./leaderboard-entries" ;
34
45const PERFECT_SCORE = 100 ;
56const SCORE_GOOD_THRESHOLD = 75 ;
67const SCORE_OK_THRESHOLD = 50 ;
78const SCORE_BAR_WIDTH = 20 ;
89const COMMAND = "npx -y react-doctor@latest ." ;
9-
10- interface LeaderboardEntry {
11- name : string ;
12- githubUrl : string ;
13- score : number ;
14- errorCount : number ;
15- warningCount : number ;
16- fileCount : number ;
17- shareUrl : string ;
18- }
19-
20- const LEADERBOARD_ENTRIES : LeaderboardEntry [ ] = [
21- {
22- name : "tldraw" ,
23- githubUrl : "https://github.com/tldraw/tldraw" ,
24- score : 84 ,
25- errorCount : 98 ,
26- warningCount : 139 ,
27- fileCount : 40 ,
28- shareUrl : "/share?p=tldraw&s=84&e=98&w=139&f=40" ,
29- } ,
30- {
31- name : "excalidraw" ,
32- githubUrl : "https://github.com/excalidraw/excalidraw" ,
33- score : 84 ,
34- errorCount : 2 ,
35- warningCount : 196 ,
36- fileCount : 80 ,
37- shareUrl : "/share?p=%40excalidraw%2Fexcalidraw&s=84&e=2&w=196&f=80" ,
38- } ,
39- {
40- name : "twenty" ,
41- githubUrl : "https://github.com/twentyhq/twenty" ,
42- score : 78 ,
43- errorCount : 99 ,
44- warningCount : 293 ,
45- fileCount : 268 ,
46- shareUrl : "/share?p=twenty-front&s=78&e=99&w=293&f=268" ,
47- } ,
48- {
49- name : "plane" ,
50- githubUrl : "https://github.com/makeplane/plane" ,
51- score : 78 ,
52- errorCount : 7 ,
53- warningCount : 525 ,
54- fileCount : 292 ,
55- shareUrl : "/share?p=web&s=78&e=7&w=525&f=292" ,
56- } ,
57- {
58- name : "formbricks" ,
59- githubUrl : "https://github.com/formbricks/formbricks" ,
60- score : 75 ,
61- errorCount : 15 ,
62- warningCount : 389 ,
63- fileCount : 242 ,
64- shareUrl : "/share?p=%40formbricks%2Fweb&s=75&e=15&w=389&f=242" ,
65- } ,
66- {
67- name : "posthog" ,
68- githubUrl : "https://github.com/PostHog/posthog" ,
69- score : 72 ,
70- errorCount : 82 ,
71- warningCount : 1177 ,
72- fileCount : 585 ,
73- shareUrl : "/share?p=%40posthog%2Ffrontend&s=72&e=82&w=1177&f=585" ,
74- } ,
75- {
76- name : "supabase" ,
77- githubUrl : "https://github.com/supabase/supabase" ,
78- score : 69 ,
79- errorCount : 74 ,
80- warningCount : 1087 ,
81- fileCount : 566 ,
82- shareUrl : "/share?p=studio&s=69&e=74&w=1087&f=566" ,
83- } ,
84- {
85- name : "onlook" ,
86- githubUrl : "https://github.com/onlook-dev/onlook" ,
87- score : 69 ,
88- errorCount : 64 ,
89- warningCount : 418 ,
90- fileCount : 178 ,
91- shareUrl : "/share?p=%40onlook%2Fweb-client&s=69&e=64&w=418&f=178" ,
92- } ,
93- {
94- name : "payload" ,
95- githubUrl : "https://github.com/payloadcms/payload" ,
96- score : 68 ,
97- errorCount : 139 ,
98- warningCount : 408 ,
99- fileCount : 298 ,
100- shareUrl : "/share?p=%40payloadcms%2Fui&s=68&e=139&w=408&f=298" ,
101- } ,
102- {
103- name : "sentry" ,
104- githubUrl : "https://github.com/getsentry/sentry" ,
105- score : 64 ,
106- errorCount : 94 ,
107- warningCount : 1345 ,
108- fileCount : 818 ,
109- shareUrl : "/share?p=sentry&s=64&e=94&w=1345&f=818" ,
110- } ,
111- {
112- name : "cal.com" ,
113- githubUrl : "https://github.com/calcom/cal.com" ,
114- score : 63 ,
115- errorCount : 31 ,
116- warningCount : 558 ,
117- fileCount : 311 ,
118- shareUrl : "/share?p=%40calcom%2Fweb&s=63&e=31&w=558&f=311" ,
119- } ,
120- {
121- name : "dub" ,
122- githubUrl : "https://github.com/dubinc/dub" ,
123- score : 62 ,
124- errorCount : 52 ,
125- warningCount : 966 ,
126- fileCount : 457 ,
127- shareUrl : "/share?p=web&s=62&e=52&w=966&f=457" ,
128- } ,
129- ] ;
10+ const CONTRIBUTE_URL =
11+ "https://github.com/millionco/react-doctor/edit/main/packages/website/src/app/leaderboard/leaderboard-entries.ts" ;
13012
13113const getScoreColorClass = ( score : number ) : string => {
13214 if ( score >= SCORE_GOOD_THRESHOLD ) return "text-green-400" ;
@@ -140,8 +22,6 @@ const getDoctorFace = (score: number): [string, string] => {
14022 return [ "x x" , " ▽ " ] ;
14123} ;
14224
143- const MAX_NAME_LENGTH = 12 ;
144-
14525const ScoreBar = ( { score } : { score : number } ) => {
14626 const filledCount = Math . round ( ( score / PERFECT_SCORE ) * SCORE_BAR_WIDTH ) ;
14727 const emptyCount = SCORE_BAR_WIDTH - filledCount ;
@@ -155,31 +35,27 @@ const ScoreBar = ({ score }: { score: number }) => {
15535 ) ;
15636} ;
15737
158- const LeaderboardRow = ( { entry, rank } : { entry : LeaderboardEntry ; rank : number } ) => {
38+ const LeaderboardRow = ( { entry, rank } : { entry : ResolvedLeaderboardEntry ; rank : number } ) => {
15939 const colorClass = getScoreColorClass ( entry . score ) ;
160- const paddedName = entry . name . padEnd ( MAX_NAME_LENGTH ) ;
16140
16241 return (
163- < div className = "group flex items-center gap-2 border-b border-white/5 py-2 transition-colors hover:bg-white/2 sm:gap-4 sm:py-2.5 " >
164- < span className = "w-6 shrink-0 text-right text-neutral-600 sm:w-8 " > { rank } </ span >
42+ < div className = "group grid items-center border-b border-white/5 py-2 transition-colors hover:bg-white/2 sm:py-2.5 grid-cols-[2rem_1fr_auto] sm:grid-cols-[2.5rem_7rem_1fr_auto] " >
43+ < span className = "text-right text-neutral-600" > { rank } </ span >
16544
16645 < a
16746 href = { entry . githubUrl }
16847 target = "_blank"
16948 rel = "noreferrer"
170- className = "shrink-0 text-white transition-colors hover:text-blue-400"
49+ className = "ml-2 truncate text-white transition-colors hover:text-blue-400 sm:ml-4 "
17150 >
172- < span className = "sm:hidden" >
173- { entry . name . length > 10 ? `${ entry . name . slice ( 0 , 9 ) } …` : entry . name }
174- </ span >
175- < span className = "hidden sm:inline" > { paddedName } </ span >
51+ { entry . name }
17652 </ a >
17753
178- < span className = "hidden flex-1 sm:inline" >
54+ < span className = "hidden sm:inline" >
17955 < ScoreBar score = { entry . score } />
18056 </ span >
18157
182- < Link href = { entry . shareUrl } className = "ml-auto shrink-0 transition-colors hover:underline" >
58+ < Link href = { entry . shareUrl } className = "ml-4 text-right transition-colors hover:underline" >
18359 < span className = { `${ colorClass } font-medium` } > { entry . score } </ span >
18460 < span className = "text-neutral-600" > /{ PERFECT_SCORE } </ span >
18561 </ Link >
@@ -230,6 +106,24 @@ const LeaderboardPage = () => {
230106 < div className = "mt-2" >
231107 < span className = "border border-white/20 px-3 py-1.5 text-white" > { COMMAND } </ span >
232108 </ div >
109+
110+ < div className = "min-h-[1.4em]" />
111+ < div className = "min-h-[1.4em]" />
112+
113+ < div className = "text-neutral-500" >
114+ { "+ " }
115+ < a
116+ href = { CONTRIBUTE_URL }
117+ target = "_blank"
118+ rel = "noreferrer"
119+ className = "text-green-400 transition-colors hover:text-green-300 hover:underline"
120+ >
121+ Add your project
122+ </ a >
123+ < span className = "text-neutral-600" >
124+ { " — open a PR to leaderboard-entries.ts" }
125+ </ span >
126+ </ div >
233127 </ div >
234128 ) ;
235129} ;
0 commit comments