mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-11-15 15:21:54 +08:00
Switch scripts to redesign
This commit is contained in:
parent
a7edc5e03e
commit
4147f2b8d8
@ -87,5 +87,8 @@
|
|||||||
"wrap-iife": ["error", "inside"],
|
"wrap-iife": ["error", "inside"],
|
||||||
"yield-star-spacing": "error",
|
"yield-star-spacing": "error",
|
||||||
"yoda": "error"
|
"yoda": "error"
|
||||||
|
},
|
||||||
|
"globals": {
|
||||||
|
"NodeJS": "readonly"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
11
src/scripts/common/debounce.ts
Normal file
11
src/scripts/common/debounce.ts
Normal 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);
|
||||||
|
};
|
||||||
|
}
|
||||||
7
src/scripts/common/parents.ts
Normal file
7
src/scripts/common/parents.ts
Normal 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;
|
||||||
|
}
|
||||||
7
src/scripts/common/parsehtml.ts
Normal file
7
src/scripts/common/parsehtml.ts
Normal 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
23
src/scripts/expanders.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,25 +1,29 @@
|
|||||||
import fixActiveLink from "./fixes/activelink";
|
// import fixActiveLink from "./fixes/activelink";
|
||||||
import fixTableHeaders from "./fixes/tableheaders";
|
// import fixTableHeaders from "./fixes/tableheaders";
|
||||||
import highlight from "./other/highlight";
|
import highlight from "./other/highlight";
|
||||||
import buildSidenav from "./navigation/sidenav";
|
// import buildSidenav from "./navigation/sidenav";
|
||||||
import buildBreadcrumbs from "./navigation/breadcrumbs";
|
// import buildBreadcrumbs from "./navigation/breadcrumbs";
|
||||||
import fixSubMenus from "./fixes/submenu";
|
// import fixSubMenus from "./fixes/submenu";
|
||||||
import generateTOC from "./navigation/toc";
|
import generateTOC from "./navigation/toc";
|
||||||
import addExternalLinks from "./fixes/externallinks";
|
// import addExternalLinks from "./fixes/externallinks";
|
||||||
import injectSwagger from "./other/swagger";
|
// import injectSwagger from "./other/swagger";
|
||||||
import makeMobileMenu from "./other/mobile";
|
// 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 ETAPI_REF_NOTE_ID = "pPIXi0uwF5GX";
|
||||||
const HIDDEN_SUBMENUS = ["blog"];
|
// const HIDDEN_SUBMENUS = ["blog"];
|
||||||
const EXTERNAL_LINKS = {
|
// const EXTERNAL_LINKS = {
|
||||||
EGFtX8Uw96FQ: "https://github.com/zadam/trilium",
|
// EGFtX8Uw96FQ: "https://github.com/zadam/trilium",
|
||||||
dXAKFE0fJtom: "https://discord.gg/eTaTXUgcBr"
|
// dXAKFE0fJtom: "https://discord.gg/eTaTXUgcBr"
|
||||||
};
|
// };
|
||||||
const ALIASES = {
|
// const ALIASES = {
|
||||||
WqBnya4Ye8rS: "",
|
// WqBnya4Ye8rS: "",
|
||||||
ZapIU17QNEyU: "blog"
|
// ZapIU17QNEyU: "blog"
|
||||||
};
|
// };
|
||||||
|
|
||||||
function $try<T extends (...a: unknown[]) => unknown>(func: T, ...args: Parameters<T>) {
|
function $try<T extends (...a: unknown[]) => unknown>(func: T, ...args: Parameters<T>) {
|
||||||
try {
|
try {
|
||||||
@ -44,20 +48,25 @@ function $try<T extends (...a: unknown[]) => unknown>(func: T, ...args: Paramete
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Perform fixes first
|
// Perform fixes first
|
||||||
$try(fixActiveLink, ALIASES);
|
// $try(fixActiveLink, ALIASES);
|
||||||
$try(fixTableHeaders);
|
// $try(fixTableHeaders);
|
||||||
$try(fixSubMenus, HIDDEN_SUBMENUS);
|
// $try(fixSubMenus, HIDDEN_SUBMENUS);
|
||||||
$try(addExternalLinks, EXTERNAL_LINKS);
|
// $try(addExternalLinks, EXTERNAL_LINKS);
|
||||||
|
|
||||||
// Now layout changes
|
// Now layout changes
|
||||||
$try(buildBreadcrumbs);
|
// $try(buildBreadcrumbs);
|
||||||
$try(buildSidenav);
|
// $try(buildSidenav);
|
||||||
$try(generateTOC);
|
$try(generateTOC);
|
||||||
|
|
||||||
// Finally, other features
|
// Finally, other features
|
||||||
$try(highlight);
|
$try(highlight);
|
||||||
$try(injectSwagger, ETAPI_REF_NOTE_ID);
|
// $try(injectSwagger, ETAPI_REF_NOTE_ID);
|
||||||
$try(makeMobileMenu);
|
|
||||||
|
$try(setupExpanders);
|
||||||
|
$try(setupMobileMenu);
|
||||||
|
$try(setupSearch);
|
||||||
|
$try(setupThemeSelector);
|
||||||
|
// $try(makeMobileMenu);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This was removed because both the title change and the opengraph
|
* This was removed because both the title change and the opengraph
|
||||||
|
|||||||
25
src/scripts/mobile.ts
Normal file
25
src/scripts/mobile.ts
Normal 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);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@ const buildItem = (heading: Element) => {
|
|||||||
const slug = slugify(heading.textContent ?? "");
|
const slug = slugify(heading.textContent ?? "");
|
||||||
|
|
||||||
const anchor = document.createElement("a");
|
const anchor = document.createElement("a");
|
||||||
|
anchor.className = "toc-anchor";
|
||||||
anchor.setAttribute("href", `#${slug}`);
|
anchor.setAttribute("href", `#${slug}`);
|
||||||
anchor.setAttribute("name", slug);
|
anchor.setAttribute("name", slug);
|
||||||
anchor.setAttribute("id", slug);
|
anchor.setAttribute("id", slug);
|
||||||
@ -108,8 +109,18 @@ export default function generateTOC() {
|
|||||||
changeLinkState();
|
changeLinkState();
|
||||||
window.addEventListener("scroll", 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.
|
// 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?.classList.add("toc");
|
||||||
layout?.append(toc);
|
layout?.append(pane);
|
||||||
}
|
}
|
||||||
53
src/scripts/search.ts
Normal file
53
src/scripts/search.ts
Normal 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
27
src/scripts/theme.ts
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user