Skip to content

Commit 52aec87

Browse files
fix
1 parent 4c7d52e commit 52aec87

2 files changed

Lines changed: 284 additions & 162 deletions

File tree

contributors.html

Lines changed: 133 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,13 @@ <h1 class="contributors-title">Meet Our <span>Contributors</span></h1>
729729
</div>
730730
</div>
731731

732+
<!-- Token Settings Button -->
733+
<div style="text-align: center; margin: 20px 0;">
734+
<button id="tokenSettingsBtn" style="padding: 10px 20px; background: var(--primary); color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 0.9rem;">
735+
<i class="fas fa-key"></i> GitHub Token Settings
736+
</button>
737+
</div>
738+
732739
<!-- Search Section -->
733740
<div class="search-section">
734741
<div class="search-container">
@@ -798,6 +805,54 @@ <h4>Connect With Us</h4>
798805
</div>
799806
</footer>
800807

808+
<!-- Token Settings Modal -->
809+
<div id="tokenModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 10000; align-items: center; justify-content: center;">
810+
<div style="background: white; padding: 30px; border-radius: 12px; max-width: 600px; width: 90%; max-height: 90vh; overflow-y: auto;">
811+
<h2 style="margin-top: 0; color: var(--primary);">GitHub Token Settings</h2>
812+
<p style="color: var(--text-light); margin-bottom: 20px;">
813+
Add a GitHub Personal Access Token to increase API rate limits from 60/hour to 5,000/hour.
814+
</p>
815+
816+
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 20px;">
817+
<h3 style="font-size: 1rem; margin-top: 0;">How to get a GitHub Token:</h3>
818+
<ol style="margin: 10px 0; padding-left: 20px; color: var(--text-light);">
819+
<li>Go to <a href="https://github.com/settings/tokens" target="_blank" style="color: var(--primary);">GitHub Settings → Developer settings → Personal access tokens</a></li>
820+
<li>Click "Generate new token (classic)"</li>
821+
<li>Give it a name (e.g., "AnimateItNow")</li>
822+
<li>Select expiration (or "No expiration")</li>
823+
<li>Check <strong>public_repo</strong> scope (read-only access)</li>
824+
<li>Click "Generate token" and copy it</li>
825+
<li>Paste it below</li>
826+
</ol>
827+
</div>
828+
829+
<div style="margin-bottom: 20px;">
830+
<label style="display: block; margin-bottom: 8px; font-weight: 600;">GitHub Personal Access Token:</label>
831+
<input
832+
type="password"
833+
id="githubTokenInput"
834+
placeholder="ghp_xxxxxxxxxxxxxxxxxxxx"
835+
style="width: 100%; padding: 12px; border: 2px solid var(--border); border-radius: 8px; font-size: 0.9rem; box-sizing: border-box;"
836+
/>
837+
<small style="color: var(--text-light); display: block; margin-top: 5px;">
838+
Token is stored locally in your browser and never sent to our servers.
839+
</small>
840+
</div>
841+
842+
<div style="display: flex; gap: 10px; justify-content: flex-end;">
843+
<button id="tokenCancelBtn" style="padding: 10px 20px; background: #e9ecef; color: var(--text); border: none; border-radius: 8px; cursor: pointer;">
844+
Cancel
845+
</button>
846+
<button id="tokenSaveBtn" style="padding: 10px 20px; background: var(--primary); color: white; border: none; border-radius: 8px; cursor: pointer;">
847+
Save Token
848+
</button>
849+
<button id="tokenRemoveBtn" style="padding: 10px 20px; background: #dc3545; color: white; border: none; border-radius: 8px; cursor: pointer;">
850+
Remove Token
851+
</button>
852+
</div>
853+
</div>
854+
</div>
855+
801856
<!-- Scroll to top button -->
802857
<button onclick="scrollToTop()" id="scrollBtn" title="Go to top"></button>
803858

@@ -809,24 +864,83 @@ <h4>Connect With Us</h4>
809864
let contributorsData = [];
810865
let filteredContributors = [];
811866

