Switch scripts to redesign

This commit is contained in:
Zack Rauen
2023-09-27 23:18:03 -04:00
parent a7edc5e03e
commit 4147f2b8d8
10 changed files with 204 additions and 28 deletions

View File

@@ -87,5 +87,8 @@
"wrap-iife": ["error", "inside"],
"yield-star-spacing": "error",
"yoda": "error"
},
"globals": {
"NodeJS": "readonly"
}
}

View File

@@ -0,0 +1,11 @@
export default function debounce<T extends (...args: unknown[]) => unknown>(executor: T, delay: number) {
let timeout: NodeJS.Timeout | null;
return function(...args: Parameters<T>): void {
const callback = () => {
timeout = null;
Reflect.apply(executor, null, args);
};
if (timeout) clearTimeout(timeout);
timeout = setTimeout(callback, delay);
};
}

View File

@@ -0,0 +1,7 @@
export default function parents<T extends HTMLElement>(el: T, selector: string) {
const result = [];
for (let p = el && el.parentElement; p; p = p.parentElement) {
if (p.matches(selector)) result.push(p);
}
return result;
}

View File

@@ -0,0 +1,7 @@
export default function parseHTML(html: string, fragment = false) {
const template = document.createElement("template");
template.innerHTML = html;
const node = template.content.cloneNode(true);
if (fragment) return node;
return node.childNodes.length > 1 ? node.childNodes : node.childNodes[0];
}

23
src/scripts/expanders.ts Normal file
View File

@@ -0,0 +1,23 @@
export default function setupExpanders() {
const expanders = Array.from(document.querySelectorAll("#menu .collapse-button"));
for (const ex of expanders) {
ex.addEventListener("click", e => {
e.preventDefault();
e.stopPropagation();
// ex.parentElement.parentElement.classList.toggle("expanded");
ex.closest(".submenu-item")?.classList.toggle("expanded");
});
}
const activeLink = document.querySelector("#menu a.active");
if (activeLink) {
let parent = activeLink.parentElement;
const mainMenu = document.getElementById("#menu");
while (parent && parent !== mainMenu) {
if (parent.matches(".submenu-item")) {
parent.classList.add("expanded");
}
parent = parent.parentElement;
}
}
}

View File

