From cb19ed36bc85e3be03d6ea1b616a533e793b1c23 Mon Sep 17 00:00:00 2001 From: Zack Rauen Date: Sat, 23 Sep 2023 02:56:59 -0400 Subject: [PATCH] Make mobile compatible --- src/main/index.ts | 9 + src/main/navigation/breadcrumbs.ts | 1 + src/main/other/mobile.ts | 74 +++++ src/styles/breadcrumbs.css | 47 +++ src/styles/externallinks.css | 19 ++ src/styles/index.css | 468 +---------------------------- src/styles/mobile.css | 148 +++++++++ src/styles/navbar.css | 152 ++++++++++ src/styles/sidebar.css | 58 ++++ src/styles/toc.css | 39 +++ 10 files changed, 559 insertions(+), 456 deletions(-) create mode 100644 src/main/other/mobile.ts create mode 100644 src/styles/breadcrumbs.css create mode 100644 src/styles/externallinks.css create mode 100644 src/styles/mobile.css create mode 100644 src/styles/navbar.css create mode 100644 src/styles/sidebar.css create mode 100644 src/styles/toc.css diff --git a/src/main/index.ts b/src/main/index.ts index 08de4d39d..1588c830e 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -8,6 +8,7 @@ import fixSubMenu from "./fixes/submenu"; import generateTOC from "./navigation/toc"; import addExternalLinks from "./fixes/externallinks"; import injectSwagger from "./other/swagger"; +import makeMobileMenu from "./other/mobile"; // https://instance-name/api/notes/vW1cXaYNN7OM/download @@ -30,6 +31,8 @@ function $try unknown>(func: T, ...args: Paramete // } // }; + + // Perform fixes first $try(fixActiveLink); $try(fixTableHeaders); @@ -44,6 +47,12 @@ $try(generateTOC); // Finally, other features $try(highlight); $try(injectSwagger); +$try(makeMobileMenu); + +// mobileMenu.append(document.querySelector("#menu > ul")!); +// mobileMenu.append(document.querySelector("#sidebar")!); + + // try {fixActiveLink();} diff --git a/src/main/navigation/breadcrumbs.ts b/src/main/navigation/breadcrumbs.ts index 79380c3fd..a32353915 100644 --- a/src/main/navigation/breadcrumbs.ts +++ b/src/main/navigation/breadcrumbs.ts @@ -47,4 +47,5 @@ export default function buildBreadcrumbsFromNav() { // Add breadcrumb container to the main layout const main = document.getElementById("main"); main?.prepend(container); + container.scrollLeft = container.scrollWidth - container.clientWidth; } \ No newline at end of file diff --git a/src/main/other/mobile.ts b/src/main/other/mobile.ts new file mode 100644 index 000000000..857ca1268 --- /dev/null +++ b/src/main/other/mobile.ts @@ -0,0 +1,74 @@ +const 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]; +}; + +const goBackString = `
  • ↩ Back to Main Menu

  • `; +const menuButtonString = ``; + +const isMobileAgent = /Mobi/.test(navigator.userAgent); +const isMobileSize = window.matchMedia("only screen and (max-width: 760px)").matches; + +// TODO: maybe re-work this to have #sidebar be later than #menu +// then use #menu.expanded ~ #sidebar for showing the sidebar +// that way less JS is involved to make mobile work properly +export default function makeMobileMenu() { + if (!isMobileAgent && !isMobileSize) return; // If nothing indicates mobile, bail out + const menuWrap = document.querySelector("#menu"); + const mainMenu = document.querySelector("#menu > ul"); + if (!menuWrap || !mainMenu) return; // Something went really wrong... + const sidebar = document.querySelector("#sidebar"); + + const toggleMenu = (event: MouseEvent) => { + event.stopPropagation(); // Don't preventDefault to allow links + + const isVisible = menuWrap.classList.contains("expanded"); + + if (isVisible) { + menuWrap.classList.remove("expanded"); + if (sidebar) { + mainMenu.classList.remove("active"); + if (!sidebar.classList.contains("active")) sidebar.classList.add("active"); + } + } + else { + menuWrap.classList.add("expanded"); + } + }; + + const menuButton = parseHTML(menuButtonString) as HTMLButtonElement; + menuButton.addEventListener("click", toggleMenu); + + window.addEventListener("click", e => { + const isVisible = menuWrap.classList.contains("expanded"); + if (!isVisible) return; // This is only for when the menu is open + toggleMenu(e); + }); + + + if (sidebar) { + const goBackButton = parseHTML(goBackString) as HTMLLIElement; + goBackButton.addEventListener("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + mainMenu.classList.add("active"); + sidebar.classList.remove("active"); + }); + + sidebar.prepend(goBackButton); + } + + + if (sidebar) sidebar.classList.add("active"); + else mainMenu.classList.add("active"); + + menuWrap.append(menuButton); + if (sidebar) menuWrap.append(sidebar); +} \ No newline at end of file diff --git a/src/styles/breadcrumbs.css b/src/styles/breadcrumbs.css new file mode 100644 index 000000000..ba56f7ac1 --- /dev/null +++ b/src/styles/breadcrumbs.css @@ -0,0 +1,47 @@ +#breadcrumbs { + margin-bottom: 30px; + display: flex; + align-items: center; + list-style: none; + padding: 0; + overflow-x: auto; +} + +#breadcrumbs li { + display: flex; + align-items: center; +} + +#breadcrumbs a { + display: flex; + align-items: center; + white-space: nowrap; + padding: 5px 10px; + border-radius: 20px; + transition: color 200ms ease, transform 200ms ease, background-color 200ms ease; +} + +#breadcrumbs img { + min-width: 18px; + filter: invert(100%); +} + +#breadcrumbs li:not(:last-child)::after { + background: url("data:image/svg+xml;utf8,") center; + content: " "; + display: inline-block; + filter: invert(0.64) sepia(0.11) saturate(0) hue-rotate(149deg) brightness(0.99) contrast(0.95); + height: 8px; + margin: 0 8px; + opacity: .5; + width: 8px; +} + +#breadcrumbs li:last-child a, +#breadcrumbs li a:hover { + background: #202127; +} + +#breadcrumbs li a:hover { + transform: translateY(-3px); +} \ No newline at end of file diff --git a/src/styles/externallinks.css b/src/styles/externallinks.css new file mode 100644 index 000000000..9beffff9a --- /dev/null +++ b/src/styles/externallinks.css @@ -0,0 +1,19 @@ +a[href^="https://"] { + display: inline-flex; + align-items: center; + gap: 6px; +} + +#main a[href^="https://"] { + padding-right: 6px; +} + +a[href^="https://"]::after { + content: ""; + background-color: currentcolor; + mask: url("data:image/svg+xml;utf8,"); + -webkit-mask: url("data:image/svg+xml;utf8,"); + width: 13.5px; + height: 13.5px; + display: inline-flex; +} \ No newline at end of file diff --git a/src/styles/index.css b/src/styles/index.css index 2028b06d8..6fcf80bcc 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -1,4 +1,12 @@ +@import "./breadcrumbs.css"; +@import "./externallinks.css"; +@import "./navbar.css"; +@import "./sidebar.css"; @import "./swagger.css"; +@import "./toc.css"; + +@import "./mobile.css"; + * {box-sizing: border-box;} @@ -22,6 +30,8 @@ --container-width: 1400px /*calc(100% - 10%)*/; --pane-size: 20%; + + scroll-padding-top: calc(72px + 1rem); color-scheme: dark; } @@ -45,79 +55,8 @@ a:hover { color: var(--accent-color); } -#main a { - color: var(--accent-color); -} -#main a:hover { - color: var(--text-heading); -} -/* a[href^="https://"]::after { - font-size: smaller; - content: "\2197"; - vertical-align: top; -} */ - -a[href^="https://"] { - display: inline-flex; - align-items: center; - gap: 6px; -} - -#main a[href^="https://"] { - padding-right: 6px; -} - -a[href^="https://"]::after { - content: ""; - background-color: currentcolor; - mask: url("data:image/svg+xml;utf8,"); - -webkit-mask: url("data:image/svg+xml;utf8,"); - width: 13.5px; - height: 13.5px; - display: inline-flex; -} - -/* pre { - overflow: auto; -} - -img { - width: auto; - height: auto; - max-width: 100%; - max-height: 100%; -} - -iframe { - border: none; - border-radius: 0.25rem; -} - -#layout { - display: flex; - flex-flow: row wrap; - justify-content: center; - min-height: 100vh; - max-width: 960px; -} - -#main { - contain: content; - background-color: var(--top-layer); - padding: 2rem 3rem 2rem 3rem; - box-shadow: 0 2px 10px rgba(0,0,0,.25)!important; - order: 2; -} - -#title { - text-align: center; - margin-block-end: 24px; - font-size: 32px; - line-height: 48px; - letter-spacing: 0.02em; -} */ #content { font-size: 16px; @@ -237,252 +176,7 @@ iframe { display: none; } -/* .showMenu #menu { - display: block; -} -#menu strong{ - color: var(--blue-strong); -} */ - -/* nav.grid ul { - display: flex; - flex-flow: row wrap; - gap: 1rem; -} -nav.list { - line-height: 1.5; -} - -nav ul { - list-style-type: none; - padding: 0 1rem; -} - -#parentLink { - display: none; - color: var(--gray); - position: relative; - left: -3rem; - top: -1rem; -} -#parentLink::before { - content: "@"; -} - -input:disabled { - border-radius: 3px; - background-color: #cacaca; -} - -.ck-content .table table { - border: 0; -} - -.ck-content .table table th { - background: #252526; - word-wrap: normal; - background-clip: padding-box; -} - -.ck-content .table table th.empty { - opacity: 0; - border: 0; -} - -@media screen and (min-width: 60rem) { - #main { - width: 48rem; - margin-block-start: 6rem; - margin-block-end: 6rem; - box-shadow: var(--shadow); - border-radius: 4px 4px 0px 0px; - } - #toggleMenuButton { - right: 1rem; - top: 1rem; - } -} - -@media screen and (max-width: 60rem) { - #main { - width: 100%; - } - #toggleMenuButton { - right: 1rem; - bottom: 1rem; - } -} - - -@media screen and (max-width: 32rem) { - #main { - padding: 4rem 2rem 2rem 2rem; - } - #content h2::before { - left: 1rem; - } - #parentLink { - left: 0rem; - } -} */ - -#menu { - display: flex; - position: fixed; - justify-content: space-between; - align-items: center; - top: 0; - left: 0; - right: 0; - width: inherit; - margin: 0 auto; - overflow: visible; - z-index: 10; - background: var(--bottom-layer); - padding: 8px 16px; -} - -#menu::before { - content: ""; - position: fixed; - left: 0; - right: 0; - background: var(--bottom-layer); - height: 72px; - z-index: -1; -} - -#menu > p > a { - display: flex; - white-space: nowrap; - gap: 10px; - align-items: center; -/* color: var(--text-heading); */ -} - -/* #menu > p > a:hover { - color: var(--accent-color); -} */ - -/* #menu a { - color: var(--text-heading); -} - -#menu a:hover { - color: var(--accent-color); -} */ - -#menu > p > a::before { - content: ""; - display: flex; - background: url("https://raw.githubusercontent.com/zadam/trilium/master/images/icon-color.svg"); - height: 40px; - width: 53px; -} - -/* #logo { - order: 1; - height: 40px; -} */ - -/* #menu > p > strong::before { - content: ""; - display: flex; - background: url("https://notes.cloud.zerebos.com/assets/v0.60.4/images/icon-black.svg"); -} */ - -#menu ul, #sidebar ul { - list-style: none; - padding: 0; - position: relative; -} - -#menu > ul { - margin: 0; - padding: 0; - display: flex; - gap: 30px; -} - -#menu > ul > li { - margin: 0; - padding: 0; - position: relative; -} - - - -#menu > ul > li > p > a { - display: flex; - gap: 10px; - align-items: center; - font-weight: 700; - padding: 16px 0; -} - -/* #menu > ul > li > p > a::after { - content: ''; - border: 4px solid transparent; - border-top: 4px solid white; - display: flex; - align-items: center; - margin-bottom: -8px; -} */ - -#menu > ul > li.submenu-item > p > a::after { - content: ""; - border-color: currentcolor #0000; - border-style: solid; - border-width: .4em .4em 0; - position: relative; - display: flex; - top: 2px; - align-items: center; -/* transform: translateY(-50%); */ -} - -#menu > ul > li.submenu-item.hidden > ul, -#menu > ul > li.submenu-item.hidden > p > a::after{ - display: none; -} - -#menu > ul > li > ul { -/* display: none; */ - opacity: 0; - pointer-events: none; - position: absolute; - top: 40px; - background: #242526; - border-radius: 6px; - min-width: 150px; - right: 50%; - transform: translateX(50%); - padding: 8px; - transition: top 200ms ease, opacity 200ms ease; -} - -#menu > ul > li > ul > li a { - display: flex; - border-radius: 6px; - padding: 3px 6px; - transition: background-color 200ms ease; -} - -#menu > ul > li > ul > li a:hover { - background: rgba(255,255,255,0.05); -} - -#menu > ul > li > ul > li > ul { - display: none; -} - -#menu > ul > li:hover > ul { -/* display: flex; */ - top: 50px; - opacity: 1; - pointer-events: initial; -} body { @@ -515,12 +209,7 @@ body { } } -#sidebar { - flex: var(--pane-size); - height: fit-content; - position: sticky; - top: calc(72px + 1rem); -} + #main { flex: 100%; @@ -546,57 +235,6 @@ body { -#sidebar, #sidebar ul { - list-style: none; - padding: 0; - margin: 0; -} - -#sidebar { -/* padding-right: 20px; */ -} - - - -/* #sidebar .title { - text-transform: uppercase; - text-align: center; - letter-spacing: 5px; - color: #777; - font-weight: 700; - border-bottom: 1px solid #777; -} */ - -#sidebar p { - display: flex; - margin: 0; -} - -#sidebar a { - flex: 1; - padding: 6px 6px 6px 12px; - border-radius: 6px; - transition: color 200ms ease, background-color 200ms ease; -} - -#sidebar a:hover { - background: rgba(255,255,255,0.05); -} - -#sidebar > li > ul > li.submenu-item > p > a { - text-transform: uppercase; - font-weight: 700; - color: #555; -} - -#sidebar li > ul { - margin-top: 5px; -} - -#sidebar > li > ul.hasSubmenu, -#sidebar > li > ul > li.submenu-item + li.submenu-item { - margin-top: 20px; -} @@ -605,7 +243,7 @@ body { -/* .ck-content pre {background: none;} */ + .ck-content code { background-color: var(--accent-layer); border-radius: 6px; @@ -625,51 +263,7 @@ body { -#breadcrumbs { - margin-bottom: 30px; - display: flex; - align-items: center; - list-style: none; - padding: 0; -} -#breadcrumbs li { - display: flex; - align-items: center; -} - -#breadcrumbs a { - display: flex; - align-items: center; - padding: 5px 10px; - border-radius: 20px; - transition: color 200ms ease, transform 200ms ease, background-color 200ms ease; -} - -#breadcrumbs img { - width: 18px; - filter: invert(100%); -} - -#breadcrumbs li:not(:last-child)::after { - background: url("data:image/svg+xml;utf8,") center; - content: " "; - display: inline-block; - filter: invert(0.64) sepia(0.11) saturate(0) hue-rotate(149deg) brightness(0.99) contrast(0.95); - height: 8px; - margin: 0 8px; - opacity: .5; - width: 8px; -} - -#breadcrumbs li:last-child a, -#breadcrumbs li a:hover { - background: #202127; -} - -#breadcrumbs li a:hover { - transform: translateY(-3px); -} #parentLink { display: none; @@ -679,45 +273,7 @@ body { -#toc { - flex: var(--pane-size); - position: sticky; - top: calc(72px + 1rem); - height: fit-content; - background: var(--top-layer); - margin: 0; - padding: 16px 16px 16px 32px; - border-radius: 6px; -} -#toc, #toc ul { - list-style: none; -} - -#toc ul { - padding-left: 16px; -} - -#toc li a { - color: var(--text-heading); - transition: color 200ms ease; -} - -#toc li a:hover, -#toc li a.active { - color: var(--accent-color); -} - -#toc::before { - content: ""; - display: block; - position: absolute; - left: 16px; - top: 20px; - width: 2px; - height: calc(100% - 40px); - background: rgba(255, 255, 255, 0.1); -} diff --git a/src/styles/mobile.css b/src/styles/mobile.css new file mode 100644 index 000000000..408d677b6 --- /dev/null +++ b/src/styles/mobile.css @@ -0,0 +1,148 @@ +.expand { + display: none +} + +button.expand { + position: relative; + padding: 9px; + margin: 9.5px 0; + border: 0 solid #000; + border-radius: 4px; + background: 0 0; + color: #fff; + -webkit-transition: -webkit-transform .5s; + -moz-transition: transform .5s; + -o-transition: transform .5s; + transition: transform .5s +} + +.expanded button.expand { + background-color: #000; + -webkit-transition: -webkit-transform .5s, background-color .5s; + -moz-transition: transform .5s, background-color .5s; + -o-transition: transform .5s, background-color .5s; + transition: transform .5s, background-color .5s; + -ms-transform: rotate(90deg); + -webkit-transform: rotate(90deg); + transform: rotate(90deg) +} + +.expanded .rectangle { + background: #fff; +} + +.rectangle { + display: block; + width: 24px; + height: 4px; + border-radius: 1px; + background: var(--text-heading); + transition: transform .5s, background-color .5s; +} + +.rectangle + .rectangle { + margin-top: 5px +} + +@media screen and (max-width: 768px) { + #toc { + display: none; + } + + #main { + padding: 1rem; + } + + #layout { + overflow: hidden; + } + + #menu { + width: auto; + } + + .expand { + display: inline-block + } + + #menu::after { + content: ""; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + height: 100%; + width: 100%; + transition: background-color 200ms ease; + pointer-events: none; + } + + #menu.expanded::after { + width: 100%; + background: rgba(0,0,0,0.7); + } + + + + #menu > ul { + position: fixed; + transform: translateX(-100%); + transition: transform 200ms ease; + transform-origin: 0 0; + z-index: 1; + background: #040405; + display: initial; + top: 0; + left: 0; + bottom: 0; + height: 100%; + + width: 70%; + padding: 1rem; + overflow: auto; + } + + #menu #go-back { + margin-bottom: 20px; + } + + #menu.expanded > ul.active { + transform: translateX(0); + } + + #menu #sidebar .category > p > a { + font-weight: 400; + } + + #menu > ul > li > p > a { + padding: 3px 6px; + } + + #menu > ul > li > ul { + background: none; + opacity: 1; + position: initial; + transform: none; + margin-top: 0; + pointer-events: initial; + padding: 0; + } + + #menu > ul > li.submenu-item > p > a::after { + display: none; + } + + #menu > ul > li > ul > li > ul { + display: initial; + } + + + #menu > ul:not(#sidebar) > li > ul > li > ul { + display: none; + } + + #menu > ul:not(#sidebar) ul { + margin-left: 20px; + } +} \ No newline at end of file diff --git a/src/styles/navbar.css b/src/styles/navbar.css new file mode 100644 index 000000000..a2685fb47 --- /dev/null +++ b/src/styles/navbar.css @@ -0,0 +1,152 @@ +#menu { + display: flex; + position: fixed; + justify-content: space-between; + align-items: center; + top: 0; + left: 0; + right: 0; + width: inherit; + margin: 0 auto; + overflow: visible; + z-index: 10; + background: var(--bottom-layer); + padding: 8px 16px; +} + +#menu::before { + content: ""; + position: fixed; + left: 0; + right: 0; + background: var(--bottom-layer); + height: 72px; + z-index: -1; +} + +#menu > p > a { + display: flex; + white-space: nowrap; + gap: 10px; + align-items: center; +/* color: var(--text-heading); */ +} + +#main a { + color: var(--accent-color); +} + +#main a:hover { + color: var(--text-heading); +} + +#menu > p > a::before { + content: ""; + display: flex; + background: url("https://raw.githubusercontent.com/zadam/trilium/master/images/icon-color.svg"); + height: 40px; + width: 53px; +} + +/* #logo { + order: 1; + height: 40px; +} */ + +/* #menu > p > strong::before { + content: ""; + display: flex; + background: url("https://notes.cloud.zerebos.com/assets/v0.60.4/images/icon-black.svg"); +} */ + +#menu ul, #sidebar ul { + list-style: none; + padding: 0; + position: relative; +} + +#menu > ul { + margin: 0; + padding: 0; + display: flex; + gap: 30px; +} + +#menu > ul > li { + margin: 0; + padding: 0; + position: relative; +} + + + +#menu > ul > li > p > a { + display: flex; + gap: 10px; + align-items: center; + font-weight: 700; + padding: 16px 0; +} + +/* #menu > ul > li > p > a::after { + content: ''; + border: 4px solid transparent; + border-top: 4px solid white; + display: flex; + align-items: center; + margin-bottom: -8px; +} */ + +#menu > ul > li.submenu-item > p > a::after { + content: ""; + border-color: currentcolor #0000; + border-style: solid; + border-width: .4em .4em 0; + position: relative; + display: flex; + top: 2px; + align-items: center; +/* transform: translateY(-50%); */ +} + +#menu > ul > li.submenu-item.hidden > ul, +#menu > ul > li.submenu-item.hidden > p > a::after{ + display: none; +} + +#menu > ul > li > ul { +/* display: none; */ + opacity: 0; + pointer-events: none; + position: absolute; + top: 40px; + background: #242526; + border-radius: 6px; + min-width: 150px; + right: 50%; + transform: translateX(50%); + padding: 8px; + transition: top 200ms ease, opacity 200ms ease; +} + +#menu > ul > li > ul > li a { + display: flex; + border-radius: 6px; + padding: 3px 6px; + transition: background-color 200ms ease; +} + +#menu > ul > li > ul > li a:hover { + background: rgba(255,255,255,0.05); +} + +#menu > ul > li > ul > li > ul { + display: none; +} + +#menu > ul > li:hover > ul { +/* display: flex; */ + top: 50px; + opacity: 1; + pointer-events: initial; +} \ No newline at end of file diff --git a/src/styles/sidebar.css b/src/styles/sidebar.css new file mode 100644 index 000000000..3a2b099ba --- /dev/null +++ b/src/styles/sidebar.css @@ -0,0 +1,58 @@ +#sidebar { + flex: var(--pane-size); + height: fit-content; + position: sticky; + top: calc(72px + 1rem); +} + +#sidebar, #sidebar ul { + list-style: none; + padding: 0; + margin: 0; +} + +#sidebar { +/* padding-right: 20px; */ +} + + + +/* #sidebar .title { + text-transform: uppercase; + text-align: center; + letter-spacing: 5px; + color: #777; + font-weight: 700; + border-bottom: 1px solid #777; +} */ + +#sidebar p { + display: flex; + margin: 0; +} + +#sidebar a { + flex: 1; + padding: 6px 6px 6px 12px; + border-radius: 6px; + transition: color 200ms ease, background-color 200ms ease; +} + +#sidebar a:hover { + background: rgba(255,255,255,0.05); +} + +#sidebar > li > ul > li.submenu-item > p > a { + text-transform: uppercase; + font-weight: 700; + color: #555; +} + +#sidebar li > ul { + margin-top: 5px; +} + +#sidebar > li > ul.hasSubmenu, +#sidebar > li > ul > li.submenu-item + li.submenu-item { + margin-top: 20px; +} \ No newline at end of file diff --git a/src/styles/toc.css b/src/styles/toc.css new file mode 100644 index 000000000..6ae6962c4 --- /dev/null +++ b/src/styles/toc.css @@ -0,0 +1,39 @@ +#toc { + flex: var(--pane-size); + position: sticky; + top: calc(72px + 1rem); + height: fit-content; + background: var(--top-layer); + margin: 0; + padding: 16px 16px 16px 32px; + border-radius: 6px; +} + +#toc, #toc ul { + list-style: none; +} + +#toc ul { + padding-left: 16px; +} + +#toc li a { + color: var(--text-heading); + transition: color 200ms ease; +} + +#toc li a:hover, +#toc li a.active { + color: var(--accent-color); +} + +#toc::before { + content: ""; + display: block; + position: absolute; + left: 16px; + top: 20px; + width: 2px; + height: calc(100% - 40px); + background: rgba(255, 255, 255, 0.1); +} \ No newline at end of file