From 4206bdc115e83ff4e3da0040c3f263fe6fb39735 Mon Sep 17 00:00:00 2001 From: Wael Nasreddine Date: Fri, 23 Jan 2026 15:43:29 -0800 Subject: [PATCH 1/2] feat(share-theme): set minimum width for table cells to improve readability --- packages/share-theme/src/styles/content.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/share-theme/src/styles/content.css b/packages/share-theme/src/styles/content.css index 38547dc3e..25804ebbe 100644 --- a/packages/share-theme/src/styles/content.css +++ b/packages/share-theme/src/styles/content.css @@ -80,3 +80,9 @@ body.type-webView { } } } + +/* table styles */ +.ck-content table td, +.ck-content table th { + min-width: 120px; +} From b70ec18732a7c62cff59831a0c2400b4897de380 Mon Sep 17 00:00:00 2001 From: Wael Nasreddine Date: Fri, 23 Jan 2026 15:43:40 -0800 Subject: [PATCH 2/2] feat(share-theme): align mobile/desktop UI with unified header --- packages/share-theme/src/scripts/index.ts | 2 + .../share-theme/src/scripts/modules/mobile.ts | 26 +++--- .../src/scripts/modules/sidebar.ts | 32 +++++++ packages/share-theme/src/styles/layout.css | 71 +++++++++++++-- packages/share-theme/src/styles/mobile.css | 90 ++++++++++++------- .../share-theme/src/styles/navbar/header.css | 9 +- packages/share-theme/src/styles/toc.css | 23 ++++- packages/share-theme/src/templates/page.ejs | 24 +++-- 8 files changed, 207 insertions(+), 70 deletions(-) create mode 100644 packages/share-theme/src/scripts/modules/sidebar.ts diff --git a/packages/share-theme/src/scripts/index.ts b/packages/share-theme/src/scripts/index.ts index 4769ea76e..89d368a96 100644 --- a/packages/share-theme/src/scripts/index.ts +++ b/packages/share-theme/src/scripts/index.ts @@ -5,6 +5,7 @@ import setupSearch from "./modules/search.js"; import setupThemeSelector from "./modules/theme.js"; import setupMermaid from "./modules/mermaid.js"; import setupMath from "./modules/math.js"; +import setupSidebars from "./modules/sidebar.js"; import api from "./modules/api.js"; import "highlight.js/styles/default.css"; import "@triliumnext/ckeditor5/src/theme/ck-content.css"; @@ -24,6 +25,7 @@ $try(setupToC); $try(setupExpanders); $try(setupMobileMenu); $try(setupSearch); +$try(setupSidebars); function setupTextNote() { $try(setupMermaid); diff --git a/packages/share-theme/src/scripts/modules/mobile.ts b/packages/share-theme/src/scripts/modules/mobile.ts index f311f5618..69611c63e 100644 --- a/packages/share-theme/src/scripts/modules/mobile.ts +++ b/packages/share-theme/src/scripts/modules/mobile.ts @@ -2,24 +2,24 @@ import parents from "../common/parents.js"; 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"); + function closeMobileMenus() { + document.body.classList.remove("menu-open"); + document.body.classList.remove("toc-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 + const isMenuOpen = document.body.classList.contains("menu-open"); + const isTocOpen = document.body.classList.contains("toc-open"); + if (!isMenuOpen && !isTocOpen) return; - // If the click was anywhere in the mobile nav, don't close + // If the click was anywhere in the mobile nav or TOC, don't close if (parents(e.target as HTMLElement, "#left-pane").length) return; - return toggleMobileMenu(e); + if (parents(e.target as HTMLElement, "#toc-pane").length) return; + + // If the click was on one of the toggle buttons, the button's own listener will handle it + if (parents(e.target as HTMLElement, ".header-button").length) return; + + return closeMobileMenus(); }); } diff --git a/packages/share-theme/src/scripts/modules/sidebar.ts b/packages/share-theme/src/scripts/modules/sidebar.ts new file mode 100644 index 000000000..0cf70af94 --- /dev/null +++ b/packages/share-theme/src/scripts/modules/sidebar.ts @@ -0,0 +1,32 @@ +export default function setupSidebars() { + const splitPane = document.getElementById("split-pane"); + + const leftToggle = document.getElementById("left-pane-toggle-button"); + const tocToggle = document.getElementById("toc-pane-toggle-button"); + + if (leftToggle && splitPane) { + leftToggle.addEventListener("click", () => { + const isMobile = window.innerWidth <= 768; // 48em + if (isMobile) { + document.body.classList.toggle("menu-open"); + document.body.classList.remove("toc-open"); + } else { + const isCollapsed = splitPane.classList.toggle("left-pane-collapsed"); + localStorage.setItem("left-pane-collapsed", isCollapsed ? "true" : "false"); + } + }); + } + + if (tocToggle && splitPane) { + tocToggle.addEventListener("click", () => { + const isMobile = window.innerWidth <= 768; // 48em + if (isMobile) { + document.body.classList.toggle("toc-open"); + document.body.classList.remove("menu-open"); + } else { + const isCollapsed = splitPane.classList.toggle("toc-pane-collapsed"); + localStorage.setItem("toc-pane-collapsed", isCollapsed ? "true" : "false"); + } + }); + } +} diff --git a/packages/share-theme/src/styles/layout.css b/packages/share-theme/src/styles/layout.css index 46cabca6e..e63ee76d3 100644 --- a/packages/share-theme/src/styles/layout.css +++ b/packages/share-theme/src/styles/layout.css @@ -2,28 +2,76 @@ html, body { width: 100vw; height: 100vh; + overflow: hidden; +} + +body { + display: flex; + flex-direction: column; } #split-pane { display: flex; flex-direction: row; width: 100vw; - height: 100vh; + flex: 1; overflow: hidden; } #left-pane { display: flex; - min-width: fit-content; - max-width: 20vw; - height: calc(100vh); + flex-direction: column; + min-width: 0; + width: 20vw; + height: 100%; background: var(--background-secondary); border-right: 5px solid var(--background-highlight); - justify-content: flex-end; + justify-content: flex-start; position: sticky; top: 0; overflow-y: auto; flex-shrink: 0; + transition: width 0.3s ease, margin-left 0.3s ease; +} + +.left-pane-collapsed #left-pane { + width: 0; + min-width: 0; + margin-left: -5px; /* offset the border */ + overflow: hidden; + border-right-width: 0; +} + +.pane-toggle { + position: absolute; + top: 60px; + background: var(--background-highlight); + border: none; + color: var(--text-primary); + width: 24px; + height: 48px; + cursor: pointer; + z-index: 100; + display: none; /* Hide standard toggles, using header buttons instead */ + align-items: center; + justify-content: center; + padding: 0; + border-radius: 0 4px 4px 0; + opacity: 0.5; + transition: opacity 0.2s ease, left 0.3s ease, right 0.3s ease; +} + +.pane-toggle:hover { + opacity: 1; +} + +#left-pane-toggle { + left: 20vw; +} + +#toc-pane-toggle { + left: -24px; + border-radius: 4px 0 0 4px; } #right-pane { @@ -31,6 +79,7 @@ body { margin: 0 auto; flex: 1; overflow: auto; + position: relative; } #main { @@ -40,10 +89,20 @@ body { padding: 0 20px; box-sizing: border-box; width: 100%; + transition: max-width 0.3s ease; +} + +.left-pane-collapsed #main, +.toc-pane-collapsed #main { + max-width: 1100px; +} + +.left-pane-collapsed.toc-pane-collapsed #main { + max-width: 100%; } @media (min-width: 1200px) { #main { padding: 0 50px; } -} \ No newline at end of file +} diff --git a/packages/share-theme/src/styles/mobile.css b/packages/share-theme/src/styles/mobile.css index 3b8d95051..bd6ad056f 100644 --- a/packages/share-theme/src/styles/mobile.css +++ b/packages/share-theme/src/styles/mobile.css @@ -1,82 +1,104 @@ -#mobile-header { - display: none; +#header { background: var(--background-secondary); + display: flex; justify-content: space-between; align-items: center; padding: 6px 12px; + border-bottom: 1px solid var(--background-highlight); } -#mobile-header a { +#header-logo { display: flex; align-items: center; gap: 5px; + font-weight: bold; } -#mobile-header a img { +#header-logo img { max-width: 32px; } -#mobile-header button { +.header-button { color: var(--text-menu); background: transparent; margin: 0; - padding: 0; + padding: 4px; border: 0; outline: 0; display: flex; align-items: center; cursor: pointer; border-radius: 6px; - transform: rotate(0); transition: background-color 200ms ease, transform 200ms ease; } +.header-button:hover { + background-color: var(--background-highlight); +} +.header-button-placeholder { + width: 32px; +} @media (max-width: 48em) { - + html, body { - width: unset; - height: unset; + height: 100%; } #split-pane { - overflow: auto; + overflow: hidden; } #right-pane, #main { width: 100%; padding: 0; } - + #main { padding: 1rem; } - - #mobile-header { - display: flex; - } - - #mobile-header button svg { + + #header .header-button svg { width: 32px; height: 32px; } - - #left-pane { + + #left-pane, #toc-pane { position: fixed; top: 0; - left: 0; - width: auto; - transform: translateX(-100%); + bottom: 0; + width: 80%; + max-width: 300px; + background: var(--background-secondary); transition: transform 200ms ease; z-index: 2; + overflow-y: auto; } - - .menu-open #left-pane { + + #left-pane { + left: 0; + transform: translateX(-100%); + } + + #toc-pane { + display: flex !important; + right: 0; + transform: translateX(100%); + padding: 20px; + } + + #toc-pane h3, + #toc-pane #toc { + display: block !important; + } + + .menu-open #left-pane, + .toc-open #toc-pane { transform: translateX(0); } - + body::before { content: ""; display: block; @@ -90,14 +112,14 @@ transition: background-color 200ms ease; z-index: 1; } - - body.menu-open::before { + + body.menu-open::before, + body.toc-open::before { background: rgba(0,0,0, 0.6); + pointer-events: auto; } - - - body.menu-open #show-menu-button { - background: var(--background-highlight); - transform: rotate(90deg); + + .toc-pane-collapsed #toc-pane { + width: 80%; /* Don't collapse to 0 on mobile */ } -} \ No newline at end of file +} diff --git a/packages/share-theme/src/styles/navbar/header.css b/packages/share-theme/src/styles/navbar/header.css index 0cb93c2c2..c29cc2c5a 100644 --- a/packages/share-theme/src/styles/navbar/header.css +++ b/packages/share-theme/src/styles/navbar/header.css @@ -4,13 +4,6 @@ gap: 20px; } -#site-header > a { - display: flex; - align-items: center; - justify-content: center; - gap: 10px; -} - /* The switch - the box around the slider */ .switch { @@ -138,4 +131,4 @@ input:checked ~ .dark-icon { position: absolute; width: 20px; left: 5px; -} \ No newline at end of file +} diff --git a/packages/share-theme/src/styles/toc.css b/packages/share-theme/src/styles/toc.css index 3e02d6577..4ab2972a1 100644 --- a/packages/share-theme/src/styles/toc.css +++ b/packages/share-theme/src/styles/toc.css @@ -5,7 +5,26 @@ position: sticky; top: 0; order: 3; -/* padding: 16px 16px 16px 32px; */ + transition: width 0.3s ease, margin-right 0.3s ease; + width: 250px; +} + +.toc-pane-collapsed #toc-pane { + width: 0; +} + +.toc-pane-collapsed #toc-pane h3, +.toc-pane-collapsed #toc-pane #toc { + display: none !important; +} + +.toc-pane-collapsed #toc-pane-toggle { + right: 0; + left: auto; +} + +.toc-pane-collapsed #toc-pane-toggle svg { + transform: rotate(180deg); } #toc-pane h3 { @@ -91,4 +110,4 @@ #toc-pane { display: none; } -} \ No newline at end of file +} diff --git a/packages/share-theme/src/templates/page.ejs b/packages/share-theme/src/templates/page.ejs index 7d387cff3..8cf75215f 100644 --- a/packages/share-theme/src/templates/page.ejs +++ b/packages/share-theme/src/templates/page.ejs @@ -66,6 +66,13 @@ isStatic: <%= !!isStatic %>, theme }; + + (function() { + const leftCollapsed = localStorage.getItem("left-pane-collapsed") === "true"; + const tocCollapsed = localStorage.getItem("toc-pane-collapsed") === "true"; + if (leftCollapsed) document.documentElement.classList.add("left-pane-collapsed"); + if (tocCollapsed) document.documentElement.classList.add("toc-pane-collapsed"); + })(); "> @@ -104,21 +111,23 @@ content = content.replaceAll(headingRe, (...match) => { %> <%- renderSnippets("body:start") %> -
- +
+