This commit is contained in:
Grant
2025-03-16 11:20:59 -06:00
commit b6d8497df5
49 changed files with 3376 additions and 0 deletions

47
public/js/codecopy.js Normal file
View File

@@ -0,0 +1,47 @@
(() => {
// <stdin>
var copyText = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M288 448L64 448l0-224 64 0 0-64-64 0c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l224 0c35.3 0 64-28.7 64-64l0-64-64 0 0 64zm-64-96l224 0c35.3 0 64-28.7 64-64l0-224c0-35.3-28.7-64-64-64L224 0c-35.3 0-64 28.7-64 64l0 224c0 35.3 28.7 64 64 64z"/></svg>';
var copiedText = 'Copied! <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64L64 32zM337 209L209 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L303 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/></svg>';
function createCopyButton(codeblock) {
const container = codeblock.parentNode.parentNode;
const copybutton = document.createElement("button");
copybutton.classList.add("copy-button");
copybutton.innerHTML = copyText;
function copyingDone() {
copybutton.innerHTML = copiedText;
setTimeout(() => {
copybutton.innerHTML = copyText;
}, 500);
}
copybutton.addEventListener("click", (cb) => {
if ("clipboard" in navigator) {
navigator.clipboard.writeText(codeblock.textContent);
copyingDone();
return;
}
const range = document.createRange();
range.selectNodeContents(codeblock);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
try {
document.execCommand("copy");
copyingDone();
} catch (e) {
}
;
selection.removeRange(range);
});
if (container.classList.contains("highlight")) {
container.appendChild(copybutton);
} else if (container.parentNode.firstChild == container) {
} else if (codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName == "TABLE") {
codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(copybutton);
} else {
codeblock.parentNode.appendChild(copybutton);
}
}
window.addEventListener("DOMContentLoaded", (event) => {
document.querySelectorAll("pre > code").forEach((codeblock) => createCopyButton(codeblock));
});
})();

134
public/js/search.js Normal file
View File

@@ -0,0 +1,134 @@
(() => {
// <stdin>
var seachOpnBtn = null;
var closeBtn = null;
var searchCntr = null;
var resultCntr = null;
var searchBtn = null;
var searchTxt = null;
var isSearchOpen = false;
var isJsonIndexed = false;
var isResEmpty = true;
var fuse;
function fetchJSON(path, callback) {
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
var data = JSON.parse(httpRequest.responseText);
if (callback) callback(data);
}
}
};
httpRequest.open("GET", path);
httpRequest.send();
}
function buildIndex() {
var baseURL = searchCntr.getAttribute("data-url");
baseURL = baseURL.replace(/\/?$/, "/");
fetchJSON(baseURL + "index.json", function(data) {
var options = {
shouldSort: true,
ignoreLocation: true,
threshold: 0,
includeMatches: true,
keys: [
{ name: "title", weight: 0.8 },
{ name: "section", weight: 0.2 },
{ name: "summary", weight: 0.6 },
{ name: "content", weight: 0.4 }
]
};
fuse = new Fuse(data, options);
isJsonIndexed = true;
});
}
function openSearch() {
if (!isJsonIndexed) {
buildIndex();
}
if (!isSearchOpen) {
searchCntr.style.display = "flex";
document.body.style.overflow = "hidden";
isSearchOpen = true;
searchTxt.focus();
}
}
function closeSearch() {
if (isSearchOpen) {
searchCntr.style.display = "none";
document.body.style.overflow = "";
isSearchOpen = false;
}
}
function executeQuery(query) {
let results = fuse.search(query);
let resultsHtml = "";
if (results.length > 1) {
results.forEach(function(value, key) {
var meta = value.item.section + " | ";
meta = meta + value.item.date ? value.item.date + " | " : "";
meta = meta + `<span class="srch-link">${value.item.permalink}</span>`;
resultsHtml = resultsHtml + `<li><a href="${value.item.permalink}">
<p class="srch-title">${value.item.title}</p>
<p class="srch-meta">${meta}</p>
<p class="srch-smry">${value.item.summary}</p>
</a></li>`;
});
isResEmpty = false;
} else {
resultsHtml = "";
isResEmpty = true;
}
resultCntr.innerHTML = resultsHtml;
}
window.addEventListener("DOMContentLoaded", (event) => {
seachOpnBtn = document.getElementById("search-open");
searchBtn = document.getElementById("search-btn");
closeBtn = document.getElementById("search-close");
searchCntr = document.getElementById("search-container");
resultCntr = document.getElementById("search-results");
searchTxt = document.getElementById("search-query");
seachOpnBtn.addEventListener("click", openSearch);
closeBtn.addEventListener("click", closeSearch);
searchTxt.onkeyup = function(event2) {
executeQuery(this.value);
};
searchTxt.onkeydown = function(event2) {
if (event2.key == "Enter" && !isResEmpty) {
resultCntr.firstChild.firstElementChild.focus();
event2.preventDefault();
}
};
});
document.addEventListener("keydown", function(event) {
if (event.key == "/") {
event.preventDefault();
openSearch();
}
if (isSearchOpen) {
if (event.key == "Escape") {
event.preventDefault();
closeSearch();
} else if (event.key == "ArrowDown" && !isResEmpty) {
if (document.activeElement == searchTxt) {
resultCntr.firstChild.firstElementChild.focus();
} else if (document.activeElement == resultCntr.lastChild.firstElementChild) {
searchTxt.focus();
} else {
document.activeElement.parentElement.nextSibling.firstElementChild.focus();
}
event.preventDefault();
} else if (event.key == "ArrowUp" && !isResEmpty) {
if (document.activeElement == searchTxt) {
resultCntr.lastChild.firstElementChild.focus();
} else if (document.activeElement == resultCntr.firstChild.firstElementChild) {
searchTxt.focus();
} else {
document.activeElement.parentElement.previousSibling.firstElementChild.focus();
}
event.preventDefault();
}
}
});
})();

25
public/js/theme.js Normal file
View File

@@ -0,0 +1,25 @@
(() => {
// <stdin>
function toggleTheme() {
if (document.body.className.includes("dark")) {
document.body.classList.remove("dark");
localStorage.setItem("theme", "light");
} else {
document.body.classList.add("dark");
localStorage.setItem("theme", "dark");
}
}
window.addEventListener("DOMContentLoaded", (event) => {
const switcher = document.getElementById("theme-switcher");
if (switcher) {
switcher.addEventListener("click", () => {
toggleTheme();
});
}
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (event2) => {
if (event2.matches && localStorage.getItem("theme") === "light") {
toggleTheme();
}
});
});
})();