This commit is contained in:
Chris Cochrun 2025-05-19 14:08:56 -05:00
parent 7a4c5c2d22
commit 2b82345290
663 changed files with 38142 additions and 0 deletions

View file

@ -0,0 +1,101 @@
const sitePreference = document.documentElement.getAttribute("data-default-appearance");
const userPreference = localStorage.getItem("appearance");
if ((sitePreference === "dark" && userPreference === null) || userPreference === "dark") {
document.documentElement.classList.add("dark");
}
if (document.documentElement.getAttribute("data-auto-appearance") === "true") {
if (
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches &&
userPreference !== "light"
) {
document.documentElement.classList.add("dark");
}
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (event) => {
if (event.matches) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
});
}
window.addEventListener("DOMContentLoaded", (event) => {
const switcher = document.getElementById("appearance-switcher");
const switcherMobile = document.getElementById("appearance-switcher-mobile");
updateMeta();
this.updateLogo?.(getTargetAppearance());
if (switcher) {
switcher.addEventListener("click", () => {
document.documentElement.classList.toggle("dark");
var targetAppearance = getTargetAppearance();
localStorage.setItem(
"appearance",
targetAppearance
);
updateMeta();
this.updateLogo?.(targetAppearance);
});
switcher.addEventListener("contextmenu", (event) => {
event.preventDefault();
localStorage.removeItem("appearance");
});
}
if (switcherMobile) {
switcherMobile.addEventListener("click", () => {
document.documentElement.classList.toggle("dark");
var targetAppearance = getTargetAppearance();
localStorage.setItem(
"appearance",
targetAppearance
);
updateMeta();
this.updateLogo?.(targetAppearance);
});
switcherMobile.addEventListener("contextmenu", (event) => {
event.preventDefault();
localStorage.removeItem("appearance");
});
}
});
var updateMeta = () => {
var elem, style;
elem = document.querySelector('body');
style = getComputedStyle(elem);
document.querySelector('meta[name="theme-color"]').setAttribute('content', style.backgroundColor);
}
{{ if and (.Site.Params.Logo) (.Site.Params.SecondaryLogo) }}
{{ $primaryLogo := resources.Get .Site.Params.Logo }}
{{ $secondaryLogo := resources.Get .Site.Params.SecondaryLogo }}
{{ if and ($primaryLogo) ($secondaryLogo) }}
var updateLogo = (targetAppearance) => {
var elems;
elems = document.querySelectorAll("img.logo")
targetLogoPath =
targetAppearance == "{{ .Site.Params.DefaultAppearance }}" ?
"{{ $primaryLogo.RelPermalink }}" : "{{ $secondaryLogo.RelPermalink }}"
for (const elem of elems) {
elem.setAttribute("src", targetLogoPath)
}
}
{{ end }}
{{- end }}
var getTargetAppearance = () => {
return document.documentElement.classList.contains("dark") ? "dark" : "light"
}
window.addEventListener("DOMContentLoaded", (event) => {
const scroller = document.getElementById("top-scroller");
const footer = document.getElementById("site-footer");
if(scroller && footer && scroller.getBoundingClientRect().top > footer.getBoundingClientRect().top) {
scroller.hidden = true;
}
});

View file

@ -0,0 +1,13 @@
function css(name) {
return "rgb(" + getComputedStyle(document.documentElement).getPropertyValue(name) + ")";
}
Chart.defaults.font.size = 14;
Chart.defaults.backgroundColor = css("--color-primary-300");
Chart.defaults.elements.point.borderColor = css("--color-primary-400");
Chart.defaults.elements.bar.borderColor = css("--color-primary-500");
Chart.defaults.elements.bar.borderWidth = 1;
Chart.defaults.elements.line.borderColor = css("--color-primary-400");
Chart.defaults.elements.arc.backgroundColor = css("--color-primary-200");
Chart.defaults.elements.arc.borderColor = css("--color-primary-500");
Chart.defaults.elements.arc.borderWidth = 1;

View file

