fix: terminal promtp
This commit is contained in:
parent
cefde24774
commit
4076af3592
6 changed files with 212 additions and 246 deletions
|
|
@ -1,126 +1,194 @@
|
|||
const TERMINAL_PROMPT = "barrett@ruth:~$ ";
|
||||
let typing = false;
|
||||
let clearing = false;
|
||||
(() => {
|
||||
if (window.__BT_INDEX_INIT) return;
|
||||
window.__BT_INDEX_INIT = true;
|
||||
|
||||
function clearPrompt(delay, callback) {
|
||||
if (clearing) return;
|
||||
clearing = true;
|
||||
const TERMINAL_PROMPT = "barrett@ruth:~$ ";
|
||||
let typing = false;
|
||||
let clearing = false;
|
||||
|
||||
const terminalPrompt = document.querySelector(".terminal-prompt");
|
||||
if (!terminalPrompt) {
|
||||
clearing = false;
|
||||
return;
|
||||
function promptEl() {
|
||||
return document.querySelector(".terminal-prompt");
|
||||
}
|
||||
|
||||
const topicLength =
|
||||
terminalPrompt.innerHTML.length - TERMINAL_PROMPT.length;
|
||||
let i = 0;
|
||||
(function restorePrompt() {
|
||||
const saved = sessionStorage.getItem("terminalPromptText");
|
||||
const el = promptEl();
|
||||
if (saved && el) el.textContent = saved;
|
||||
sessionStorage.removeItem("terminalPromptText");
|
||||
})();
|
||||
|
||||
function removeChar() {
|
||||
if (i++ < topicLength) {
|
||||
terminalPrompt.textContent = terminalPrompt.textContent.slice(0, -1);
|
||||
setTimeout(removeChar, delay / topicLength);
|
||||
} else {
|
||||
i = 0;
|
||||
function clearPrompt(delay, callback) {
|
||||
if (clearing) return;
|
||||
clearing = true;
|
||||
const el = promptEl();
|
||||
if (!el) {
|
||||
clearing = false;
|
||||
callback && callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
removeChar();
|
||||
}
|
||||
|
||||
function typechars(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const topicElement = e.target;
|
||||
if (topicElement.classList.contains("active")) return;
|
||||
if (typing) return;
|
||||
typing = true;
|
||||
|
||||
const topic = topicElement.dataset.topic;
|
||||
const terminalText = ` /${topic.toLowerCase()}`;
|
||||
const terminalPrompt = document.querySelector(".terminal-prompt");
|
||||
const delay =
|
||||
terminalPrompt.innerHTML.length > TERMINAL_PROMPT.length ? 250 : 500;
|
||||
|
||||
const topics = document.querySelectorAll(".topic a");
|
||||
topics.forEach((t) => {
|
||||
t.classList.remove("active");
|
||||
t.style.color = "";
|
||||
});
|
||||
|
||||
topicElement.classList.add("active");
|
||||
topicElement.style.color = getTopicColor(topic);
|
||||
|
||||
clearPrompt(delay, () => {
|
||||
const excess = el.textContent.length - TERMINAL_PROMPT.length;
|
||||
let i = 0;
|
||||
function typechar() {
|
||||
if (i < terminalText.length) {
|
||||
terminalPrompt.innerHTML += terminalText.charAt(i++);
|
||||
setTimeout(typechar, delay / terminalText.length);
|
||||
function tick() {
|
||||
if (i++ < excess) {
|
||||
el.textContent = el.textContent.slice(0, -1);
|
||||
setTimeout(tick, delay / Math.max(excess, 1));
|
||||
} else {
|
||||
renderPosts(topic);
|
||||
typing = false;
|
||||
clearing = false;
|
||||
callback && callback();
|
||||
}
|
||||
}
|
||||
typechar();
|
||||
});
|
||||
}
|
||||
|
||||
function renderPosts(topic) {
|
||||
const posts = document.getElementById("posts");
|
||||
posts.innerHTML = "";
|
||||
|
||||
const categoryPosts = postsByCategory[topic];
|
||||
|
||||
if (!categoryPosts) {
|
||||
return;
|
||||
tick();
|
||||
}
|
||||
|
||||
categoryPosts.forEach((post) => {
|
||||
const postDiv = document.createElement("div");
|
||||
postDiv.classList.add("post");
|
||||
|
||||
const link = document.createElement("a");
|
||||
const slug = post.id
|
||||
.split("/")
|
||||
.pop()
|
||||
.replace(/\.mdx?$/, "");
|
||||
|
||||
link.href = `/posts/${topic}/${slug}.html`;
|
||||
link.textContent = post.data.title;
|
||||
link.style.textDecoration = "underline";
|
||||
|
||||
postDiv.appendChild(link);
|
||||
posts.appendChild(postDiv);
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const topics = document.querySelectorAll(".topic a");
|
||||
|
||||
topics.forEach((topic) => {
|
||||
topic.addEventListener("click", typechars);
|
||||
|
||||
const topicName = topic.dataset.topic;
|
||||
|
||||
topic.addEventListener("mouseenter", () => {
|
||||
const color = window.getTopicColor(topicName);
|
||||
topic.style.color = color;
|
||||
});
|
||||
|
||||
topic.addEventListener("mouseleave", () => {
|
||||
if (!topic.classList.contains("active")) {
|
||||
topic.style.color = "";
|
||||
function typeTerminalPath(topic, delay, callback) {
|
||||
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);
|
||||
}
|
||||
|
||||
function renderPosts(topic) {
|
||||
if (!window.postsByCategory) return;
|
||||
const posts = document.getElementById("posts");
|
||||
if (!posts) return;
|
||||
posts.innerHTML = "";
|
||||
const arr = window.postsByCategory[topic];
|
||||
if (!arr) return;
|
||||
for (const post of arr) {
|
||||
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`;
|
||||
a.textContent = post.data.title;
|
||||
a.style.textDecoration = "underline";
|
||||
div.appendChild(a);
|
||||
posts.appendChild(div);
|
||||
}
|
||||
}
|
||||
|
||||
function handleDataTopicClick(e) {
|
||||
const link = e.target.closest("[data-topic]");
|
||||
if (!link) return;
|
||||
e.preventDefault();
|
||||
if (typing) return;
|
||||
|
||||
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) => {
|
||||
t.classList.remove("active");
|
||||
t.style.color = "";
|
||||
});
|
||||
link.classList.add("active");
|
||||
const c = colorFn(topic);
|
||||
if (c) link.style.color = c;
|
||||
|
||||
typeTerminalPath(topic, delay, () => {
|
||||
persistPrompt();
|
||||
|
||||
if (path === "/" || path === "/index.html") {
|
||||
if (window.postsByCategory && window.postsByCategory[topic]) {
|
||||
renderPosts(topic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
function handleHomeClick(e) {
|
||||
const home = e.target.closest(".home-link");
|
||||
if (!home) return;
|
||||
e.preventDefault();
|
||||
const isHome =
|
||||
window.location.pathname === "/" ||
|
||||
window.location.pathname === "/index.html";
|
||||
if (isHome) {
|
||||
clearPrompt(500, () => {
|
||||
const posts = document.getElementById("posts");
|
||||
if (posts) posts.innerHTML = "";
|
||||
const topics = document.querySelectorAll("[data-topic].active");
|
||||
topics.forEach((t) => {
|
||||
t.classList.remove("active");
|
||||
t.style.color = "";
|
||||
});
|
||||
});
|
||||
} else {
|
||||
persistPrompt();
|
||||
clearPrompt(500, () => {
|
||||
window.location.href = "/";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.body.addEventListener("click", (e) => {
|
||||
if (e.target.closest(".home-link")) return handleHomeClick(e);
|
||||
if (e.target.closest("[data-topic]")) return handleDataTopicClick(e);
|
||||
});
|
||||
|
||||
document.body.addEventListener(
|
||||
"mouseenter",
|
||||
(e) => {
|
||||
const link = e.target.closest("[data-topic]");
|
||||
if (!link) return;
|
||||
const color =
|
||||
(window.getTopicColor &&
|
||||
window.getTopicColor(link.dataset.topic.toLowerCase())) ||
|
||||
"";
|
||||
if (color) link.style.color = color;
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
document.body.addEventListener(
|
||||
"mouseleave",
|
||||
(e) => {
|
||||
const link = e.target.closest("[data-topic]");
|
||||
if (!link) return;
|
||||
if (!link.classList.contains("active")) link.style.color = "";
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
window.addEventListener("beforeunload", () => {
|
||||
const el = promptEl();
|
||||
if (el) el.textContent = TERMINAL_PROMPT;
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener("beforeunload", () => {
|
||||
const terminalPrompt = document.querySelector(".terminal-prompt");
|
||||
if (terminalPrompt) {
|
||||
terminalPrompt.innerHTML = TERMINAL_PROMPT;
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue