refactor
This commit is contained in:
parent
846bce9480
commit
60aea94006
32 changed files with 328 additions and 278 deletions
|
|
@ -4,12 +4,25 @@
|
|||
|
||||
const TERMINAL_PROMPT = "barrett@ruth:~$ ";
|
||||
let typing = false;
|
||||
let clearing = false;
|
||||
|
||||
function promptEl() {
|
||||
return document.querySelector(".terminal-prompt");
|
||||
}
|
||||
|
||||
function promptTail() {
|
||||
const el = promptEl();
|
||||
if (!el) return "";
|
||||
const s = el.textContent || "";
|
||||
return s.startsWith(TERMINAL_PROMPT) ? s.slice(TERMINAL_PROMPT.length) : s;
|
||||
}
|
||||
function setPromptTailImmediate(tail) {
|
||||
const el = promptEl();
|
||||
if (!el) return;
|
||||
el.textContent = TERMINAL_PROMPT + tail;
|
||||
}
|
||||
function persistPrompt() {
|
||||
const el = promptEl();
|
||||
if (el) sessionStorage.setItem("terminalPromptText", el.textContent);
|
||||
}
|
||||
(function restorePrompt() {
|
||||
const saved = sessionStorage.getItem("terminalPromptText");
|
||||
const el = promptEl();
|
||||
|
|
@ -17,52 +30,80 @@
|
|||
sessionStorage.removeItem("terminalPromptText");
|
||||
})();
|
||||
|
||||
function clearPrompt(delay, callback) {
|
||||
if (clearing) return;
|
||||
clearing = true;
|
||||
const el = promptEl();
|
||||
if (!el) {
|
||||
clearing = false;
|
||||
function normalizeDisplayPath(pathname) {
|
||||
let p = pathname.replace(/\/index\.html$/, "/").replace(/\.html$/, "");
|
||||
p = p.replace(/\/{2,}/g, "/");
|
||||
if (p !== "/" && p.endsWith("/")) p = p.slice(0, -1);
|
||||
return p === "/" ? "" : p;
|
||||
}
|
||||
function displayPathFromHref(href) {
|
||||
const url = new URL(href, location.origin);
|
||||
return normalizeDisplayPath(url.pathname);
|
||||
}
|
||||
function currentDisplayPath() {
|
||||
return normalizeDisplayPath(location.pathname);
|
||||
}
|
||||
function setDocTitleForPath(displayPath) {
|
||||
if (!displayPath) {
|
||||
document.title = "Barrett Ruth";
|
||||
return;
|
||||
}
|
||||
const excess = el.textContent.length - TERMINAL_PROMPT.length;
|
||||
let i = 0;
|
||||
function tick() {
|
||||
if (i++ < excess) {
|
||||
el.textContent = el.textContent.slice(0, -1);
|
||||
setTimeout(tick, delay / Math.max(excess, 1));
|
||||
} else {
|
||||
clearing = false;
|
||||
callback && callback();
|
||||
}
|
||||
}
|
||||
tick();
|
||||
document.title = displayPath.slice(1);
|
||||
}
|
||||
|
||||
function typeTerminalPath(topic, delay, callback) {
|
||||
function animateToDisplayPath(displayPath, totalMs, done) {
|
||||
if (typing) return;
|
||||
typing = true;
|
||||
const el = promptEl();
|
||||
if (!el) return;
|
||||
const txt = ` /${topic}`;
|
||||
clearPrompt(delay, () => {
|
||||
let i = 0;
|
||||
function step() {
|
||||
if (i < txt.length) {
|
||||
el.textContent += txt.charAt(i++);
|
||||
setTimeout(step, delay / txt.length);
|
||||
} else {
|
||||
typing = false;
|
||||
callback && callback();
|
||||
}
|
||||
}
|
||||
step();
|
||||
});
|
||||
}
|
||||
|
||||
function persistPrompt() {
|
||||
const el = promptEl();
|
||||
if (el) sessionStorage.setItem("terminalPromptText", el.textContent);
|
||||
if (!el) {
|
||||
typing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const targetTail = displayPath ? " " + displayPath : "";
|
||||
const curTail = promptTail();
|
||||
|
||||
let i = 0;
|
||||
const max = Math.min(curTail.length, targetTail.length);
|
||||
while (i < max && curTail.charAt(i) === targetTail.charAt(i)) i++;
|
||||
|
||||
const delSteps = curTail.length - i;
|
||||
const typeSteps = targetTail.length - i;
|
||||
const totalSteps = delSteps + typeSteps;
|
||||
|
||||
if (totalSteps === 0) {
|
||||
typing = false;
|
||||
done && done();
|
||||
return;
|
||||
}
|
||||
|
||||
const stepMs = totalMs / totalSteps;
|
||||
|
||||
let delCount = 0;
|
||||
function tickDelete() {
|
||||
if (delCount < delSteps) {
|
||||
setPromptTailImmediate(curTail.slice(0, curTail.length - delCount - 1));
|
||||
delCount++;
|
||||
setTimeout(tickDelete, stepMs);
|
||||
} else {
|
||||
let j = 0;
|
||||
function tickType() {
|
||||
if (j < typeSteps) {
|
||||
setPromptTailImmediate(
|
||||
curTail.slice(0, i) + targetTail.slice(i, i + j + 1),
|
||||
);
|
||||
j++;
|
||||
setTimeout(tickType, stepMs);
|
||||
} else {
|
||||
typing = false;
|
||||
done && done();
|
||||
}
|
||||
}
|
||||
tickType();
|
||||
}
|
||||
}
|
||||
tickDelete();
|
||||
}
|
||||
|
||||
function renderPosts(topic) {
|
||||
|
|
@ -76,11 +117,13 @@
|
|||
const div = document.createElement("div");
|
||||
div.className = "post";
|
||||
const a = document.createElement("a");
|
||||
const slug = post.id
|
||||
.split("/")
|
||||
.pop()
|
||||
.replace(/\.mdx?$/, "");
|
||||
a.href = `/posts/${topic}/${slug}.html`;
|
||||
const slug =
|
||||
post.slug ||
|
||||
post.id
|
||||
?.split("/")
|
||||
.pop()
|
||||
?.replace(/\.mdx?$/, "");
|
||||
a.href = `/${topic}/${slug}.html`;
|
||||
a.textContent = post.data.title;
|
||||
a.style.textDecoration = "underline";
|
||||
div.appendChild(a);
|
||||
|
|
@ -94,14 +137,14 @@
|
|||
e.preventDefault();
|
||||
if (typing) return;
|
||||
|
||||
const topic = link.dataset.topic.toLowerCase();
|
||||
const path = window.location.pathname;
|
||||
const isHome = path === "/" || path === "/index.html";
|
||||
const topic = link.dataset.topic?.toLowerCase() || "";
|
||||
const href = link.getAttribute("href") || "/";
|
||||
const delay = 500;
|
||||
const path = window.location.pathname;
|
||||
|
||||
const colorFn = window.getTopicColor || (() => "");
|
||||
const topics = document.querySelectorAll("[data-topic]");
|
||||
topics.forEach((t) => {
|
||||
document.querySelectorAll("[data-topic]").forEach((t) => {
|
||||
t.classList.remove("active");
|
||||
t.style.color = "";
|
||||
});
|
||||
|
|
@ -109,27 +152,29 @@
|
|||
const c = colorFn(topic);
|
||||
if (c) link.style.color = c;
|
||||
|
||||
typeTerminalPath(topic, delay, () => {
|
||||
persistPrompt();
|
||||
const displayPath = isHome ? `/${topic}` : displayPathFromHref(href);
|
||||
|
||||
if (path === "/" || path === "/index.html") {
|
||||
if (window.postsByCategory && window.postsByCategory[topic]) {
|
||||
renderPosts(topic);
|
||||
return;
|
||||
}
|
||||
animateToDisplayPath(displayPath, delay, () => {
|
||||
if (
|
||||
isHome &&
|
||||
topic &&
|
||||
window.postsByCategory &&
|
||||
window.postsByCategory[topic]
|
||||
) {
|
||||
renderPosts(topic);
|
||||
return;
|
||||
}
|
||||
persistPrompt();
|
||||
|
||||
const isMail = href.startsWith("mailto:");
|
||||
if (isMail) {
|
||||
window.location.href = href;
|
||||
return;
|
||||
}
|
||||
|
||||
if (link.target === "_blank") {
|
||||
window.open(href, "_blank");
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = href;
|
||||
});
|
||||
}
|
||||
|
|
@ -141,25 +186,31 @@
|
|||
const isHome =
|
||||
window.location.pathname === "/" ||
|
||||
window.location.pathname === "/index.html";
|
||||
const delay = 500;
|
||||
if (isHome) {
|
||||
clearPrompt(500, () => {
|
||||
animateToDisplayPath("", delay, () => {
|
||||
const posts = document.getElementById("posts");
|
||||
if (posts) posts.innerHTML = "";
|
||||
const topics = document.querySelectorAll("[data-topic].active");
|
||||
topics.forEach((t) => {
|
||||
document.querySelectorAll("[data-topic].active").forEach((t) => {
|
||||
t.classList.remove("active");
|
||||
t.style.color = "";
|
||||
});
|
||||
setDocTitleForPath("");
|
||||
});
|
||||
} else {
|
||||
persistPrompt();
|
||||
clearPrompt(500, () => {
|
||||
animateToDisplayPath("", delay, () => {
|
||||
window.location.href = "/";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const initial = currentDisplayPath();
|
||||
if (initial) setPromptTailImmediate(" " + initial);
|
||||
else setPromptTailImmediate("");
|
||||
if (initial) setDocTitleForPath(initial);
|
||||
|
||||
document.body.addEventListener("click", (e) => {
|
||||
if (e.target.closest(".home-link")) return handleHomeClick(e);
|
||||
if (e.target.closest("[data-topic]")) return handleDataTopicClick(e);
|
||||
|
|
@ -172,7 +223,7 @@
|
|||
if (!link) return;
|
||||
const color =
|
||||
(window.getTopicColor &&
|
||||
window.getTopicColor(link.dataset.topic.toLowerCase())) ||
|
||||
window.getTopicColor(link.dataset.topic?.toLowerCase() || "")) ||
|
||||
"";
|
||||
if (color) link.style.color = color;
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue