// Replace default mdBook themes with Catppuccin themes (function () { "use strict"; // Wait for DOM to be ready if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", init); } else { init(); } function init() { addSidebarLogo(); replaceThemeList(); setupGhosttyStyleSidebar(); // Watch for sidebar changes and re-run setup const sidebarScrollbox = document.querySelector(".sidebar-scrollbox"); if (sidebarScrollbox) { const observer = new MutationObserver(() => { // Wait a bit for mdBook to finish updating setTimeout(setupGhosttyStyleSidebar, 50); }); observer.observe(sidebarScrollbox, { childList: true, subtree: true, }); } // Also re-run on page navigation window.addEventListener("hashchange", () => { setTimeout(setupGhosttyStyleSidebar, 100); }); } function addSidebarLogo() { const scrollbox = document.querySelector(".sidebar-scrollbox"); if (!scrollbox) { return; } // Check if logo already exists if (document.querySelector(".sidebar-logo")) { return; } // Create logo container const logoContainer = document.createElement("div"); logoContainer.className = "sidebar-logo"; // Create clickable link wrapper const logoLink = document.createElement("a"); logoLink.href = "https://socktop.io"; logoLink.style.display = "block"; logoLink.style.textAlign = "center"; // Create logo image const logoImg = document.createElement("img"); // Use root-relative path that works from any page depth logoImg.src = window.location.pathname.includes("/assets/docs/") ? "/assets/docs/logo.png" : "logo.png"; logoImg.alt = "socktop"; logoImg.style.display = "inline-block"; logoImg.style.maxWidth = "80%"; logoLink.appendChild(logoImg); logoContainer.appendChild(logoLink); // Insert as the very first child inside the scrollbox scrollbox.insertBefore(logoContainer, scrollbox.firstChild); } function replaceThemeList() { const themeList = document.getElementById("mdbook-theme-list"); if (!themeList) { console.warn("Theme list not found"); return; } // Clear existing themes themeList.innerHTML = ""; // Catppuccin themes const catppuccinThemes = [ { id: "latte", name: "Latte" }, { id: "frappe", name: "Frappé" }, { id: "macchiato", name: "Macchiato" }, { id: "mocha", name: "Mocha" }, ]; // Add Catppuccin themes catppuccinThemes.forEach((theme) => { const li = document.createElement("li"); li.setAttribute("role", "none"); const button = document.createElement("button"); button.setAttribute("role", "menuitem"); button.className = "theme"; button.id = "mdbook-theme-" + theme.id; button.textContent = theme.name; li.appendChild(button); themeList.appendChild(li); }); } function setupGhosttyStyleSidebar() { // Hide mdBook's default fold toggles const defaultToggles = document.querySelectorAll(".chapter-fold-toggle"); defaultToggles.forEach((toggle) => { toggle.style.display = "none"; }); // Get current page path to determine active item const currentPath = window.location.pathname; // Find all chapter items const allChapterItems = document.querySelectorAll( "ol.chapter > li.chapter-item", ); allChapterItems.forEach((li) => { // Check if this item has a nested section list const nestedList = li.querySelector("ol.section"); // Skip if no nested list (like Introduction) if (!nestedList) { return; } const linkWrapper = li.querySelector("span.chapter-link-wrapper"); const link = linkWrapper ? linkWrapper.querySelector("a") : null; if (!linkWrapper) { return; } // Check if any child link matches current page let hasActivePage = false; const childLinks = nestedList.querySelectorAll("a"); childLinks.forEach((childLink) => { const href = childLink.getAttribute("href"); if ( href && currentPath.includes(href.replace("../", "").replace("./", "")) ) { childLink.closest("li.chapter-item").classList.add("active"); hasActivePage = true; } }); // Skip if we already added a chevron - just update state const existingChevron = linkWrapper.querySelector(".chapter-chevron"); if (existingChevron) { if (hasActivePage) { nestedList.style.display = "block"; li.classList.add("expanded"); li.classList.remove("collapsed"); existingChevron.style.transform = "rotate(90deg)"; } return; } // Create custom chevron const chevron = document.createElement("span"); chevron.className = "chapter-chevron"; chevron.textContent = "›"; chevron.style.cssText = "float: right; transition: transform 0.2s ease; display: inline-block; opacity: 0.6; font-size: 1.2em; line-height: 1; user-select: none; cursor: pointer;"; // Insert chevron into the link wrapper linkWrapper.appendChild(chevron); // Start expanded if it contains the active page, collapsed otherwise if (hasActivePage) { nestedList.style.display = "block"; li.classList.add("expanded"); li.classList.remove("collapsed"); chevron.style.transform = "rotate(90deg)"; } else { nestedList.style.display = "none"; li.classList.add("collapsed"); li.classList.remove("expanded"); chevron.style.transform = "rotate(0deg)"; } // Add click handler to toggle const toggleSection = function (e) { e.preventDefault(); e.stopPropagation(); const isCollapsed = li.classList.contains("collapsed"); if (isCollapsed) { // Expand nestedList.style.display = "block"; li.classList.remove("collapsed"); li.classList.add("expanded"); chevron.style.transform = "rotate(90deg)"; } else { // Collapse nestedList.style.display = "none"; li.classList.add("collapsed"); li.classList.remove("expanded"); chevron.style.transform = "rotate(0deg)"; } }; // Click on chevron toggles chevron.addEventListener("click", toggleSection); // Click on parent link also toggles if it's a dummy link if (link) { const href = link.getAttribute("href"); if (!href || href === "" || href === "#") { link.addEventListener("click", toggleSection); link.style.cursor = "pointer"; } } else { linkWrapper.addEventListener("click", toggleSection); linkWrapper.style.cursor = "pointer"; } }); } })();