mirror of
https://github.com/asimonson1125/asimonson1125.github.io.git
synced 2026-09-22 11:35:33 -05:00
feat: implement SPA loading bar, harden status page logic, and optimize Dockerfile
This commit is contained in:
@@ -14,50 +14,81 @@ function toggleMenu(collapse) {
|
||||
}
|
||||
|
||||
async function goto(location, { push = true } = {}) {
|
||||
let response;
|
||||
const loadingBar = document.getElementById('loading-bar');
|
||||
console.log(`Navigating to ${location}`);
|
||||
|
||||
if (loadingBar) {
|
||||
loadingBar.style.width = ''; // Clear inline style from previous run
|
||||
}
|
||||
|
||||
let loadingTimeout = setTimeout(() => {
|
||||
if (loadingBar) {
|
||||
console.log("Navigation taking > 150ms, showing bar");
|
||||
loadingBar.classList.remove('finish');
|
||||
loadingBar.classList.add('active');
|
||||
loadingBar.classList.add('visible');
|
||||
}
|
||||
}, 150);
|
||||
|
||||
try {
|
||||
response = await fetch("/api/goto/" + location, {
|
||||
const response = await fetch("/api/goto/" + location, {
|
||||
credentials: "include",
|
||||
method: "GET",
|
||||
mode: "cors",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`Navigation failed: HTTP ${response.status}`);
|
||||
return;
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Navigation fetch failed:", err);
|
||||
return;
|
||||
}
|
||||
|
||||
document.dispatchEvent(new Event('beforenavigate'));
|
||||
// Wait for the full body to download - this is usually the slow part
|
||||
const [metadata, content] = await response.json();
|
||||
|
||||
document.dispatchEvent(new Event('beforenavigate'));
|
||||
|
||||
const [metadata, content] = await response.json();
|
||||
const root = document.getElementById("root");
|
||||
root.innerHTML = content;
|
||||
const root = document.getElementById("root");
|
||||
root.innerHTML = content;
|
||||
|
||||
// Re-execute scripts injected via innerHTML (browser ignores them otherwise)
|
||||
root.querySelectorAll("script").forEach(function(oldScript) {
|
||||
const newScript = document.createElement("script");
|
||||
Array.from(oldScript.attributes).forEach(function(attr) {
|
||||
newScript.setAttribute(attr.name, attr.value);
|
||||
// Re-execute scripts
|
||||
root.querySelectorAll("script").forEach(function(oldScript) {
|
||||
const newScript = document.createElement("script");
|
||||
Array.from(oldScript.attributes).forEach(function(attr) {
|
||||
newScript.setAttribute(attr.name, attr.value);
|
||||
});
|
||||
newScript.textContent = oldScript.textContent;
|
||||
oldScript.parentNode.replaceChild(newScript, oldScript);
|
||||
});
|
||||
newScript.textContent = oldScript.textContent;
|
||||
oldScript.parentNode.replaceChild(newScript, oldScript);
|
||||
});
|
||||
|
||||
if (window.location.href.includes("#")) {
|
||||
const id = decodeURIComponent(window.location.hash.substring(1));
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.scrollIntoView();
|
||||
} else {
|
||||
window.scrollTo({ top: 0, left: 0, behavior: "instant" });
|
||||
}
|
||||
if (window.location.href.includes("#")) {
|
||||
const id = decodeURIComponent(window.location.hash.substring(1));
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.scrollIntoView();
|
||||
} else {
|
||||
window.scrollTo({ top: 0, left: 0, behavior: "instant" });
|
||||
}
|
||||
|
||||
toggleMenu(true);
|
||||
document.querySelector("title").textContent = metadata["title"];
|
||||
if (push) {
|
||||
history.pushState(null, null, metadata["canonical"]);
|
||||
toggleMenu(true);
|
||||
document.querySelector("title").textContent = metadata["title"];
|
||||
if (push) {
|
||||
history.pushState(null, null, metadata["canonical"]);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error("Navigation failed:", err);
|
||||
} finally {
|
||||
clearTimeout(loadingTimeout);
|
||||
if (loadingBar && loadingBar.classList.contains('active')) {
|
||||
console.log("Navigation finished, hiding bar");
|
||||
loadingBar.classList.add('finish');
|
||||
loadingBar.classList.remove('active');
|
||||
setTimeout(() => {
|
||||
if (!loadingBar.classList.contains('active')) {
|
||||
loadingBar.style.width = '0%';
|
||||
loadingBar.classList.remove('finish');
|
||||
loadingBar.classList.remove('visible');
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user