@@ -1,25 +1,29 @@
import fixActiveLink from "./fixes/activelink";
import fixTableHeaders from "./fixes/tableheaders";
// import fixActiveLink from "./fixes/activelink";
// import fixTableHeaders from "./fixes/tableheaders";
import highlight from "./other/highlight";
import buildSidenav from "./navigation/sidenav";
import buildBreadcrumbs from "./navigation/breadcrumbs";
import fixSubMenus from "./fixes/submenu";
// import buildSidenav from "./navigation/sidenav";
// import buildBreadcrumbs from "./navigation/breadcrumbs";
// import fixSubMenus from "./fixes/submenu";
import generateTOC from "./navigation/toc";
import addExternalLinks from "./fixes/externallinks";
import injectSwagger from "./other/swagger";
import makeMobileMenu from "./other/mobile";
// import addExternalLinks from "./fixes/externallinks";
// import injectSwagger from "./other/swagger";
// import makeMobileMenu from "./other/mobile";
import setupExpanders from "./expanders";
import setupMobileMenu from "./mobile";
import setupSearch from "./search";
import setupThemeSelector from "./theme";
const ETAPI_REF_NOTE_ID = "pPIXi0uwF5GX";
const HIDDEN_SUBMENUS = ["blog"];
const EXTERNAL_LINKS = {
EGFtX8Uw96FQ: "https://github.com/zadam/trilium",
dXAKFE0fJtom: "https://discord.gg/eTaTXUgcBr"
};
const ALIASES = {
WqBnya4Ye8rS: "",
ZapIU17QNEyU: "blog"
};
// const ETAPI_REF_NOTE_ID = "pPIXi0uwF5GX";
// const HIDDEN_SUBMENUS = ["blog"];
// const EXTERNAL_LINKS = {
// EGFtX8Uw96FQ: "https://github.com/zadam/trilium",
// dXAKFE0fJtom: "https://discord.gg/eTaTXUgcBr"
// };
// const ALIASES = {
// WqBnya4Ye8rS: "",
// ZapIU17QNEyU: "blog"
// };
function $try<T extends (...a: unknown[]) => unknown>(func: T, ...args: Parameters<T>) {
try {
@@ -44,20 +48,25 @@ function $try<T extends (...a: unknown[]) => unknown>(func: T, ...args: Paramete
*/
// Perform fixes first
$try(fixActiveLink, ALIASES);
$try(fixTableHeaders);
$try(fixSubMenus, HIDDEN_SUBMENUS);
$try(addExternalLinks, EXTERNAL_LINKS);
// $try(fixActiveLink, ALIASES);
// $try(fixTableHeaders);
// $try(fixSubMenus, HIDDEN_SUBMENUS);
// $try(addExternalLinks, EXTERNAL_LINKS);
// Now layout changes
$try(buildBreadcrumbs);
$try(buildSidenav);
// $try(buildBreadcrumbs);
// $try(buildSidenav);
$try(generateTOC);
// Finally, other features
$try(highlight);
$try(injectSwagger, ETAPI_REF_NOTE_ID);
$try(makeMobileMenu);
// $try(injectSwagger, ETAPI_REF_NOTE_ID);
$try(setupExpanders);
$try(setupMobileMenu);
$try(setupSearch);
$try(setupThemeSelector);
// $try(makeMobileMenu);
/**
* This was removed because both the title change and the opengraph

25
src/scripts/mobile.ts Normal file
View File

@@ -0,0 +1,25 @@
import parents from "./common/parents";
export default function setupMobileMenu() {
function toggleMobileMenu(event: MouseEvent) {
event.stopPropagation(); // Don't prevent default for links
const isOpen = document.body.classList.contains("menu-open");
if (isOpen) return document.body.classList.remove("menu-open");
return document.body.classList.add("menu-open");
}
const showMenuButton = document.getElementById("show-menu-button");
showMenuButton?.addEventListener("click", toggleMobileMenu);
window.addEventListener("click", e => {
const isOpen = document.body.classList.contains("menu-open");
if (!isOpen) return; // This listener is only to close
// If the click was anywhere in the mobile nav, don't close
if (parents(e.target as HTMLElement, "#left-pane").length) return;
return toggleMobileMenu(e);
});
}

View File

@@ -6,6 +6,7 @@ const buildItem = (heading: Element) => {
const slug = slugify(heading.textContent ?? "");
const anchor = document.createElement("a");
anchor.className = "toc-anchor";
anchor.setAttribute("href", `#${slug}`);
anchor.setAttribute("name", slug);
anchor.setAttribute("id", slug);
@@ -108,8 +109,18 @@ export default function generateTOC() {
changeLinkState();
window.addEventListener("scroll", changeLinkState);
// Create the toc wrapper
const pane = document.createElement("div");
pane.id = "toc-pane";
// Create the header
const header = document.createElement("h3");
header.textContent = "On This Page";
pane.append(header);
pane.append(toc);
// Finally, add the ToC to the end of layout. Give the layout a class for adjusting widths.
const layout = document.querySelector("#layout");
const layout = document.querySelector("#right-pane");
layout?.classList.add("toc");
layout?.append(toc);
layout?.append(pane);
}

53
src/scripts/search.ts Normal file
View File

@@ -0,0 +1,53 @@
import debounce from "./common/debounce";
import parents from "./common/parents";
import parseHTML from "./common/parsehtml";
interface SearchResults {
results: SearchResult[];
}
interface SearchResult {
id: string;
title: string;
score: number;
path: string;
}
export default function setupSearch() {
const searchInput: HTMLInputElement = document.querySelector(".search-input")!;
searchInput.addEventListener("keyup", debounce(async () => {
// console.log("CHANGE EVENT");
const current = document.body.dataset.noteId;
const query = searchInput.value;
if (query.length < 3) return;
const resp = await fetch(`api/search/${current}?query=${query}`);
const json = await resp.json() as SearchResults;
const results = json.results.slice(0, 5);
const lines = [`<div class="search-results">`];
for (const result of results) {
lines.push(`<a class="search-result-item" href="./${result.id}"><div class="search-result-title">${result.title}</div><div class="search-result-note">${result.path || "Home"}</div></a>`);
}
lines.push("</div>");
const container = parseHTML(lines.join("")) as HTMLDivElement;
// console.log(container, lines);
const rect = searchInput.getBoundingClientRect();
container.style.top = `${rect.bottom}px`;
container.style.left = `${rect.left}px`;
container.style.minWidth = `${rect.width}px`;
const existing = document.querySelector(".search-results");
if (existing) existing.replaceWith(container);
else document.body.append(container);
}, 500));
window.addEventListener("click", e => {
const existing = document.querySelector(".search-results");
if (!existing) return;
// If the click was anywhere search components ignore it
if (parents(e.target as HTMLElement, ".search-results,.search-item").length) return;
if (existing) existing.remove();
});
}

27
src/scripts/theme.ts Normal file
View File

@@ -0,0 +1,27 @@
export default function setupThemeSelector() {
const themeSwitch: HTMLInputElement = document.querySelector(".theme-selection input")!;
themeSwitch?.addEventListener("change", () => {
if (themeSwitch.checked) {
document.body.classList.add("theme-dark");
document.body.classList.remove("theme-light");
localStorage.setItem("theme", "dark");
}
else {
document.body.classList.remove("theme-dark");
document.body.classList.add("theme-light");
localStorage.setItem("theme", "light");
}
});
const preference = localStorage.getItem("theme");
if (preference) {
if (preference === "dark") {
document.body.classList.add("theme-dark");
document.body.classList.remove("theme-light");
}
else {
document.body.classList.remove("theme-dark");
document.body.classList.add("theme-light");
}
}
}