(() => { if (window.__BT_INDEX_INIT) return; window.__BT_INDEX_INIT = true; const TERMINAL_PROMPT = "barrett@ruth:~$ "; let typing = 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(); if (saved && el) el.textContent = saved; sessionStorage.removeItem("terminalPromptText"); })(); 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 animateToDisplayPath(displayPath, totalMs, done) { if (typing) return; typing = true; const el = promptEl(); 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) { 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.slug || post.id ?.split("/") .pop() ?.replace(/\.mdx?$/, ""); a.href = `/${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 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 colorFn = window.getTopicColor || (() => ""); const topicKey = topic.split("/")[0]; const willNavigateAway = !( isHome && topic && window.postsByCategory && window.postsByCategory[topic] ); if (willNavigateAway) { link.classList.add("active"); const c = colorFn(topicKey); if (c) link.style.color = c; } else { document.querySelectorAll("[data-topic]").forEach((t) => { t.classList.remove("active"); t.style.color = ""; }); link.classList.add("active"); const c = colorFn(topicKey); if (c) link.style.color = c; } const displayPath = isHome ? `/${topic}` : displayPathFromHref(href); 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; }); } 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"; const delay = 500; if (isHome) { animateToDisplayPath("", delay, () => { const posts = document.getElementById("posts"); if (posts) posts.innerHTML = ""; document.querySelectorAll("[data-topic].active").forEach((t) => { t.classList.remove("active"); t.style.color = ""; }); document.title = ""; }); } else { persistPrompt(); animateToDisplayPath("", delay, () => { window.location.href = "/"; }); } } document.addEventListener("DOMContentLoaded", () => { const initial = currentDisplayPath(); if (initial) setPromptTailImmediate(" " + initial); else setPromptTailImmediate(""); document.body.addEventListener("click", (e) => { if (e.target.closest(".home-link")) return handleHomeClick(e); if (e.target.closest(".topics [data-topic]")) return handleDataTopicClick(e); }); document.body.addEventListener( "mouseenter", (e) => { const link = e.target.closest(".topics [data-topic]"); if (!link) return; const raw = link.dataset.topic || ""; const key = raw.split("/")[0].toLowerCase(); const color = (window.getTopicColor && window.getTopicColor(key)) || ""; if (color) { link.style.color = color; link.style.textDecorationColor = color; } }, true, ); document.body.addEventListener( "mouseleave", (e) => { const link = e.target.closest(".topics [data-topic]"); if (!link) return; if (!link.classList.contains("active")) { link.style.color = ""; link.style.textDecorationColor = ""; } }, true, ); const themeToggle = document.getElementById("theme-toggle"); if (themeToggle) { function updateBearVisual() { const currentTheme = document.documentElement.getAttribute("data-theme"); if (currentTheme === "dark") { themeToggle.textContent = "☾⊂ʕ•ᴥ•ʔ"; } else { themeToggle.textContent = "☼⊂ʕ•ᴥ•ʔ"; } } updateBearVisual(); themeToggle.addEventListener("click", () => { const currentTheme = document.documentElement.getAttribute("data-theme"); const newTheme = currentTheme === "dark" ? "light" : "dark"; document.documentElement.setAttribute("data-theme", newTheme); localStorage.setItem("theme", newTheme); updateBearVisual(); }); } window.addEventListener("beforeunload", () => { const el = promptEl(); if (el) el.textContent = TERMINAL_PROMPT; }); }); })();