812-
// GitHub API headers with hardcoded token
813-
// IMPORTANT: Make sure this token has 'public_repo' scope and hasn't been revoked
814-
const GITHUB_TOKEN = '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'.trim();
815-
816-
function getApiHeaders() {
817-
// Validate token format
818-
if (!GITHUB_TOKEN || GITHUB_TOKEN.length < 10) {
819-
console.error('❌ Invalid token format');
820-
throw new Error('GitHub token is missing or invalid');
867+
// GitHub Token Management
868+
function getGitHubToken() {
869+
return localStorage.getItem('github_token') || null;
870+
}
871+
872+
function setGitHubToken(token) {
873+
if (token && token.trim()) {
874+
localStorage.setItem('github_token', token.trim());
875+
} else {
876+
localStorage.removeItem('github_token');
821877
}
822-
823-
return {
878+
}
879+
880+
function getApiHeaders() {
881+
const headers = {
824882
'Accept': 'application/vnd.github.v3+json',
825-
'User-Agent': 'AnimateItNow-Contributors',
826-
// Classic tokens use 'token' prefix (not 'Bearer')
827-
'Authorization': `token ${GITHUB_TOKEN}`
883+
'User-Agent': 'AnimateItNow-Contributors'
828884
};
829-
}
885+
const token = getGitHubToken();
886+
if (token) {
887+
headers['Authorization'] = `token ${token}`;
888+
}
889+
return headers;
890+
}
891+
892+
// Token Modal Management
893+
const tokenModal = document.getElementById('tokenModal');
894+
const tokenSettingsBtn = document.getElementById('tokenSettingsBtn');
895+
const tokenSaveBtn = document.getElementById('tokenSaveBtn');
896+
const tokenCancelBtn = document.getElementById('tokenCancelBtn');
897+
const tokenRemoveBtn = document.getElementById('tokenRemoveBtn');
898+
const tokenInput = document.getElementById('githubTokenInput');
899+
900+
// Load existing token
901+
const existingToken = getGitHubToken();
902+
if (existingToken) {
903+
tokenInput.value = existingToken;
904+
}
905+
906+
tokenSettingsBtn.addEventListener('click', () => {
907+
tokenModal.style.display = 'flex';
908+
});
909+
910+
tokenCancelBtn.addEventListener('click', () => {
911+
tokenModal.style.display = 'none';
912+
tokenInput.value = existingToken || '';
913+
});
914+
915+
tokenSaveBtn.addEventListener('click', () => {
916+
const token = tokenInput.value.trim();
917+
if (token) {
918+
setGitHubToken(token);
919+
alert('Token saved! Refreshing page...');
920+
location.reload();
921+
} else {
922+
alert('Please enter a valid token');
923+
}
924+
});
925+
926+
tokenRemoveBtn.addEventListener('click', () => {
927+
if (confirm('Are you sure you want to remove the token?')) {
928+
setGitHubToken('');
929+
tokenInput.value = '';
930+
alert('Token removed! Refreshing page...');
931+
location.reload();
932+
}
933+
});
934+
935+
// Close modal on outside click
936+
tokenModal.addEventListener('click', (e) => {
937+
if (e.target === tokenModal) {
938+
tokenModal.style.display = 'none';
939+
tokenInput.value = existingToken || '';
940+
}
941+
});
942+
943+
// Note: Use getApiHeaders() function instead of apiHeaders constant
830944

831945
// Fetch all pages of contributors
832946
async function fetchAllContributors() {
@@ -837,34 +951,12 @@ <h4>Connect With Us</h4>
837951
while (true) {
838952
try {
839953
const url = `https://api.github.com/repos/${owner}/${repo}/contributors?per_page=${perPage}&page=${page}`;
840-
const headers = getApiHeaders();
841-
842-
// Debug: Log request details (remove token from log)
843-
console.log(`Fetching contributors page ${page}`);
844-
console.log('Headers:', { ...headers, Authorization: 'token ***' });
845-
846-
const response = await fetch(url, {
847-
method: 'GET',
848-
headers: headers,
849-
mode: 'cors',
850-
cache: 'no-cache'
851-
});
954+
const response = await fetch(url, { headers: getApiHeaders() });
852955

853956
// Check rate limit
854957
const remaining = response.headers.get('X-RateLimit-Remaining');
855958
const resetTime = response.headers.get('X-RateLimit-Reset');
856959

857-
if (response.status === 401) {
858-
const errorData = await response.json().catch(() => ({}));
859-
console.error('401 Error Details:', errorData);
860-
console.error('Response Headers:', {
861-
'X-RateLimit-Remaining': remaining,
862-
'X-RateLimit-Reset': resetTime,
863-
'X-GitHub-Media-Type': response.headers.get('X-GitHub-Media-Type')
864-
});
865-
throw new Error(`GitHub API authentication failed (401). ${errorData.message || 'Bad credentials. Token may be invalid, expired, or missing required scopes.'}`);
866-
}
867-
868960
if (response.status === 403) {
869961
if (resetTime) {
870962
const resetDate = new Date(parseInt(resetTime) * 1000);
@@ -874,8 +966,7 @@ <h4>Connect With Us</h4>
874966
}
875967

876968
if (!response.ok) {
877-
const errorData = await response.json().catch(() => ({}));
878-
throw new Error(`GitHub API error! Status: ${response.status}. ${errorData.message || ''}`);
969+
throw new Error(`GitHub API error! Status: ${response.status}`);
879970
}
880971

881972
const contributors = await response.json();
@@ -920,7 +1011,8 @@ <h4>Connect With Us</h4>
9201011
}
9211012

9221013
try {
923-
console.log("🔄 Fetching contributors with token...");
1014+
const token = getGitHubToken();
1015+
console.log(token ? "🔄 Fetching contributors with token..." : "🔄 Fetching contributors (unauthenticated - limited to 60/hour)...");
9241016
const contributors = await fetchAllContributors();
9251017

9261018
if (!Array.isArray(contributors) || contributors.length === 0) {

0 commit comments

Comments
 (0)