diff --git a/.eslintrc b/.eslintrc index cf8dd4cc5..23653b106 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,25 +2,20 @@ "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended-type-checked", - "plugin:@typescript-eslint/stylistic-type-checked", - "plugin:solid/typescript" + "plugin:@typescript-eslint/stylistic-type-checked" ], "env": { - "node": true, "es2020": true, - "browser": true, - "jquery": true + "browser": true }, - "plugins": ["@typescript-eslint", "solid"], + "plugins": ["@typescript-eslint"], "parser": "@typescript-eslint/parser", + "ignorePatterns": ["legacy/", "dist/"], "parserOptions": { "project": ["./tsconfig.eslint.json"], "tsconfigRootDir": ".", "ecmaVersion": 2022, - "sourceType": "module", - "ecmaFeatures": { - "jsx": true - } + "sourceType": "module" }, "rules": { "accessor-pairs": "error", @@ -92,9 +87,5 @@ "wrap-iife": ["error", "inside"], "yield-star-spacing": "error", "yoda": "error" - }, - "globals": { - "api": "readonly", - "NodeJS": "readonly" } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1415c70da..f7ce1e157 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "devDependencies": { "@digitak/esrun": "^3.2.24", + "@types/swagger-ui": "^3.52.0", "@typescript-eslint/eslint-plugin": "^6.7.2", "@typescript-eslint/parser": "^6.7.2", "dotenv": "^16.3.1", @@ -935,6 +936,12 @@ "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", "dev": true }, + "node_modules/@types/swagger-ui": { + "version": "3.52.0", + "resolved": "https://registry.npmjs.org/@types/swagger-ui/-/swagger-ui-3.52.0.tgz", + "integrity": "sha512-SlufixEmh+8CLHNgTfAfCT1icNOF7bXboWabhHr1+hIolqlvfwYJGe7HgRcpI3ChE7HWASmEKLkMu34rxseJjQ==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.7.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.2.tgz", diff --git a/package.json b/package.json index ffe0518a2..5bc733544 100644 --- a/package.json +++ b/package.json @@ -7,12 +7,14 @@ "build": "esrun scripts/build.ts", "build-main": "esrun scripts/build.ts -- --module=main", "build-styles": "esrun scripts/build.ts -- --module=styles", + "dist": "esrun scripts/build.ts -- --minify", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "devDependencies": { "@digitak/esrun": "^3.2.24", + "@types/swagger-ui": "^3.52.0", "@typescript-eslint/eslint-plugin": "^6.7.2", "@typescript-eslint/parser": "^6.7.2", "dotenv": "^16.3.1", diff --git a/scripts/.eslintrc b/scripts/.eslintrc index 2598b25f5..ba1c19726 100644 --- a/scripts/.eslintrc +++ b/scripts/.eslintrc @@ -1,5 +1,8 @@ { "extends": "../.eslintrc", + "env": { + "node": true + }, "rules": { "no-console": "off" } diff --git a/scripts/build.ts b/scripts/build.ts index 419b17c5c..4591c6db3 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -73,9 +73,7 @@ async function runBuild() { bundle: true, outdir: path.join(rootDir, "dist"), format: "cjs", - external: ["fs", "path", "electron", "@electron/remote"], - banner: {js: "const require = mod => {try{return window.require(mod);}catch{return {};}};"}, - target: ["chrome96", "node16"], + target: ["chrome96"], loader: { ".png": "dataurl", ".gif": "dataurl", diff --git a/src/main/breadcrumbs.ts b/src/main/breadcrumbs.ts deleted file mode 100644 index 01e34c61d..000000000 --- a/src/main/breadcrumbs.ts +++ /dev/null @@ -1,31 +0,0 @@ -export default function buildBreadcrumbsFromNav() { - const container = document.createElement("ul"); - container.id = "breadcrumbs"; - - const current = document.querySelector("#menu .active"); - if (!current) return; // Something went really wrong - const wrap = document.createElement("li"); - wrap.append(current.cloneNode(true)); - container.prepend(wrap); - let next = current.closest("ul"); - while (next) { - const clone = next?.previousElementSibling?.querySelector("a")?.cloneNode(true); - if (!clone) continue; // This also means something went very wrong - const wrap = document.createElement("li"); - wrap.append(clone); - container.prepend(wrap); - next = next?.parentElement?.closest("ul") ?? null; - if (!next) { - clone.textContent = ""; - const logo = document.createElement("img"); - logo.src = "https://raw.githubusercontent.com/zadam/trilium/master/images/icon-black.svg"; - clone.appendChild(logo); - } - } - - // We don't need this at root - if (container.children.length === 1) return; - - const main = document.getElementById("main"); - main?.prepend(container); -} \ No newline at end of file diff --git a/src/main/externallinks.ts b/src/main/externallinks.ts deleted file mode 100644 index e411412f4..000000000 --- a/src/main/externallinks.ts +++ /dev/null @@ -1,15 +0,0 @@ -export default function addExternalLinks() { - const mapping = { - EGFtX8Uw96FQ: "https://github.com/zadam/trilium" - }; - - for (const id in mapping) { - const links = document.querySelectorAll(`a[href*="${id}"]`); - if (!links.length) {console.warn(`Could not find link to note id ${id}`); continue;} - for (const link of links) { - link.href = mapping[id as keyof typeof mapping]; - link.target = "_blank"; - link.rel = "noopener noreferrer"; - } - } -} \ No newline at end of file diff --git a/src/main/fixactivelink.ts b/src/main/fixes/activelink.ts similarity index 53% rename from src/main/fixactivelink.ts rename to src/main/fixes/activelink.ts index c4797c401..f991393b0 100644 --- a/src/main/fixactivelink.ts +++ b/src/main/fixes/activelink.ts @@ -1,11 +1,24 @@ +/** + * For some reason Trilium share chooses to have the + * active link be just a rather than a true + * link with a special style. This fixes that and + * turns the back into an actual link + * with the correct note id. + */ export default function fixActiveLink() { const active = document.querySelector("#menu strong"); if (!active) return; // Something is really wrong + + // Currently active note id is stored on body + const id = document.body.dataset.noteId; + + // Create the new link const link = document.createElement("a"); link.className = "type-text active"; link.href = ``; link.textContent = active.textContent; - active.replaceWith(link); - const id = document.body.dataset.noteId; link.href = `./${id}`; + + // Replace the + active.replaceWith(link); } \ No newline at end of file diff --git a/src/main/fixes/externallinks.ts b/src/main/fixes/externallinks.ts new file mode 100644 index 000000000..bdbac9333 --- /dev/null +++ b/src/main/fixes/externallinks.ts @@ -0,0 +1,19 @@ +/** + * This function just lets us map some note links to be external links. + * This was originally designed to link the Trilium GitHub via a note. + */ +export default function addExternalLinks(mapping: Record) { + for (const id in mapping) { + const links = document.querySelectorAll(`a[href*="${id}"]`); + if (!links.length) { + // eslint-disable-next-line no-console + console.warn(`Could not find link to note id ${id}`); + continue; + } + for (const link of links) { + link.href = mapping[id]; + link.target = "_blank"; + link.rel = "noopener noreferrer"; + } + } +} \ No newline at end of file diff --git a/src/main/fixes/submenu.ts b/src/main/fixes/submenu.ts new file mode 100644 index 000000000..82609d6ca --- /dev/null +++ b/src/main/fixes/submenu.ts @@ -0,0 +1,62 @@ +const submenuBlacklist = ["ZapIU17QNEyU"]; +// if (item.innerHTML.includes(submenuBlacklist[0])) item.className += " hidden"; +/* function fixSubMenu() { + const items = document.querySelectorAll("#menu > ul > li"); + for (const item of items) { + const sublist = item.querySelector("ul"); + if (sublist) { + if (sublist.children.length) { + item.className = "submenu"; + } + else { + sublist.remove(); + } + } + } +} */ + +/** + * General premise here is to find all submenus/sublists + * and give them a submenu class. Then any list item + * that contains one of these submenus gets a submenu-item + * class. Additionally, any sublist that itself has a + * sublist is given the class hasSubmenu. + */ +export default function fixSubMenu() { + // Get every list item in the navigation + const items = document.querySelectorAll("#menu ul li"); + for (const item of items) { + const sublist = item.querySelector("ul"); + + // If the list item has no submenu, ignore and move on + if (!sublist) continue; + + // There seems to be some weird edge cases where a + // sublist ul is added but has no list items and + // in trilium the corresponding note has no children + if (!sublist.children.length) { + sublist.remove(); + continue; + } + + // If the submenu is part of our blacklist, then + // give it the hidden class. This is for pages + // that have no subcategories and only a long + // list of subpages. + const ihtml = item.innerHTML; + for (const bl of submenuBlacklist) { + if (!ihtml.includes(bl)) continue; + item.classList.add("hidden"); + } + + // Finally, add the corresponding classes to the elements + item.classList.add("submenu-item"); + sublist.classList.add("submenu"); + + // Currently, this is only used by the sidebar styles to + // adjust margins. TODO: Might be worth investigating a + // different method. + if (sublist.querySelector("ul")?.children.length) sublist.classList.add("hasSubmenu"); + + } +} \ No newline at end of file diff --git a/src/main/fixes/tableheaders.ts b/src/main/fixes/tableheaders.ts new file mode 100644 index 000000000..d67174fe1 --- /dev/null +++ b/src/main/fixes/tableheaders.ts @@ -0,0 +1,10 @@ +/** + * This specifically fixes when you have empty corners + * like on tables with column and row headers + */ +export default function fixTableHeaders() { + const headers = document.querySelectorAll("th"); + for (const header of headers) { + if (!header.textContent?.trim()) header.classList.add("empty"); + } +} \ No newline at end of file diff --git a/src/main/fixtableheaders.ts b/src/main/fixtableheaders.ts deleted file mode 100644 index 0dbf61f5d..000000000 --- a/src/main/fixtableheaders.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default function fixTableHeaders() { - Array.from(document.querySelectorAll("th")).forEach(el => { - if (!el.textContent?.trim()) el.classList.add("empty"); - }); -} \ No newline at end of file diff --git a/src/main/highlight.ts b/src/main/highlight.ts deleted file mode 100644 index 38871f021..000000000 --- a/src/main/highlight.ts +++ /dev/null @@ -1,31 +0,0 @@ -import {HLJSApi} from "highlight.js"; - -declare const hljs: HLJSApi; - -export default function addHljs() { - const link = document.createElement("link"); - link.rel = "stylesheet"; - link.href = "api/notes/cVaK9ZJwx5Hs/download"; - document.head.append(link); - - const script = document.createElement("script"); - script.src = "api/notes/6PVElIem02b5/download"; - script.addEventListener("load", () => { - hljs.registerAliases(["application-javascript-env-frontend", "application-javascript-env-backend"], {languageName: "javascript"}); - hljs.addPlugin({ - "after:highlight": (result) => { - // Add api global - result.value = result.value.replaceAll(/([^A-Za-z0-9])api\./g, function(match, prefix) { - return `${prefix}api.`; - }); - - // Add jquery global - result.value = result.value.replaceAll(/([^A-Za-z0-9\.])\$\((.+)\)/g, function(match, prefix, variable) { - return `${prefix}$(${variable})`; - }); - } - }) - hljs.highlightAll(); - }); - document.head.append(script); -} \ No newline at end of file diff --git a/src/main/index.ts b/src/main/index.ts index 2e92bc03e..08de4d39d 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,22 +1,75 @@ -import fixActiveLink from "./fixactivelink"; -import fixTableHeaders from "./fixtableheaders"; -import highlight from "./highlight"; -import buildSidenav from "./sidenav"; -import buildBreadcrumbs from "./breadcrumbs"; -import fixSubMenu from "./submenu"; -import generateTOC from "./toc"; -import addExternalLinks from "./externallinks"; +/* eslint-disable no-console */ +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 fixSubMenu from "./fixes/submenu"; +import generateTOC from "./navigation/toc"; +import addExternalLinks from "./fixes/externallinks"; +import injectSwagger from "./other/swagger"; // https://instance-name/api/notes/vW1cXaYNN7OM/download +const EXTERNAL_LINKS = { + EGFtX8Uw96FQ: "https://github.com/zadam/trilium" +}; -try{fixActiveLink();} catch(e){console.error(e)} -try{highlight();} catch(e){console.error(e)} -try{fixTableHeaders();} catch(e){console.error(e)} -// try{addLogo();} catch{} +function $try unknown>(func: T, ...args: Parameters) { + try { + func.apply(func, args); + } + catch (e) { + console.error(e); + } +} -try{fixSubMenu();} catch(e){console.error(e)} -try{buildSidenav();} catch(e){console.error(e)} -try{buildBreadcrumbs();} catch(e){console.error(e)} -try{generateTOC();} catch(e){console.error(e)} -try{addExternalLinks();} catch(e){console.error(e)} \ No newline at end of file +// const $try = (func, ...args) => { +// try { +// func.apply() +// } +// }; + +// Perform fixes first +$try(fixActiveLink); +$try(fixTableHeaders); +$try(fixSubMenu); +$try(addExternalLinks, EXTERNAL_LINKS); + +// Now layout changes +$try(buildBreadcrumbs); +$try(buildSidenav); +$try(generateTOC); + +// Finally, other features +$try(highlight); +$try(injectSwagger); + + +// try {fixActiveLink();} +// catch (e) {console.error(e);} + +// try {highlight();} +// catch (e) {console.error(e);} + +// try {fixTableHeaders();} +// catch (e) {console.error(e);} + +// try{addLogo();} +// catch{} + + +// try {fixSubMenu();} +// catch (e) {console.error(e);} + +// try {buildSidenav();} +// catch (e) {console.error(e);} + +// try {buildBreadcrumbs();} +// catch (e) {console.error(e);} + +// try {generateTOC();} +// catch (e) {console.error(e);} + +// try {addExternalLinks(EXTERNAL_LINKS);} +// catch (e) {console.error(e);} diff --git a/src/main/navigation/breadcrumbs.ts b/src/main/navigation/breadcrumbs.ts new file mode 100644 index 000000000..79380c3fd --- /dev/null +++ b/src/main/navigation/breadcrumbs.ts @@ -0,0 +1,50 @@ +/** + * This build breadcrumb-style navigation using the existing + * tree menu generated by Trilium. The concept is to find + * the currently active link (fixed by an earlier script) + * and follow that up to the root part of the menu + */ +export default function buildBreadcrumbsFromNav() { + const container = document.createElement("ul"); + container.id = "breadcrumbs"; + + // Find currently active link + const current = document.querySelector("#menu .active"); + if (!current) return; // Something went really wrong + + // Clone the link and add it to the front of the breadcrumb list + const firstItem = document.createElement("li"); + firstItem.append(current.cloneNode(true)); + container.prepend(firstItem); + + // Walk the sublists upward until the root + let next = current.closest("ul"); + while (next) { + const clone = next?.previousElementSibling?.querySelector("a")?.cloneNode(true); + if (!clone) continue; // This also means something went very wrong + + // Get the parent of the previous and add to front of breadcrumbs + const ancestorItem = document.createElement("li"); + ancestorItem.append(clone); + container.prepend(ancestorItem); + + // Get the next sublist upward + next = next?.parentElement?.closest("ul") ?? null; + + // We are not yet at root, continue + if (next) continue; + + // Since next == null, we are at root, let's ue a pretty logo + clone.textContent = ""; + const logo = document.createElement("img"); + logo.src = "https://raw.githubusercontent.com/zadam/trilium/master/images/icon-black.svg"; + clone.appendChild(logo); + } + + // We don't need this at root + if (container.children.length === 1) return; + + // Add breadcrumb container to the main layout + const main = document.getElementById("main"); + main?.prepend(container); +} \ No newline at end of file diff --git a/src/main/navigation/sidenav.ts b/src/main/navigation/sidenav.ts new file mode 100644 index 000000000..0663155f4 --- /dev/null +++ b/src/main/navigation/sidenav.ts @@ -0,0 +1,30 @@ +/** + * This generates a docs-style sidebar navigation using the Trilium tree + */ +export default function addSideNav() { + // Give all tier 2 list items category class... TODO: should this be done elsewhere? + const categories = document.querySelectorAll("#menu > ul > li > ul > li"); + for (const cat of categories) cat.classList.add("category"); + + // Use the active link as our reference point + const active = document.querySelector("#menu .active"); + + // From the active link, find the nearest category that is also a submenu item + // If there is none, try to grab the nearest hidden submenu item (for non- + // category style pages) + const treeToClone = active?.closest(".category.submenu-item") ?? active?.closest(".submenu-item.hidden"); + if (!treeToClone) return; // If neither exist, 99% chance it's the homepage + + // Clone the found node and add it to the sidebar + const sidebar = document.createElement("ul"); + sidebar.id = "sidebar"; + const clone = treeToClone.cloneNode(true); + sidebar.append(clone); + + // If there's only a single item... probably not worth having a sidebar + if (sidebar.querySelectorAll("li").length <= 1) return; + + // Add the sidebar to the front of the layout container + const layout = document.querySelector("#layout"); + layout?.prepend(sidebar); +} \ No newline at end of file diff --git a/src/main/navigation/toc.ts b/src/main/navigation/toc.ts new file mode 100644 index 000000000..89f46bfa9 --- /dev/null +++ b/src/main/navigation/toc.ts @@ -0,0 +1,106 @@ +const slugify = (text: string) => text.toLowerCase().replace(/[^\w]/g, "-"); + +const getDepth = (el: Element) => parseInt(el.tagName.replace("H","").replace("h","")); + +const buildItem = (heading: Element) => { + const slug = slugify(heading.textContent ?? ""); + + const anchor = document.createElement("a"); + anchor.setAttribute("href", `#${slug}`); + anchor.setAttribute("name", slug); + anchor.setAttribute("id", slug); + anchor.textContent = "#"; + + const link = document.createElement("a"); + link.setAttribute("href", `#${slug}`); + link.textContent = heading.textContent; + + heading.append(anchor); + + const li = document.createElement("li"); + li.append(link); + return li; +}; + +/** + * Generate a ToC from all heading elements in the main content area. + * This should go to full h6 depth and not be too opinionated. It + * does assume a "sensible" structure in that you don't go from + * h2 > h4 > h1 but rather h2 > h3 > h2 so you change by 1 and end + * up at the same level as before. + */ +export default function generateTOC() { + // Get all headings from the page and map them to already built elements + const headings = Array.from(document.querySelectorAll("h1, h2, h3, h4, h5, h6")); + if (headings.length <= 1) return; // But if there are none, let's do nothing + const items = headings.map(h => buildItem(h)); + + // Setup the ToC list + const toc = document.createElement("ul"); + toc.id = "toc"; + + // Get the depth of the first content heading on the page. + // This depth will be used as reference for all other headings. + // headings[0] === the

from Trilium + const firstDepth = getDepth(headings[1]); + + // Loop over ALL headings including the first + for (let h = 0; h < headings.length; h++) { + // Get current heading and determine depth + const current = headings[h]; + const currentDepth = getDepth(current); + + // If it's the same depth as our first heading, add to ToC + if (currentDepth === firstDepth) toc.append(items[h]); + + // If this is the last element then it will have already + // been added as a child or as same depth as first + let nextIndex = h + 1; + if (nextIndex >= headings.length) continue; + + // Time to find all children of this heading + const children = []; + const childDepth = currentDepth + 1; + let depthOfNext = getDepth(headings[nextIndex]); + while (depthOfNext > currentDepth) { + // If it's the expected depth, add as child + if (depthOfNext === childDepth) children.push(nextIndex); + nextIndex++; + + // If the next index is valid, grab the depth for next loop + // TODO: could this be done cleaner with a for loop? + if (nextIndex < headings.length) depthOfNext = getDepth(headings[nextIndex]); + else depthOfNext = currentDepth; // If the index was invalid, break loop + } + + // If this heading had children, add them as children + if (children.length) { + const ul = document.createElement("ul"); + for (const c of children) ul.append(items[c]); + items[h].append(ul); + } + } + + // Setup a moving "active" in the ToC that adjusts with the scroll state + const sections = headings.slice(1); + const links = toc.querySelectorAll("a"); + function changeLinkState() { + let index = sections.length; + + // Work backkwards to find the first matching section + while (--index && window.scrollY + 50 < (sections[index] as HTMLElement).offsetTop) {} // eslint-disable-line no-empty + + // Update the "active" item in ToC + links.forEach((link) => link.classList.remove("active")); + links[index].classList.add("active"); + } + + // Initial render + changeLinkState(); + window.addEventListener("scroll", changeLinkState); + + // Finally, add the ToC to the end of layout. Give the layout a class for adjusting widths. + const layout = document.querySelector("#layout"); + layout?.classList.add("toc"); + layout?.append(toc); +} \ No newline at end of file diff --git a/src/main/other/highlight.ts b/src/main/other/highlight.ts new file mode 100644 index 000000000..7218847ec --- /dev/null +++ b/src/main/other/highlight.ts @@ -0,0 +1,53 @@ +import {HLJSApi, HLJSPlugin} from "highlight.js"; + + +declare const hljs: HLJSApi; + + +// Custom highlight.js plugin to highlight the `api` globals for Trilium +const highlightTriliumApi: HLJSPlugin = { + "after:highlight": (result) => { + result.value = result.value.replaceAll(/([^A-Za-z0-9])api\./g, function(match, prefix) { + return `${prefix}api.`; + }); + } +}; + +// Custom highlight.js plugin to highlight JQuery function usage +const highlightJQuery: HLJSPlugin = { + "after:highlight": (result) => { + result.value = result.value.replaceAll(/([^A-Za-z0-9.])\$\((.+)\)/g, function(match, prefix, variable) { + return `${prefix}$(${variable})`; + }); + // TODO: add highlighting for static calls like $.ajax + } +}; + + +/** + * Let's highlight some codeblocks! + * TODO: check if there are codeblocks on the page before performing this action + */ +export default function addHljs() { + // Add the hightlight.js styles from the child note of this script + // TODO: make this a mapping + const link = document.createElement("link"); + link.rel = "stylesheet"; + link.href = "api/notes/cVaK9ZJwx5Hs/download"; + document.head.append(link); + + // Add the highlight.js script too + // TODO: make this a mappin as well + const script = document.createElement("script"); + script.src = "api/notes/6PVElIem02b5/download"; + script.addEventListener("load", () => { + // This registers the JS Frontend and JS Backend types as javascript aliases for highlighting purposes + hljs.registerAliases(["application-javascript-env-frontend", "application-javascript-env-backend"], {languageName: "javascript"}); + + // Add our custom plugins and highlight all on page + hljs.addPlugin(highlightTriliumApi); + hljs.addPlugin(highlightJQuery); + hljs.highlightAll(); + }); + document.head.append(script); +} \ No newline at end of file diff --git a/src/main/other/swagger.ts b/src/main/other/swagger.ts new file mode 100644 index 000000000..de8fa3f44 --- /dev/null +++ b/src/main/other/swagger.ts @@ -0,0 +1,35 @@ +import SwaggerUI, {SwaggerUIOptions} from "swagger-ui"; + + +declare const SwaggerUIBundle: typeof SwaggerUI; +const opts: SwaggerUIOptions = { + url: "https://raw.githubusercontent.com/zadam/trilium/master/src/etapi/etapi.openapi.yaml" +}; + +/** + * Add swagger to the ETAPI page! + */ +export default function injectSwagger() { + // Check if it's the ETAPI page, otherwise avoid dependency + const noteId = document.body.dataset.noteId; + if (noteId !== "pPIXi0uwF5GX") return; // TODO: make this a param + const main = document.getElementById("main")!; + main.innerHTML = ""; + opts.domNode = main; + // Add the swagger-ui styles from unpkg + // TODO: make this hosted by trilium + const link = document.createElement("link"); + link.rel = "stylesheet"; + link.href = "https://unpkg.com/swagger-ui-dist@4.5.0/swagger-ui.css"; + document.head.append(link); + + // Add the swagger-ui script too + // TODO: make this hosted by trilium + const script = document.createElement("script"); + script.src = "https://unpkg.com/swagger-ui-dist@4.5.0/swagger-ui-bundle.js"; + script.addEventListener("load", () => { + // This immediately generated the swagger-ui in the main element + SwaggerUIBundle(opts); // eslint-disable-line new-cap + }); + document.head.append(script); +} \ No newline at end of file diff --git a/src/main/sidenav.ts b/src/main/sidenav.ts deleted file mode 100644 index c8d4c7af1..000000000 --- a/src/main/sidenav.ts +++ /dev/null @@ -1,19 +0,0 @@ -export default function addSideNav() { - const categories = document.querySelectorAll("#menu > ul > li > ul > li"); - for (const cat of categories) cat.classList.add("category"); - const active = document.querySelector("#menu .active"); - const treeToClone = active?.closest(".category.submenu-item") ?? active?.closest(".submenu-item.hidden"); - if (!treeToClone) return; // probably homepage - const layout = document.querySelector("#layout"); - const sidebar = document.createElement("ul"); - sidebar.id = "sidebar"; - const clone = treeToClone.cloneNode(true); - /*const title = document.createElement("div"); - title.className = "title"; - title.append(clone.querySelector("p > a")); - sidebar.append(title); - sidebar.append(clone.querySelector("ul"));*/ - sidebar.append(clone); - if (sidebar.querySelectorAll("li").length <= 1) return; - layout?.prepend(sidebar); -} \ No newline at end of file diff --git a/src/main/submenu.ts b/src/main/submenu.ts deleted file mode 100644 index 60d9998ca..000000000 --- a/src/main/submenu.ts +++ /dev/null @@ -1,38 +0,0 @@ -const submenuBlacklist = ["ZapIU17QNEyU"] -//if (item.innerHTML.includes(submenuBlacklist[0])) item.className += " hidden"; -/*function fixSubMenu() { - const items = document.querySelectorAll("#menu > ul > li"); - for (const item of items) { - const sublist = item.querySelector("ul"); - if (sublist) { - if (sublist.children.length) { - item.className = "submenu"; - } - else { - sublist.remove(); - } - } - } -}*/ - -export default function fixSubMenu() { - const items = document.querySelectorAll("#menu ul li"); - for (const item of items) { - const sublist = item.querySelector("ul"); - if (sublist) { - if (sublist.children.length) { - const ihtml = item.innerHTML; - for (const bl of submenuBlacklist) { - if (!ihtml.includes(bl)) continue; - item.classList.add("hidden"); - } - item.classList.add("submenu-item"); - sublist.classList.add("submenu"); - if (sublist.querySelector("ul")?.children.length) sublist.classList.add("hasSubmenu"); - } - else { - sublist.remove(); - } - } - } -} \ No newline at end of file diff --git a/src/main/toc.ts b/src/main/toc.ts deleted file mode 100644 index 6b8b346e4..000000000 --- a/src/main/toc.ts +++ /dev/null @@ -1,76 +0,0 @@ -export default function generateTOC() { - const slugify = (text: string) => text.toLowerCase().replace(/[^\w]/g, "-"); - const buildItem = (heading: Element) => { - const slug = slugify(heading.textContent ?? ""); - - const anchor = document.createElement("a"); - anchor.setAttribute("href", `#${slug}`); - anchor.setAttribute("name", slug); - anchor.setAttribute("id", slug); - anchor.textContent = "#"; - - const link = document.createElement("a"); - link.setAttribute("href", `#${slug}`); - link.textContent = heading.textContent; - - heading.append(anchor); - - const li = document.createElement("li"); - li.append(link); - return li; - }; - - const headings = Array.from(document.querySelectorAll("h1, h2, h3, h4, h5, h6")); - const items = headings.map(h => buildItem(h)); - if (headings.length <= 1) return; - - const getNum = (el: Element) => parseInt(el.tagName.replace("H","").replace("h","")); - - const toc = document.createElement("ul"); - toc.id = "toc"; - const first = headings[1]; - const firstDepth = getNum(first); - - for (let h = 0; h < headings.length; h++) { - const current = headings[h]; - const currentDepth = getNum(current); - if (currentDepth === firstDepth) toc.append(items[h]); - - let nextIndex = h + 1; - if (nextIndex >= headings.length) continue; - - const children = []; - const childDepth = currentDepth + 1; - let nextDepth = getNum(headings[nextIndex]); - while (nextDepth > currentDepth) { - if (nextDepth === childDepth) children.push(nextIndex); - nextIndex++; - if (nextIndex < headings.length) nextDepth = getNum(headings[nextIndex]); - else nextDepth = currentDepth; - } - - if (children.length) { - const ul = document.createElement("ul"); - for (const c of children) ul.append(items[c]); - items[h].append(ul); - } - } - - const sections = headings.slice(1); - const links = toc.querySelectorAll("a"); - function changeLinkState() { - let index = sections.length; - - while(--index && window.scrollY + 50 < (sections[index] as HTMLElement).offsetTop) {} - - links.forEach((link) => link.classList.remove('active')); - links[index].classList.add('active'); - } - - changeLinkState(); - window.addEventListener('scroll', changeLinkState); - - const layout = document.querySelector("#layout"); - layout?.classList.add("toc"); - layout?.append(toc) -} \ No newline at end of file diff --git a/src/styles/index.css b/src/styles/index.css index d77fef91c..2028b06d8 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -1,3 +1,5 @@ +@import "./swagger.css"; + * {box-sizing: border-box;} :root { @@ -8,6 +10,7 @@ --ck-color-table-caption-text: gray; --bg-primary: #1E1E1E; --bg-secondary: #3C3C3C; + --text-muted: #777; --text-primary: #ddd; --text-heading: #fff; @@ -20,6 +23,7 @@ --container-width: 1400px /*calc(100% - 10%)*/; --pane-size: 20%; scroll-padding-top: calc(72px + 1rem); + color-scheme: dark; } body { diff --git a/src/styles/swagger.css b/src/styles/swagger.css new file mode 100644 index 000000000..472a5043f --- /dev/null +++ b/src/styles/swagger.css @@ -0,0 +1,85 @@ +#main .swagger-ui .scheme-container { + background: #20212B; +} + +#main .swagger-ui .opblock .opblock-section-header { + background: rgba(0, 0, 0, 0.2); +} + +#main .swagger-ui .opblock-body pre.microlight { + background: #20212B!important; +} + +#main .swagger-ui, +#main .swagger-ui .info li, +#main .swagger-ui .info p, +#main .swagger-ui .info table, +#main .swagger-ui .opblock-description-wrapper p, +#main .swagger-ui .opblock-external-docs-wrapper p, +#main .swagger-ui .opblock-title_normal p, +#main .swagger-ui .response-col_status, +#main .swagger-ui .response-col_links { + color: var(--text-primary); +} + +#main .swagger-ui .btn, +#main .swagger-ui .model, +#main .swagger-ui .tab li, +#main .swagger-ui table thead tr td, +#main .swagger-ui table thead tr th, +#main .swagger-ui .parameter__type, +#main .swagger-ui .parameter__name, +#main .swagger-ui thead tr td.col_header, +#main .swagger-ui .model-title { + color: var(--text-heading); +} + +#main .swagger-ui .model .property.primitive { + color: var(--text-muted); +} + +#main .swagger-ui .prop-type { + color: var(--accent-color); +} + +#main .swagger-ui svg { + fill: var(--text-heading); +} + + +#main .swagger-ui .model-toggle::after { + filter: invert(100%); +} + +#main .swagger-ui .btn { + border: 2px solid var(--text-heading); + transition: transform 200ms ease; +} + +#main .swagger-ui .btn:hover { + transform: translateY(-5px); +} + +#main .swagger-ui input[disabled], +#main .swagger-ui select[disabled], +#main .swagger-ui textarea[disabled], +#main .swagger-ui select { + background: rgba(0, 0, 0, 0.2); + color: var(--text-primary); + border: 2px solid rgba(0,0,0,0.3); + appearance: auto; +} + + +#main .models > h4 { + margin: 5px 10px; +} + + +#main .swagger-ui .opblock-summary-control { + margin-right: 10px; +} + +#main .swagger-ui .authorization__btn { + padding-left: 0; +} \ No newline at end of file diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 912c46deb..5e04c9f4f 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -4,5 +4,5 @@ "rootDir": ".", "noEmit": true }, - "include": ["src/**/*", "scripts/*", "static/*"], + "include": ["src/**/*", "scripts/*"], } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index e32c9959d..ef08e0c07 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,30 +5,12 @@ "esModuleInterop": true, "allowSyntheticDefaultImports": true, "resolveJsonModule": true, - "declaration": true, "strictNullChecks": true, "moduleResolution": "Node16", "target": "ES2021", "rootDir": "src", "outDir": "lib/cjs", - "module": "Node16", - "jsx": "preserve", - "jsxImportSource": "solid-js", + "module": "Node16" }, - "include": ["src/**/*"], - "typedocOptions": { - "name": "TriliumETAPI", - "entryPoints": ["src/index.ts"], - "out": "docs", - "includeVersion": true, - "navigationLinks": { - "Trilium": "https://github.com/zadam/trilium" - }, - "sidebarLinks": {}, - "navigation": { - "fullTree": true, - "includeCategories": true, - "includeGroups": false - } - } + "include": ["src/**/*"] } \ No newline at end of file