@@ -221,200 +221,164 @@ <h2 class="section-title" data-aos="fade-right">Explore Our Projects</h2>
221221 </ div >
222222 </ section >
223223
224- < section id ="contributors " class ="" style ="padding: 20px " data-aos ="fade-up ">
225- < h1 class ="hero-text ms-5 "> Our Contributors</ h1 >
226- < div id ="contributors-box ">
227- < ul id ="contributors-list ">
228- <!-- Contributors will be displayed here -->
229- </ ul >
230- </ div >
231- </ section >
232-
233- <!-- Footer -->
234- < footer class ="bg-dark text-light text-center py-3 " data-aos ="fade-up ">
235- < div class ="container ">
236- < a href ="https://github.com/ianshulx " target ="_blank "> < i class ="bi bi-github "> </ i > </ a >
237-
238-
239- < br >
240- This repository is licensed under the MIT license. See the
241- < a href ="https://github.com/ianshulx/react-projects-for-beginners/blob/main/LICENSE " target ="_blank "> LICENSE
242- </ a >
243- file for more information.
244- </ p >
245- </ div >
246- </ footer >
224+ < section id ="contributors " class ="" style ="padding: 20px " data-aos ="fade-up ">
225+ < h1 class ="hero-text ms-5 "> Our Contributors</ h1 >
226+ < div id ="contributors-box ">
227+ < ul id ="contributors-list ">
228+ <!-- Contributors will be displayed here -->
229+ </ ul >
247230 </ div >
248-
249- < script >
250- // Replace with your GitHub repository URL
251- const repoUrl =
252- "https://api.github.com/repos/ianshulx/react-Projects-for-beginners" ;
253-
254- // Fetch contributors data from GitHub API
255- fetch ( `${ repoUrl } /contributors` )
256- . then ( ( response ) => response . json ( ) )
257- . then ( ( data ) => {
258- const contributorsList = document . getElementById ( "contributors-list" ) ;
259-
260- // Loop through the contributors and create list items
261- data . forEach ( ( contributor ) => {
262- const listItem = document . createElement ( "li" ) ;
263- listItem . innerHTML = `
264- <a href="${ contributor . html_url } " target="_blank">
265- <img src="${ contributor . avatar_url } " alt="${ contributor . login } " width="100" height="100">
266- <p>${ contributor . login } </p>
267- </a>
268- ` ;
269- contributorsList . appendChild ( listItem ) ;
270- } ) ;
271-
272- // Update contributors count in menu button and stats
273- const contributorsBtn = document . querySelector ( '.contributors-btn' ) ;
274- if ( contributorsBtn ) {
275- contributorsBtn . innerHTML = `<i class="bi bi-people-fill"></i> Contributors (${ data . length } )` ;
276- }
277-
278- const contributorCount = document . getElementById ( 'contributor-count' ) ;
279- if ( contributorCount ) {
280- contributorCount . textContent = data . length + '+' ;
281- }
282- } )
283- . catch ( ( error ) => {
284- console . error ( "Error fetching data:" , error ) ;
285- } ) ;
286-
287- // Fetch repo details for stars, forks, watchers, etc.
288- fetch ( repoUrl )
289- . then ( ( response ) => response . json ( ) )
290- . then ( ( repoData ) => {
291- // Update stars count
292- const starBtn = document . querySelector ( '.star-btn' ) ;
293- if ( starBtn ) {
294- starBtn . innerHTML = `<i class="bi bi-star-fill"></i> Star (${ repoData . stargazers_count } )` ;
295- }
296-
297- const starCount = document . getElementById ( 'star-count' ) ;
298- if ( starCount ) {
299- starCount . textContent = repoData . stargazers_count + '+' ;
300- }
301-
302- // Update forks count
303- const forkBtn = document . querySelector ( '.fork-btn' ) ;
304- if ( forkBtn ) {
305- forkBtn . innerHTML = `<i class="bi bi-code-branch"></i> Fork (${ repoData . forks_count } )` ;
306- }
307- // Fetch open PRs count
308- fetch ( `${ repoUrl } /pulls?state=open` )
309- . then ( ( response ) => response . json ( ) )
310- . then ( ( pullsData ) => {
311- const prCount = pullsData . length ;
312- const issuesCount = repoData . open_issues_count - prCount ;
313- const watchersCount = repoData . subscribers_count ;
314- // Fix NaN and undefined counts by validating values
315- const safeIssuesCount = Number . isInteger ( issuesCount ) && issuesCount >= 0 ? issuesCount : 0 ;
316- const safePrCount = Number . isInteger ( prCount ) && prCount >= 0 ? prCount : 0 ;
317- const safeWatchersCount = Number . isInteger ( watchersCount ) && watchersCount >= 0 ? watchersCount : 0 ;
318- // Update issues
319- const issuesBtn = document . querySelector ( '.issues-btn' ) ;
320- if ( issuesBtn ) {
321- issuesBtn . innerHTML = `<i class="bi bi-exclamation-circle-fill"></i> Issues (${ safeIssuesCount } )` ;
322- }
323- // Update PRs
324- const prBtn = document . querySelector ( '.pr-btn' ) ;
325- if ( prBtn ) {
326- prBtn . innerHTML = `<i class="bi bi-git-pull-request"></i> Pull Requests (${ safePrCount } )` ;
327- }
328- // Update Watchers
329- const watchersBtn = document . querySelector ( '.watchers-btn' ) ;
330- if ( watchersBtn ) {
331- watchersBtn . innerHTML = `<i class="bi bi-eye"></i> Watchers (${ safeWatchersCount } )` ;
332- }
333- } )
334- . catch ( ( error ) => {
335- console . error ( "Error fetching pulls:" , error ) ;
336- } ) ;
337- } )
338- . catch ( ( error ) => {
339- console . error ( "Error fetching repo data:" , error ) ;
340- } ) ;
341-
342- // Navbar scroll effect
343- const navbar = document . querySelector ( '.floating-navbar' ) ;
344- window . addEventListener ( 'scroll' , ( ) => {
345- if ( window . scrollY > 10 ) {
346- navbar . classList . add ( 'scrolled' ) ;
347- } else {
348- navbar . classList . remove ( 'scrolled' ) ;
349- }
231+ </ section >
232+
233+ <!-- Footer -->
234+ < footer class ="bg-dark text-light text-center py-3 " data-aos ="fade-up ">
235+ < div class ="container ">
236+ < a href ="https://github.com/ianshulx " target ="_blank "> < i class ="bi bi-github "> </ i > </ a >
237+ < br >
238+ This repository is licensed under the MIT license. See the
239+ < a href ="https://github.com/ianshulx/react-projects-for-beginners/blob/main/LICENSE " target ="_blank "> LICENSE</ a >
240+ file for more information.
241+ </ div >
242+ </ footer >
243+
244+ < script >
245+ const repoUrl = "https://api.github.com/repos/ianshulx/react-Projects-for-beginners" ;
246+ const contributorsList = document . getElementById ( "contributors-list" ) ;
247+
248+ async function fetchAllContributors ( ) {
249+ let allContributors = [ ] ;
250+ let page = 1 ;
251+ const perPage = 100 ; // max allowed by GitHub
252+
253+ while ( true ) {
254+ const response = await fetch ( `${ repoUrl } /contributors?per_page=${ perPage } &page=${ page } ` ) ;
255+ const data = await response . json ( ) ;
256+ if ( data . length === 0 ) break ;
257+ allContributors = allContributors . concat ( data ) ;
258+ page ++ ;
259+ }
260+
261+ // Display contributors
262+ allContributors . forEach ( contributor => {
263+ const li = document . createElement ( "li" ) ;
264+ li . innerHTML = `
265+ <a href="${ contributor . html_url } " target="_blank">
266+ <img src="${ contributor . avatar_url } " alt="${ contributor . login } " width="100" height="100">
267+ <p>${ contributor . login } </p>
268+ </a>
269+ ` ;
270+ contributorsList . appendChild ( li ) ;
350271 } ) ;
351272
352- // Fade logo on scroll
353- const logoDiv = document . querySelector ( '.hf-logoo' ) ;
354- window . addEventListener ( 'scroll' , ( ) => {
355- const scrollY = window . scrollY ;
356- if ( scrollY > 50 ) {
357- logoDiv . style . opacity = '0' ;
358- } else {
359- logoDiv . style . opacity = '1' ;
360- }
361- } ) ;
362- </ script >
363- < script src ="projects.js "> </ script >
273+ // Update contributors count
274+ const contributorsBtn = document . querySelector ( '.contributors-btn' ) ;
275+ if ( contributorsBtn ) contributorsBtn . innerHTML = `<i class="bi bi-people-fill"></i> Contributors (${ allContributors . length } )` ;
276+
277+ const contributorCount = document . getElementById ( 'contributor-count' ) ;
278+ if ( contributorCount ) contributorCount . textContent = allContributors . length + '+' ;
279+ }
280+
281+ fetchAllContributors ( ) . catch ( console . error ) ;
282+
283+ // Fetch repo details
284+ async function fetchRepoDetails ( ) {
285+ try {
286+ const repoData = await ( await fetch ( repoUrl ) ) . json ( ) ;
364287
288+ // Update stars
289+ const starBtn = document . querySelector ( '.star-btn' ) ;
290+ if ( starBtn ) starBtn . innerHTML = `<i class="bi bi-star-fill"></i> Star (${ repoData . stargazers_count } )` ;
365291
292+ const starCount = document . getElementById ( 'star-count' ) ;
293+ if ( starCount ) starCount . textContent = repoData . stargazers_count + '+' ;
366294
367- < script src ="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js "
368- integrity ="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL "
369- crossorigin ="anonymous "> </ script >
370- < script src ="https://code.jquery.com/jquery-3.6.0.min.js "> </ script >
295+ // Update forks
296+ const forkBtn = document . querySelector ( '.fork-btn' ) ;
297+ if ( forkBtn ) forkBtn . innerHTML = `<i class="bi bi-code-branch"></i> Fork (${ repoData . forks_count } )` ;
371298
372- <!-- AOS Animation Script -->
373- < script src ="https://unpkg.com/aos@2.3.1/dist/aos.js "> </ script >
374- < script >
375- window . addEventListener ( "load" , ( ) =>
299+ // Update open PRs, issues, watchers
300+ const pullsData = await ( await fetch ( `${ repoUrl } /pulls?state=open` ) ) . json ( ) ;
301+ const prCount = pullsData . length ;
302+ const issuesCount = Math . max ( repoData . open_issues_count - prCount , 0 ) ;
303+ const watchersCount = Math . max ( repoData . subscribers_count || 0 , 0 ) ;
304+
305+ const issuesBtn = document . querySelector ( '.issues-btn' ) ;
306+ if ( issuesBtn ) issuesBtn . innerHTML = `<i class="bi bi-exclamation-circle-fill"></i> Issues (${ issuesCount } )` ;
307+
308+ const prBtn = document . querySelector ( '.pr-btn' ) ;
309+ if ( prBtn ) prBtn . innerHTML = `<i class="bi bi-git-pull-request"></i> Pull Requests (${ prCount } )` ;
310+
311+ const watchersBtn = document . querySelector ( '.watchers-btn' ) ;
312+ if ( watchersBtn ) watchersBtn . innerHTML = `<i class="bi bi-eye"></i> Watchers (${ watchersCount } )` ;
313+
314+ } catch ( err ) {
315+ console . error ( "Error fetching repo details:" , err ) ;
316+ }
317+ }
318+
319+ fetchRepoDetails ( ) ;
320+
321+ // Navbar scroll effect
322+ const navbar = document . querySelector ( '.floating-navbar' ) ;
323+ window . addEventListener ( 'scroll' , ( ) => {
324+ if ( window . scrollY > 10 ) navbar . classList . add ( 'scrolled' ) ;
325+ else navbar . classList . remove ( 'scrolled' ) ;
326+ } ) ;
327+
328+ // Fade logo on scroll
329+ const logoDiv = document . querySelector ( '.hf-logoo' ) ;
330+ window . addEventListener ( 'scroll' , ( ) => {
331+ logoDiv . style . opacity = window . scrollY > 50 ? '0' : '1' ;
332+ } ) ;
333+ </ script >
334+
335+ < script src ="projects.js "> </ script >
336+ < script src ="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js " integrity ="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL " crossorigin ="anonymous "> </ script >
337+ < script src ="https://code.jquery.com/jquery-3.6.0.min.js "> </ script >
338+
339+ <!-- AOS Animation Script -->
340+ < script src ="https://unpkg.com/aos@2.3.1/dist/aos.js "> </ script >
341+ < script >
342+ window . addEventListener ( "load" , ( ) => {
376343 AOS . init ( {
377344 duration : 800 ,
378345 easing : 'ease-out-cubic' ,
379346 once : true ,
380347 offset : 50
381- } )
382- ) ;
383-
384- </ script >
385-
386- < svg version ="1.1 " xmlns ="http://www.w3.org/2000/svg " xmlns:xlink ="http://www.w3.org/1999/xlink " x ="0px " y ="0px "
387- width ="100% " height ="100% " viewBox ="0 0 1600 900 " preserveAspectRatio ="xMidYMax slice ">
388- < defs >
389- < linearGradient id ="bg ">
390- < stop offset ="0% " style ="stop-color:rgba(130, 158, 249, 0.06) "> </ stop >
391- < stop offset ="50% " style ="stop-color:rgba(76, 190, 255, 0.6) "> </ stop >
392- < stop offset ="100% " style ="stop-color:rgba(115, 209, 72, 0.2) "> </ stop >
393- </ linearGradient >
394- < path id ="wave " fill ="url(#bg) " d ="M-363.852,502.589c0,0,236.988-41.997,505.475,0
395- s371.981,38.998,575.971,0s293.985-39.278,505.474,5.859s493.475,48.368,716.963-4.995v560.106H-363.852V502.589z " />
396- </ defs >
397- < g >
398- < use xlink:href ='#wave ' opacity =".3 ">
399- < animateTransform attributeName ="transform " attributeType ="XML " type ="translate " dur ="10s " calcMode ="spline "
400- values ="270 230; -334 180; 270 230 " keyTimes ="0; .5; 1 " keySplines ="0.42, 0, 0.58, 1.0;0.42, 0, 0.58, 1.0 "
401- repeatCount ="indefinite " />
402- </ use >
403- < use xlink:href ='#wave ' opacity =".6 ">
404- < animateTransform attributeName ="transform " attributeType ="XML " type ="translate " dur ="8s " calcMode ="spline "
405- values ="-270 230;243 220;-270 230 " keyTimes ="0; .6; 1 " keySplines ="0.42, 0, 0.58, 1.0;0.42, 0, 0.58, 1.0 "
406- repeatCount ="indefinite " />
407- </ use >
408- < use xlink:href ='#wave ' opacity =".9 ">
409- < animateTransform attributeName ="transform " attributeType ="XML " type ="translate " dur ="6s " calcMode ="spline "
410- values ="0 230;-140 200;0 230 " keyTimes ="0; .4; 1 " keySplines ="0.42, 0, 0.58, 1.0;0.42, 0, 0.58, 1.0 "
411- repeatCount ="indefinite " />
412- </ use >
413- </ g >
414- </ svg >
415- </ body >
416- < script src ="./menu-toggle.js "> </ script >
417-
418-
348+ } ) ;
349+ } ) ;
350+ </ script >
351+
352+ <!-- Wave SVG Animation -->
353+ < svg version ="1.1 " xmlns ="http://www.w3.org/2000/svg " xmlns:xlink ="http://www.w3.org/1999/xlink " x ="0px " y ="0px "
354+ width ="100% " height ="100% " viewBox ="0 0 1600 900 " preserveAspectRatio ="xMidYMax slice ">
355+ < defs >
356+ < linearGradient id ="bg ">
357+ < stop offset ="0% " style ="stop-color:rgba(130, 158, 249, 0.06) "> </ stop >
358+ < stop offset ="50% " style ="stop-color:rgba(76, 190, 255, 0.6) "> </ stop >
359+ < stop offset ="100% " style ="stop-color:rgba(115, 209, 72, 0.2) "> </ stop >
360+ </ linearGradient >
361+ < path id ="wave " fill ="url(#bg) " d ="M-363.852,502.589c0,0,236.988-41.997,505.475,0
362+ s371.981,38.998,575.971,0s293.985-39.278,505.474,5.859s493.475,48.368,716.963-4.995v560.106H-363.852V502.589z " />
363+ </ defs >
364+ < g >
365+ < use xlink:href ='#wave ' opacity =".3 ">
366+ < animateTransform attributeName ="transform " attributeType ="XML " type ="translate " dur ="10s " calcMode ="spline "
367+ values ="270 230; -334 180; 270 230 " keyTimes ="0; .5; 1 " keySplines ="0.42, 0, 0.58, 1.0;0.42, 0, 0.58, 1.0 "
368+ repeatCount ="indefinite " />
369+ </ use >
370+ < use xlink:href ='#wave ' opacity =".6 ">
371+ < animateTransform attributeName ="transform " attributeType ="XML " type ="translate " dur ="8s " calcMode ="spline "
372+ values ="-270 230;243 220;-270 230 " keyTimes ="0; .6; 1 " keySplines ="0.42, 0, 0.58, 1.0;0.42, 0, 0.58, 1.0 "
373+ repeatCount ="indefinite " />
374+ </ use >
375+ < use xlink:href ='#wave ' opacity =".9 ">
376+ < animateTransform attributeName ="transform " attributeType ="XML " type ="translate " dur ="6s " calcMode ="spline "
377+ values ="0 230;-140 200;0 230 " keyTimes ="0; .4; 1 " keySplines ="0.42, 0, 0.58, 1.0;0.42, 0, 0.58, 1.0 "
378+ repeatCount ="indefinite " />
379+ </ use >
380+ </ g >
381+ </ svg >
419382
420- </ html >
383+ < script src ="./menu-toggle.js "> </ script >
384+ </ div > </ body > </ html >
0 commit comments