@ -0,0 +1,66 @@
var scriptBundle = document.getElementById("script-bundle");
var copyText = scriptBundle && scriptBundle.getAttribute("data-copy")? scriptBundle.getAttribute("data-copy") : "Copy";
var copiedText = scriptBundle && scriptBundle.getAttribute("data-copied")? scriptBundle.getAttribute("data-copied") : "Copied";
function createCopyButton(highlightDiv) {
const button = document.createElement("button");
button.className = "copy-button";
button.type = "button";
button.ariaLabel = copyText;
button.innerText = copyText;
button.addEventListener("click", () => copyCodeToClipboard(button, highlightDiv));
addCopyButtonToDom(button, highlightDiv);
}
async function copyCodeToClipboard(button, highlightDiv) {
const codeToCopy = highlightDiv.querySelector(":last-child > .chroma > code").innerText;
try {
result = await navigator.permissions.query({ name: "clipboard-write" });
if (result.state == "granted" || result.state == "prompt") {
await navigator.clipboard.writeText(codeToCopy);
} else {
copyCodeBlockExecCommand(codeToCopy, highlightDiv);
}
} catch (_) {
copyCodeBlockExecCommand(codeToCopy, highlightDiv);
} finally {
codeWasCopied(button);
}
}
function copyCodeBlockExecCommand(codeToCopy, highlightDiv) {
const textArea = document.createElement("textArea");
textArea.contentEditable = "true";
textArea.readOnly = "false";
textArea.className = "copy-textarea";
textArea.value = codeToCopy;
highlightDiv.insertBefore(textArea, highlightDiv.firstChild);
const range = document.createRange();
range.selectNodeContents(textArea);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
textArea.setSelectionRange(0, 999999);
document.execCommand("copy");
highlightDiv.removeChild(textArea);
}
function codeWasCopied(button) {
button.blur();
button.innerText = copiedText;
setTimeout(function () {
button.innerText = copyText;
}, 2000);
}
function addCopyButtonToDom(button, highlightDiv) {
highlightDiv.insertBefore(button, highlightDiv.firstChild);
const wrapper = document.createElement("div");
wrapper.className = "highlight-wrapper";
highlightDiv.parentNode.insertBefore(wrapper, highlightDiv);
wrapper.appendChild(highlightDiv);
}
window.addEventListener("DOMContentLoaded", (event) => {
document.querySelectorAll(".highlight").forEach((highlightDiv) => createCopyButton(highlightDiv));
});

106
themes/bl/assets/js/page.js Normal file
View file

@ -0,0 +1,106 @@
var liked_page = false
if (typeof auth !== 'undefined') {
var id = oid ? oid.replaceAll("/", "-") : oid
var viewed = localStorage.getItem(id);
if (!viewed) {
auth.signInAnonymously()
.then(() => {
var docRef = db.collection('views').doc(id)
localStorage.setItem(id, true);
docRef.get().then((doc) => {
if (doc.exists) {
db.collection('views').doc(id).update({
views: firebase.firestore.FieldValue.increment(1)
});
} else {
db.collection('views').doc(id).set({ views: 1 })
}
}).catch((error) => {
console.log("Error getting document:", error);
});
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
console.error(errorCode, errorMessage)
});
}
var id_likes = oid_likes ? oid_likes.replaceAll("/", "-") : oid_likes
var liked = localStorage.getItem(id_likes);
if (liked) {
liked_page = true
document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = ""
document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = "none"
document.querySelectorAll("span[id='button_likes_text']")[0].innerText = ""
}
}
function like_article(id_likes) {
auth.signInAnonymously()
.then(() => {
var docRef = db.collection('likes').doc(id_likes)
docRef.get().then((doc) => {
liked_page = true
localStorage.setItem(id_likes, true);
document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = ""
document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = "none"
document.querySelectorAll("span[id='button_likes_text']")[0].innerText = ""
if (doc.exists) {
db.collection('likes').doc(id_likes).update({
likes: firebase.firestore.FieldValue.increment(1)
});
} else {
db.collection('likes').doc(id_likes).set({ likes: 1 })
}
}).catch((error) => {
console.log("Error getting document:", error);
});
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
console.error(errorCode, errorMessage)
});
}
function remove_like_article(id_likes) {
auth.signInAnonymously()
.then(() => {
var docRef = db.collection('likes').doc(id_likes)
docRef.get().then((doc) => {
liked_page = false
localStorage.removeItem(id_likes);
document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = "none"
document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = ""
document.querySelectorAll("span[id='button_likes_text']")[0].innerText = "\xa0Like"
if (doc.exists) {
db.collection('likes').doc(id_likes).update({
likes: firebase.firestore.FieldValue.increment(-1)
});
} else {
db.collection('likes').doc(id_likes).set({ likes: 0 })
}
}).catch((error) => {
console.log("Error getting document:", error);
});
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
console.error(errorCode, errorMessage)
});
}
function process_article() {
var id_likes = oid_likes ? oid_likes.replaceAll("/", "-") : oid_likes
if (!liked_page) {
like_article(id_likes)
} else {
remove_like_article(id_likes)
}
}

View file

@ -0,0 +1,71 @@
if (typeof auth !== 'undefined') {
var viewsCollection = db.collection('views');
var likesCollection = db.collection('likes');
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
function toggleLoaders(node){
var classesString = node.className;
if(classesString == "") return
var classes = classesString.split(" ");
for(var i in classes){
node.classList.toggle(classes[i])
}
}
var update_views = function (node, id) {
viewsCollection.doc(id).onSnapshot(doc => {
var data = doc.data();
if (data) {
node.innerText = numberWithCommas(data.views)
} else {
node.innerText = 0
}
toggleLoaders(node)
})
}
var update_likes = function (node, id) {
likesCollection.doc(id).onSnapshot(doc => {
var data = doc.data();
if (data) {
node.innerText = numberWithCommas(data.likes)
} else {
node.innerText = 0
}
toggleLoaders(node)
})
}
auth.signInAnonymously()
.then(() => {
var views_nodes = document.querySelectorAll("span[id^='views_']")
for (var i in views_nodes) {
var node = views_nodes[i]
var id = node.id ? node.id.replaceAll("/", "-") : node.id
if (id) {
update_views(node, id)
}
}
var likes_nodes = document.querySelectorAll("span[id^='likes_']")
for (var i in likes_nodes) {
var node = likes_nodes[i]
var id = node.id ? node.id.replaceAll("/", "-") : node.id
if (id) {
update_likes(node, id)
}
}
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
console.error(errorCode, errorMessage)
});
}

