@@ -5,41 +5,60 @@ const ORG_REPO = "fastrepl/hyprnote";
55
66// Curated list of profiles to display
77const CURATED_PROFILES = [
8- // TODO: Add your curated list of avatar URLs here
9- "https://avatars.githubusercontent.com/u/61503739?v=4" ,
10- "https://avatars.githubusercontent.com/u/105270342?v=4" ,
11- "https://avatars.githubusercontent.com/u/30039641?v=4" ,
12- "https://avatars.githubusercontent.com/u/63365510?v=4" ,
13- "https://avatars.githubusercontent.com/u/97124713?v=4" ,
14- "https://avatars.githubusercontent.com/u/59800?v=4" ,
15- "https://avatars.githubusercontent.com/u/51254761?v=4" ,
16- "https://avatars.githubusercontent.com/u/76832007?v=4" ,
17- "https://avatars.githubusercontent.com/u/86834898?v=4" ,
18- "https://avatars.githubusercontent.com/u/48201223?v=4" ,
19- "https://avatars.githubusercontent.com/u/26774729?v=4" ,
20- "https://avatars.githubusercontent.com/u/23347263?v=4" ,
8+ { username : "tobi" , avatar : "https://avatars.githubusercontent.com/u/347?v=4" } ,
9+ { username : "DidierRLopes" , avatar : "https://avatars.githubusercontent.com/u/25267873?v=4" } ,
10+ { username : "FelixMalfait" , avatar : "https://avatars.githubusercontent.com/u/6399865?v=4" } ,
11+ { username : "jeremyfowers" , avatar : "https://avatars.githubusercontent.com/u/80718789?v=4" } ,
12+ { username : "micheleriva" , avatar : "https://avatars.githubusercontent.com/u/14977595?v=4" } ,
13+ { username : "thomwolf" , avatar : "https://avatars.githubusercontent.com/u/7353373?v=4" } ,
14+ { username : "brodock" , avatar : "https://avatars.githubusercontent.com/u/20575?v=4" } ,
15+ { username : "anthonycorletti" , avatar : "https://avatars.githubusercontent.com/u/3477132?v=4" } ,
16+ { username : "followingell" , avatar : "https://avatars.githubusercontent.com/u/5324956?v=4" } ,
17+ { username : "mbanzi" , avatar : "https://avatars.githubusercontent.com/u/405127?v=4" } ,
18+ { username : "kevinxh" , avatar : "https://avatars.githubusercontent.com/u/10948652?v=4" } ,
19+ { username : "gregnr" , avatar : "https://avatars.githubusercontent.com/u/4133076?v=4" } ,
20+ { username : "JoeDo" , avatar : "https://avatars.githubusercontent.com/u/775702?v=4" } ,
21+ { username : "toby" , avatar : "https://avatars.githubusercontent.com/u/83556?v=4" } ,
22+ { username : "patrick91" , avatar : "https://avatars.githubusercontent.com/u/667029?v=4" } ,
23+ { username : "timrogers" , avatar : "https://avatars.githubusercontent.com/u/116134?v=4" } ,
24+ { username : "freeqaz" , avatar : "https://avatars.githubusercontent.com/u/4573221?v=4" } ,
25+ { username : "robertefreeman" , avatar : "https://avatars.githubusercontent.com/u/6842762?v=4" } ,
26+ { username : "mriley" , avatar : "https://avatars.githubusercontent.com/u/28009?v=4" } ,
27+ { username : "pmdartus" , avatar : "https://avatars.githubusercontent.com/u/2567083?v=4" } ,
28+ { username : "ezekg" , avatar : "https://avatars.githubusercontent.com/u/6979737?v=4" } ,
29+ { username : "Jonathanvwersch" , avatar : "https://avatars.githubusercontent.com/u/38623677?v=4" } ,
30+ { username : "thewh1teagle" , avatar : "https://avatars.githubusercontent.com/u/61390950?v=4" } ,
31+ { username : "dguido" , avatar : "https://avatars.githubusercontent.com/u/294844?v=4" } ,
32+ { username : "calvinfo" , avatar : "https://avatars.githubusercontent.com/u/487539?v=4" } ,
33+ { username : "velyan" , avatar : "https://avatars.githubusercontent.com/u/1313779?v=4" } ,
34+ { username : "mfts" , avatar : "https://avatars.githubusercontent.com/u/4049052?v=4" } ,
35+ { username : "devgony" , avatar : "https://avatars.githubusercontent.com/u/51254761?v=4" } ,
36+ { username : "bartoszgrabski" , avatar : "https://avatars.githubusercontent.com/u/5851315?v=4" } ,
37+ { username : "mpazik" , avatar : "https://avatars.githubusercontent.com/u/4086126?v=4" } ,
38+ { username : "Necromenta" , avatar : "https://avatars.githubusercontent.com/u/95664440?v=4" } ,
39+ { username : "jonpage0" , avatar : "https://avatars.githubusercontent.com/u/48391075?v=4" } ,
40+ { username : "ralder" , avatar : "https://avatars.githubusercontent.com/u/10889830?v=4" } ,
41+ { username : "mateusrevoredo" , avatar : "https://avatars.githubusercontent.com/u/1175432?v=4" } ,
42+ { username : "annieappflowy" , avatar : "https://avatars.githubusercontent.com/u/12026239?v=4" } ,
43+ { username : "carllippert" , avatar : "https://avatars.githubusercontent.com/u/16457876?v=4" } ,
44+ { username : "avneetsb" , avatar : "https://avatars.githubusercontent.com/u/5681972?v=4" } ,
45+ { username : "anrath" , avatar : "https://avatars.githubusercontent.com/u/62771105?v=4" } ,
46+ { username : "srikanta30" , avatar : "https://avatars.githubusercontent.com/u/28688901?v=4" } ,
47+ { username : "allisoneer" , avatar : "https://avatars.githubusercontent.com/u/20910163?v=4" } ,
48+ { username : "kebot" , avatar : "https://avatars.githubusercontent.com/u/289392?v=4" } ,
49+ { username : "daevaorn" , avatar : "https://avatars.githubusercontent.com/u/37366?v=4" } ,
50+ { username : "rdt712" , avatar : "https://avatars.githubusercontent.com/u/13369991?v=4" } ,
51+ { username : "olabrainy" , avatar : "https://avatars.githubusercontent.com/u/28204401?v=4" } ,
52+ { username : "aaronrau" , avatar : "https://avatars.githubusercontent.com/u/207538?v=4" } ,
53+ { username : "jhbao" , avatar : "https://avatars.githubusercontent.com/u/1714002?v=4" } ,
54+ { username : "dbkegley" , avatar : "https://avatars.githubusercontent.com/u/5727001?v=4" } ,
55+ { username : "chrismalek" , avatar : "https://avatars.githubusercontent.com/u/9403?v=4" } ,
56+ { username : "KlimDos" , avatar : "https://avatars.githubusercontent.com/u/17221993?v=4" } ,
57+ { username : "maximilianmessing" , avatar : "https://avatars.githubusercontent.com/u/7516094?v=4" } ,
58+ { username : "levysantanna" , avatar : "https://avatars.githubusercontent.com/u/1235238?v=4" } ,
59+ { username : "falltodis" , avatar : "https://avatars.githubusercontent.com/u/7006864?v=4" } ,
2160] ;
2261
23- function ProfileGrid ( { profiles, cols } : { profiles : string [ ] ; cols : 2 | 3 } ) {
24- const count = cols === 2 ? 4 : 6 ;
25- return (
26- < div className = { `grid grid-cols-${ cols } gap-1` } >
27- { profiles . slice ( 0 , count ) . map ( ( avatar , idx ) => (
28- < div
29- key = { `profile-${ idx } ` }
30- className = "size-10 rounded-sm overflow-hidden border-2 border-neutral-200 bg-neutral-100"
31- >
32- < img
33- src = { avatar }
34- alt = "Contributor"
35- className = "w-full h-full object-cover"
36- />
37- </ div >
38- ) ) }
39- </ div >
40- ) ;
41- }
42-
4362function StatBadge ( {
4463 type,
4564 count,
@@ -50,59 +69,243 @@ function StatBadge({
5069 const renderCount = ( n : number ) => n > 1000 ? `${ ( n / 1000 ) . toFixed ( 1 ) } k` : n ;
5170
5271 return (
53- < div className = "flex flex-col gap-1 text-stone-600 h-24 items-center justify-center border border-neutral-200 rounded-sm px-4 bg-neutral-100" >
54- < p className = "font-semibold font-serif" >
72+ < div className = "flex flex-col gap-1 text-stone-600 h-[84px] w-[84px] items-center justify-center border border-neutral-200 rounded-sm px-4 bg-neutral-100" >
73+ < p className = "font-semibold font-serif text-sm " >
5574 { type === "stars" ? "Stars" : "Forks" }
5675 </ p >
57- < p className = "text-sm font-medium text-center" >
58- { renderCount ( count ) }
76+ < p className = "text-sm font-medium text-center" > { renderCount ( count ) } </ p >
77+ </ div >
78+ ) ;
79+ }
80+
81+ function OpenSourceButton ( { showStars = false , starCount } : { showStars ?: boolean ; starCount ?: number } ) {
82+ const renderCount = ( n : number ) => n > 1000 ? `${ ( n / 1000 ) . toFixed ( 1 ) } k` : n ;
83+
84+ return (
85+ < div className = "text-center space-y-4 w-full" >
86+ < h2 className = "text-3xl font-serif text-stone-600" > Open source</ h2 >
87+ < p className = "text-lg text-neutral-600" >
88+ { "Hyprnote values privacy and community, so it's been transparent from day one" }
5989 </ p >
90+ < a
91+ href = { `https://github.com/${ ORG_REPO } ` }
92+ target = "_blank"
93+ rel = "noopener noreferrer"
94+ className = { cn ( [
95+ "group px-6 h-12 inline-flex items-center justify-center gap-2" ,
96+ "bg-linear-to-t from-neutral-800 to-neutral-700 text-white rounded-full" ,
97+ "shadow-md hover:shadow-lg hover:scale-[102%] active:scale-[98%]" ,
98+ "transition-all cursor-pointer" ,
99+ ] ) }
100+ >
101+ < Icon icon = "mdi:github" className = "text-xl" />
102+ View on GitHub
103+ { showStars && starCount && (
104+ < >
105+ < span className = "text-neutral-400" > •</ span >
106+ < div className = "flex items-center gap-1" >
107+ < Icon icon = "mdi:star" className = "text-lg" />
108+ < span > { renderCount ( starCount ) } </ span >
109+ </ div >
110+ </ >
111+ ) }
112+ </ a >
60113 </ div >
61114 ) ;
62115}
63116
117+ function Avatar ( { username, avatar } : { username : string ; avatar : string } ) {
118+ return (
119+ < a
120+ href = { `https://github.com/${ username } ` }
121+ target = "_blank"
122+ rel = "noopener noreferrer"
123+ className = "size-10 rounded-sm overflow-hidden border-2 border-neutral-200 bg-neutral-100 shrink-0 hover:scale-110 hover:border-neutral-400 transition-all cursor-pointer"
124+ >
125+ < img src = { avatar } alt = { `${ username } 's avatar` } className = "w-full h-full object-cover" />
126+ </ a >
127+ ) ;
128+ }
129+
130+ function GridRow ( {
131+ children,
132+ } : {
133+ children : React . ReactNode ;
134+ } ) {
135+ return < div className = "flex gap-1 items-center" > { children } </ div > ;
136+ }
137+
64138export function GitHubOpenSource ( ) {
65139 const STARS_COUNT = 6419 ;
66140 const FORKS_COUNT = 396 ;
67141
68142 return (
69143 < section className = "border-t border-neutral-100" >
70- < div className = "py-16" >
71- < div className = "grid grid-cols-1 lg:grid-cols-3 items-center max-w-6xl mx-auto" >
72- { /* Column 1: 2x2 grid + Stars badge + 3x2 grid */ }
73- < div className = "flex items-center gap-1 justify-center bg-red-100" >
74- < ProfileGrid profiles = { CURATED_PROFILES . slice ( 0 , 4 ) } cols = { 2 } />
75- < StatBadge type = "stars" count = { STARS_COUNT } />
76- < ProfileGrid profiles = { CURATED_PROFILES . slice ( 4 , 10 ) } cols = { 3 } />
144+ < div className = "py-16 px-4" >
145+ { /* Small & Medium screens: button with star count */ }
146+ < div className = "lg:hidden max-w-4xl mx-auto" >
147+ < OpenSourceButton showStars = { true } starCount = { STARS_COUNT } />
148+ </ div >
149+
150+ { /* Large screen: 3-column layout with symmetric left and right sides */ }
151+ < div className = "hidden lg:flex justify-between max-w-7xl mx-auto items-center" >
152+ { /* Left Side: 3 sub-columns with explicit widths */ }
153+ < div className = "flex gap-1" >
154+ { /* Left Sub-column 1: 2x4 grid */ }
155+ < div className = "flex flex-col gap-1" >
156+ { /* Row 1 */ }
157+ < GridRow >
158+ { CURATED_PROFILES . slice ( 0 , 2 ) . map ( ( profile ) => (
159+ < Avatar key = { `left-c1-r1-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
160+ ) ) }
161+ </ GridRow >
162+ { /* Row 2 */ }
163+ < GridRow >
164+ { CURATED_PROFILES . slice ( 2 , 4 ) . map ( ( profile ) => (
165+ < Avatar key = { `left-c1-r2-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
166+ ) ) }
167+ </ GridRow >
168+ { /* Row 3 */ }
169+ < GridRow >
170+ { CURATED_PROFILES . slice ( 4 , 6 ) . map ( ( profile ) => (
171+ < Avatar key = { `left-c1-r3-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
172+ ) ) }
173+ </ GridRow >
174+ { /* Row 4 */ }
175+ < GridRow >
176+ { CURATED_PROFILES . slice ( 6 , 8 ) . map ( ( profile ) => (
177+ < Avatar key = { `left-c1-r4-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
178+ ) ) }
179+ </ GridRow >
180+ </ div >
181+
182+ { /* Left Sub-column 2: 2 avatars + Stars badge (spans 2 rows) + 2 avatars */ }
183+ < div className = "flex flex-col gap-1" >
184+ { /* Row 1 */ }
185+ < GridRow >
186+ { CURATED_PROFILES . slice ( 8 , 10 ) . map ( ( profile ) => (
187+ < Avatar key = { `left-c2-r1-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
188+ ) ) }
189+ </ GridRow >
190+ { /* Rows 2-3: Stars badge - spans 2 rows (40px + 4px + 40px = 84px) */ }
191+ < StatBadge type = "stars" count = { STARS_COUNT } />
192+ { /* Row 4 */ }
193+ < GridRow >
194+ { CURATED_PROFILES . slice ( 10 , 12 ) . map ( ( profile ) => (
195+ < Avatar key = { `left-c2-r4-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
196+ ) ) }
197+ </ GridRow >
198+ </ div >
199+
200+ { /* Left Sub-column 3: 3x4 grid */ }
201+ < div className = "flex flex-col gap-1" >
202+ { /* Row 1 */ }
203+ < GridRow >
204+ { CURATED_PROFILES . slice ( 12 , 15 ) . map ( ( profile ) => (
205+ < Avatar key = { `left-c3-r1-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
206+ ) ) }
207+ </ GridRow >
208+ { /* Row 2 */ }
209+ < GridRow >
210+ { CURATED_PROFILES . slice ( 15 , 18 ) . map ( ( profile ) => (
211+ < Avatar key = { `left-c3-r2-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
212+ ) ) }
213+ </ GridRow >
214+ { /* Row 3 */ }
215+ < GridRow >
216+ { CURATED_PROFILES . slice ( 18 , 21 ) . map ( ( profile ) => (
217+ < Avatar key = { `left-c3-r3-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
218+ ) ) }
219+ </ GridRow >
220+ { /* Row 4 */ }
221+ < GridRow >
222+ { CURATED_PROFILES . slice ( 21 , 24 ) . map ( ( profile ) => (
223+ < Avatar key = { `left-c3-r4-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
224+ ) ) }
225+ </ GridRow >
226+ </ div >
77227 </ div >
78228
79- { /* Column 2: Text content */ }
80- < div className = "text-center space-y-4" >
81- < h2 className = "text-3xl font-serif text-stone-600" > Open source</ h2 >
82- < p className = "text-lg text-neutral-600" >
83- { "Hyprnote values privacy and community, so it's been transparent from day one" }
84- </ p >
85- < a
86- href = { `https://github.com/${ ORG_REPO } ` }
87- target = "_blank"
88- rel = "noopener noreferrer"
89- className = { cn ( [
90- "group px-6 h-12 inline-flex items-center justify-center gap-2" ,
91- "bg-linear-to-t from-neutral-800 to-neutral-700 text-white rounded-full" ,
92- "shadow-md hover:shadow-lg hover:scale-[102%] active:scale-[98%]" ,
93- "transition-all cursor-pointer" ,
94- ] ) }
95- >
96- < Icon icon = "mdi:github" className = "text-xl" />
97- View on GitHub
98- </ a >
229+ { /* Center Column: Open Source Button */ }
230+ < div className = "flex items-center justify-center" >
231+ < OpenSourceButton />
99232 </ div >
100233
101- { /* Column 3: 2x2 grid + Forks badge + 3x2 grid */ }
102- < div className = "flex items-center gap-1 justify-center" >
103- < ProfileGrid profiles = { CURATED_PROFILES . slice ( 4 , 10 ) } cols = { 3 } />
104- < StatBadge type = "forks" count = { FORKS_COUNT } />
105- < ProfileGrid profiles = { CURATED_PROFILES . slice ( 0 , 4 ) } cols = { 2 } />
234+ { /* Right Side: 3 sub-columns with explicit widths (symmetric) */ }
235+ < div className = "flex gap-1" >
236+ { /* Right Sub-column 1: 3x4 grid */ }
237+ < div className = "flex flex-col gap-1" >
238+ { /* Row 1 */ }
239+ < GridRow >
240+ { CURATED_PROFILES . slice ( 24 , 27 ) . map ( ( profile ) => (
241+ < Avatar key = { `right-c1-r1-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
242+ ) ) }
243+ </ GridRow >
244+ { /* Row 2 */ }
245+ < GridRow >
246+ { CURATED_PROFILES . slice ( 27 , 30 ) . map ( ( profile ) => (
247+ < Avatar key = { `right-c1-r2-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
248+ ) ) }
249+ </ GridRow >
250+ { /* Row 3 */ }
251+ < GridRow >
252+ { CURATED_PROFILES . slice ( 30 , 33 ) . map ( ( profile ) => (
253+ < Avatar key = { `right-c1-r3-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
254+ ) ) }
255+ </ GridRow >
256+ { /* Row 4 */ }
257+ < GridRow >
258+ { CURATED_PROFILES . slice ( 33 , 36 ) . map ( ( profile ) => (
259+ < Avatar key = { `right-c1-r4-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
260+ ) ) }
261+ </ GridRow >
262+ </ div >
263+
264+ { /* Right Sub-column 2: 2 avatars + Forks badge (spans 2 rows) + 2 avatars */ }
265+ < div className = "flex flex-col gap-1" >
266+ { /* Row 1 */ }
267+ < GridRow >
268+ { CURATED_PROFILES . slice ( 36 , 38 ) . map ( ( profile ) => (
269+ < Avatar key = { `right-c2-r1-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
270+ ) ) }
271+ </ GridRow >
272+ { /* Rows 2-3: Forks badge - spans 2 rows (40px + 4px + 40px = 84px) */ }
273+ < StatBadge type = "forks" count = { FORKS_COUNT } />
274+ { /* Row 4 */ }
275+ < GridRow >
276+ { CURATED_PROFILES . slice ( 38 , 40 ) . map ( ( profile ) => (
277+ < Avatar key = { `right-c2-r4-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
278+ ) ) }
279+ </ GridRow >
280+ </ div >
281+
282+ { /* Right Sub-column 3: 2x4 grid */ }
283+ < div className = "flex flex-col gap-1" >
284+ { /* Row 1 */ }
285+ < GridRow >
286+ { CURATED_PROFILES . slice ( 40 , 42 ) . map ( ( profile ) => (
287+ < Avatar key = { `right-c3-r1-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
288+ ) ) }
289+ </ GridRow >
290+ { /* Row 2 */ }
291+ < GridRow >
292+ { CURATED_PROFILES . slice ( 42 , 44 ) . map ( ( profile ) => (
293+ < Avatar key = { `right-c3-r2-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
294+ ) ) }
295+ </ GridRow >
296+ { /* Row 3 */ }
297+ < GridRow >
298+ { CURATED_PROFILES . slice ( 44 , 46 ) . map ( ( profile ) => (
299+ < Avatar key = { `right-c3-r3-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
300+ ) ) }
301+ </ GridRow >
302+ { /* Row 4 */ }
303+ < GridRow >
304+ { CURATED_PROFILES . slice ( 46 , 48 ) . map ( ( profile ) => (
305+ < Avatar key = { `right-c3-r4-${ profile . username } ` } username = { profile . username } avatar = { profile . avatar } />
306+ ) ) }
307+ </ GridRow >
308+ </ div >
106309 </ div >
107310 </ div >
108311 </ div >
0 commit comments