-
Notifications
You must be signed in to change notification settings - Fork 356
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed the rate limit exceed of GitHub API on contributors page (#1426)
- Loading branch information
1 parent
8086579
commit d1866c1
Showing
4 changed files
with
188 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,128 @@ | ||
const cont = document.getElementById('contributor'); | ||
let currentPage = 1; // Start from page 1 | ||
let isLoading = false; // Flag to track loading state | ||
let hasMore = true; // Flag to track if there's more data to load | ||
|
||
// Loading spinner element | ||
const loadingSpinner = document.getElementById('loading-spinner'); | ||
|
||
// Error message element | ||
const errorMessage = document.getElementById('error-message'); | ||
|
||
// Intersection Observer for infinite scroll | ||
const observerOptions = { | ||
root: null, | ||
rootMargin: '0px', | ||
threshold: 0.1 | ||
}; | ||
|
||
// Use when one page is loaded, and then scroll down to load more | ||
const intersectionObserver = new IntersectionObserver((entries) => { | ||
entries.forEach(entry => { | ||
if (entry.isIntersecting && !isLoading && hasMore) { | ||
// If intersecting, not in loading state, and has more data to load | ||
fetchContributors(currentPage); | ||
} | ||
}); | ||
}, observerOptions); | ||
|
||
// Lazy loading observer for avatars | ||
const lazyLoadObserver = new IntersectionObserver((entries) => { | ||
entries.forEach(entry => { | ||
if (entry.isIntersecting) { | ||
const img = entry.target; | ||
img.src = img.dataset.src; | ||
img.classList.remove('lazy'); | ||
lazyLoadObserver.unobserve(img); | ||
} | ||
}); | ||
}, observerOptions); | ||
|
||
// Loads a single page of contributors | ||
async function fetchContributors(pageNumber) { | ||
const perPage = 100; | ||
const apiUrl = '/.netlify/functions/contributors'; // Netlify serverless function path | ||
if (isLoading) return; | ||
|
||
const response = await fetch(`${apiUrl}?page=${pageNumber}&per_page=${perPage}`); | ||
|
||
if (!response.ok) { | ||
throw new Error(`Failed to fetch the contributors data. Status code: ${response.status}`); | ||
} | ||
isLoading = true; | ||
const perPage = 20; // Number of items per page | ||
const apiUrl = '/.netlify/functions/contributors'; | ||
|
||
const contributorsData = await response.json(); | ||
return contributorsData; | ||
} | ||
try { | ||
// Show loading spinner at the bottom | ||
loadingSpinner.style.display = 'block'; | ||
|
||
async function fetchAllContributors() { | ||
let allContributors = []; | ||
let pageNumber = 1; | ||
const maxPages = 10; // Limiting the number of pages to avoid overload (can be adjusted) | ||
const response = await fetch(`${apiUrl}?page=${pageNumber}&per_page=${perPage}`); | ||
|
||
try { | ||
// Fetch all contributors in parallel using Promise.all() | ||
const fetchPromises = []; | ||
if (!response.ok) { | ||
throw new Error(`Failed to fetch contributors. Status: ${response.status}`); | ||
} | ||
|
||
const contributorsData = await response.json(); | ||
|
||
// Fetch data for multiple pages concurrently | ||
for (let i = 1; i <= maxPages; i++) { | ||
fetchPromises.push(fetchContributors(i)); | ||
// Check if we have more data to load | ||
hasMore = contributorsData.length === perPage; | ||
|
||
// Create and append contributor cards | ||
await displayContributors(contributorsData); | ||
|
||
currentPage++; | ||
} catch (error) { | ||
errorMessage.style.display = 'block'; | ||
console.error('Error fetching contributors:', error); | ||
} finally { | ||
isLoading = false; | ||
loadingSpinner.style.display = 'none'; | ||
|
||
// Add observer to the last card for infinite scroll | ||
const allCards = cont.querySelectorAll('.contributor-card'); | ||
if (allCards.length > 0) { | ||
intersectionObserver.observe(allCards[allCards.length - 1]); | ||
} | ||
} | ||
} | ||
|
||
const contributorsArray = await Promise.all(fetchPromises); | ||
// Displays the contributors on the page | ||
async function displayContributors(contributors) { | ||
const fragment = document.createDocumentFragment(); | ||
|
||
// Combine all the results | ||
contributorsArray.forEach(contributorsData => { | ||
allContributors = allContributors.concat(contributorsData); | ||
}); | ||
for (const contributor of contributors) { | ||
if (contributor.login === 'Rakesh9100') continue; // Skip owner | ||
|
||
// Display contributor cards | ||
allContributors.forEach((contributor) => { | ||
if (contributor.login === 'Rakesh9100') return; // Skip owner | ||
const contributorCard = document.createElement('div'); | ||
contributorCard.classList.add('contributor-card'); | ||
|
||
const contributorCard = document.createElement('div'); | ||
contributorCard.classList.add('contributor-card'); | ||
// Create avatar with lazy loading | ||
const avatarImg = document.createElement('img'); | ||
avatarImg.classList.add('lazy'); | ||
avatarImg.src = '../images/avatar.svg'; // Add a placeholder image | ||
avatarImg.dataset.src = contributor.avatar_url; | ||
avatarImg.alt = `${contributor.login}'s Picture`; | ||
|
||
const avatarImg = document.createElement('img'); | ||
avatarImg.src = contributor.avatar_url; | ||
avatarImg.alt = `${contributor.login}'s Picture`; | ||
const loginLink = document.createElement('a'); | ||
loginLink.href = contributor.html_url; | ||
loginLink.target = '_blank'; | ||
loginLink.appendChild(avatarImg); | ||
|
||
const loginLink = document.createElement('a'); | ||
loginLink.href = contributor.html_url; | ||
loginLink.target = '_blank'; | ||
loginLink.appendChild(avatarImg); | ||
const displayName = contributor.login; | ||
|
||
// Fetch detailed info for the name | ||
fetch(contributor.url) | ||
.then(contributorDetails => contributorDetails.json()) | ||
.then(contributorData => { | ||
const displayName = contributorData.name || contributor.login; | ||
const nameDiv = document.createElement('div'); | ||
nameDiv.classList.add('contributor-name'); | ||
nameDiv.textContent = displayName; | ||
|
||
const nameDiv = document.createElement('div'); | ||
nameDiv.classList.add('contributor-name'); | ||
nameDiv.textContent = displayName; | ||
const contributionsCountBubbleDiv = document.createElement('div'); | ||
contributionsCountBubbleDiv.classList.add('contributions-count-bubble'); | ||
contributionsCountBubbleDiv.textContent = contributor.contributions; | ||
|
||
contributorCard.appendChild(loginLink); | ||
contributorCard.appendChild(nameDiv); | ||
contributorCard.appendChild(loginLink); | ||
contributorCard.appendChild(nameDiv); | ||
contributorCard.appendChild(contributionsCountBubbleDiv); | ||
fragment.appendChild(contributorCard); | ||
|
||
cont.appendChild(contributorCard); | ||
}) | ||
.catch(error => console.error('Error fetching the contributor details:', error)); | ||
}); | ||
} catch (error) { | ||
console.error('Error fetching the contributors:', error); | ||
// Observe the image for lazy loading | ||
lazyLoadObserver.observe(avatarImg); | ||
} | ||
|
||
cont.appendChild(fragment); | ||
} | ||
|
||
fetchAllContributors(); | ||
// Initial load | ||
fetchContributors(currentPage); |