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