From 41f83aebac1a45ab269afc25b7391f10ca7546a7 Mon Sep 17 00:00:00 2001 From: Lakshan Tharaka Date: Thu, 17 Jul 2025 14:01:49 +0530 Subject: [PATCH] add GitHub token authentication and UI for private repos --- index.html | 136 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 125 insertions(+), 11 deletions(-) diff --git a/index.html b/index.html index 4343ff1..3a14c3e 100644 --- a/index.html +++ b/index.html @@ -27,14 +27,14 @@ } #repo { position: fixed; - top: 170px; + top: 220px; } #menu { position: fixed; top: 0px; left: 0px; right: 0px; - height: 170px; + height: 220px; margin-bottom: 20px; margin-left: 20px; margin-left: auto; @@ -69,6 +69,15 @@ background-color: #fff; filter: drop-shadow( 0px 2px 2px rgba(150, 150, 150, 0.2)); } + #tokenInput { + font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + padding: 5px 7px; + border: 1px solid #bbb; + outline: none; + background-color: #fff; + filter: drop-shadow( 0px 1px 1px rgba(150, 150, 150, 0.2)); + border-radius: 2px; + } #repoButton { display: inline-block; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; @@ -132,6 +141,20 @@ color: black; font-size: 0.8em; } + #saveToken, #clearToken { + font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + cursor: pointer; + background-color: #bbb; + border: 0px; + filter: drop-shadow( 0px 1px 1px rgba(150, 150, 150, 0.2)); + border-radius: 2px; + } + #saveToken:hover, #clearToken:hover { + background-color: #999; + } + #auth-toggle:hover { + text-decoration: underline; + } a { color: #444; } @@ -144,6 +167,17 @@

repofiles

+
+
+
+ 🔒 Add GitHub token for private repos +
+
@@ -168,32 +202,83 @@

repofiles

document.getElementById('status').textContent = text; } +function getGitHubToken() { + return localStorage.getItem('github-token'); +} + +function setGitHubToken(token) { + if (token && token.trim()) { + localStorage.setItem('github-token', token.trim()); + updateTokenStatus(); + } +} + +function clearGitHubToken() { + localStorage.removeItem('github-token'); + updateTokenStatus(); +} + +function updateTokenStatus() { + const token = getGitHubToken(); + const statusDiv = document.getElementById('token-status'); + if (token) { + statusDiv.textContent = '✓ Token saved (can access private repos)'; + statusDiv.style.color = 'green'; + } else { + statusDiv.textContent = 'No token (public repos only)'; + statusDiv.style.color = '#666'; + } +} + async function fetchGitHub(url, after) { + const token = getGitHubToken(); + const headers = { + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28" + }; + + if (token) { + headers["Authorization"] = `Bearer ${token}`; + } + const options = { method: "GET", - headers: { - "Accept": "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28" - } + headers: headers }; try { const response = await fetch(url, options); if (!response.ok) { + if (response.status === 401) { + setStatus('Authentication failed. Check your GitHub token.'); + return; + } else if (response.status === 403) { + setStatus('Access forbidden. Token may lack necessary permissions.'); + return; + } else if (response.status === 404) { + setStatus('Repository not found. Check the URL or ensure you have access.'); + return; + } throw new Error(`HTTP error! Status: ${response.status}`); } const data = await response.json(); if ('message' in data) { if (data.message && data.message.startsWith('API rate limit exceeded')) { - setStatus('GitHub API rate limit exceeded. Wait, or try from another device.', ); + setStatus('GitHub API rate limit exceeded. Wait, or try from another device.'); + } else if (data.message && data.message.includes('Bad credentials')) { + setStatus('Invalid GitHub token. Please check your token.'); } else { - setStatus('An unknown error occurred. You can @BenjDicken on twitter.'); + setStatus(`GitHub API error: ${data.message}`); } } else { after(data); } } catch (error) { - console.error("Error fetching the latest commit:", error); - setStatus('An unknown error occurred. You can @BenjDicken on twitter.'); + console.error("Error fetching from GitHub:", error); + if (error.message.includes('Failed to fetch')) { + setStatus('Network error. Check your internet connection.'); + } else { + setStatus('An unknown error occurred. You can @BenjDicken on twitter.'); + } } } @@ -256,7 +341,7 @@

repofiles

function draw(data) { let width = window.innerWidth; - let height = window.innerHeight - 170; + let height = window.innerHeight - 220; let wh = Math.min(width, height); const svg = d3.select("#repo") .append("svg") @@ -430,6 +515,35 @@

repofiles

} }); +// Authentication UI event listeners +document.getElementById('auth-toggle').addEventListener('click', function() { + const authInputs = document.getElementById('auth-inputs'); + const isVisible = authInputs.style.display === 'block'; + authInputs.style.display = isVisible ? 'none' : 'block'; + this.textContent = isVisible ? '🔒 Add GitHub token for private repos' : '🔒 Hide GitHub token settings'; +}); + +document.getElementById('saveToken').addEventListener('click', function() { + const token = document.getElementById('tokenInput').value; + setGitHubToken(token); + document.getElementById('tokenInput').value = ''; +}); + +document.getElementById('clearToken').addEventListener('click', function() { + clearGitHubToken(); +}); + +document.getElementById('tokenInput').addEventListener('keydown', function(event) { + if (event.key === "Enter") { + const token = this.value; + setGitHubToken(token); + this.value = ''; + } +}); + +// Initialize token status on page load +updateTokenStatus(); + if (!getRepoInfoFromURL()) { // If no repo specified in URL, // Initially just load the json file from the server for neovim