View file

@ -0,0 +1,3 @@
window.addEventListener("DOMContentLoaded", (event) => {
document.querySelectorAll("pre, .highlight-wrapper").forEach((tag) => (tag.dir = "auto"));
});

View file

@ -0,0 +1,177 @@
var fuse;
var showButton = document.getElementById("search-button");
var showButtonMobile = document.getElementById("search-button-mobile");
var hideButton = document.getElementById("close-search-button");
var wrapper = document.getElementById("search-wrapper");
var modal = document.getElementById("search-modal");
var input = document.getElementById("search-query");
var output = document.getElementById("search-results");
var first = output.firstChild;
var last = output.lastChild;
var searchVisible = false;
var indexed = false;
var hasResults = false;
// Listen for events
showButton? showButton.addEventListener("click", displaySearch) : null;
showButtonMobile? showButtonMobile.addEventListener("click", displaySearch) : null;
hideButton.addEventListener("click", hideSearch);
wrapper.addEventListener("click", hideSearch);
modal.addEventListener("click", function (event) {
event.stopPropagation();
event.stopImmediatePropagation();
return false;
});
document.addEventListener("keydown", function (event) {
// Forward slash to open search wrapper
if (event.key == "/") {
if (!searchVisible) {
event.preventDefault();
displaySearch();
}
}
// Esc to close search wrapper
if (event.key == "Escape") {
hideSearch();
}
// Down arrow to move down results list
if (event.key == "ArrowDown") {
if (searchVisible && hasResults) {
event.preventDefault();
if (document.activeElement == input) {
first.focus();
} else if (document.activeElement == last) {
last.focus();
} else {
document.activeElement.parentElement.nextSibling.firstElementChild.focus();
}
}
}
// Up arrow to move up results list
if (event.key == "ArrowUp") {
if (searchVisible && hasResults) {
event.preventDefault();
if (document.activeElement == input) {
input.focus();
} else if (document.activeElement == first) {
input.focus();
} else {
document.activeElement.parentElement.previousSibling.firstElementChild.focus();
}
}
}
// Enter to get to results
if (event.key == "Enter") {
if (searchVisible && hasResults) {
event.preventDefault();
if (document.activeElement == input) {
first.focus();
} else {
document.activeElement.click();
}
}else{
event.preventDefault();
}
}
});
// Update search on each keypress
input.onkeyup = function (event) {
executeQuery(this.value);
};
function displaySearch() {
if (!indexed) {
buildIndex();
}
if (!searchVisible) {
document.body.style.overflow = "hidden";
wrapper.style.visibility = "visible";
input.focus();
searchVisible = true;
}
}
function hideSearch() {
if (searchVisible) {
document.body.style.overflow = "visible";
wrapper.style.visibility = "hidden";
input.value = "";
output.innerHTML = "";
document.activeElement.blur();
searchVisible = false;
}
}
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 = wrapper.getAttribute("data-url");
baseURL = baseURL.replace(/\/?$/, '/');
fetchJSON(baseURL + "index.json", function (data) {
var options = {
shouldSort: true,
ignoreLocation: true,
threshold: 0.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);
indexed = true;
});
}
function executeQuery(term) {
let results = fuse.search(term);
let resultsHTML = "";
if (results.length > 0) {
results.forEach(function (value, key) {
resultsHTML =
resultsHTML +
`<li class="mb-2">
<a class="flex items-center px-3 py-2 rounded-md appearance-none bg-neutral-100 dark:bg-neutral-700 focus:bg-primary-100 hover:bg-primary-100 dark:hover:bg-primary-900 dark:focus:bg-primary-900 focus:outline-dotted focus:outline-transparent focus:outline-2" href="${value.item.permalink}" tabindex="0">
<div class="grow">
<div class="-mb-1 text-lg font-bold">${value.item.title}</div>
<div class="text-sm text-neutral-500 dark:text-neutral-400">${value.item.section}<span class="px-2 text-primary-500">&middot;</span>${value.item.date}</span></div>
<div class="text-sm italic">${value.item.summary}</div>
</div>
<div class="ml-2 ltr:block rtl:hidden text-neutral-500">&rarr;</div>
<div class="mr-2 ltr:hidden rtl:block text-neutral-500">&larr;</div>
</a>
</li>`;
});
hasResults = true;
} else {
resultsHTML = "";
hasResults = false;
}
output.innerHTML = resultsHTML;
if (results.length > 0) {
first = output.firstChild.firstElementChild;
last = output.lastChild.firstElementChild;
}
}