227 lines
6.8 KiB
JavaScript
227 lines
6.8 KiB
JavaScript
// 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";
|
||
}
|
||
});
|
||
}
|
||
})();
|