socktop-webterm/docs/theme/catppuccin-themes.js

227 lines
6.8 KiB
JavaScript
Raw Normal View History

// 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";
}
});
}
})();