mirror of
https://github.com/zadam/trilium.git
synced 2026-02-26 16:43:36 +01:00
Merge b70ec18732a7c62cff59831a0c2400b4897de380 into bbf090edf017e4040d09faeb9a208f9903f6fd40
This commit is contained in:
commit
f70ddb20ad
@ -5,6 +5,7 @@ import setupSearch from "./modules/search.js";
|
|||||||
import setupThemeSelector from "./modules/theme.js";
|
import setupThemeSelector from "./modules/theme.js";
|
||||||
import setupMermaid from "./modules/mermaid.js";
|
import setupMermaid from "./modules/mermaid.js";
|
||||||
import setupMath from "./modules/math.js";
|
import setupMath from "./modules/math.js";
|
||||||
|
import setupSidebars from "./modules/sidebar.js";
|
||||||
import api from "./modules/api.js";
|
import api from "./modules/api.js";
|
||||||
import "highlight.js/styles/default.css";
|
import "highlight.js/styles/default.css";
|
||||||
import "@triliumnext/ckeditor5/src/theme/ck-content.css";
|
import "@triliumnext/ckeditor5/src/theme/ck-content.css";
|
||||||
@ -24,6 +25,7 @@ $try(setupToC);
|
|||||||
$try(setupExpanders);
|
$try(setupExpanders);
|
||||||
$try(setupMobileMenu);
|
$try(setupMobileMenu);
|
||||||
$try(setupSearch);
|
$try(setupSearch);
|
||||||
|
$try(setupSidebars);
|
||||||
|
|
||||||
function setupTextNote() {
|
function setupTextNote() {
|
||||||
$try(setupMermaid);
|
$try(setupMermaid);
|
||||||
|
|||||||
@ -2,24 +2,24 @@ import parents from "../common/parents.js";
|
|||||||
|
|
||||||
|
|
||||||
export default function setupMobileMenu() {
|
export default function setupMobileMenu() {
|
||||||
function toggleMobileMenu(event: MouseEvent) {
|
function closeMobileMenus() {
|
||||||
event.stopPropagation(); // Don't prevent default for links
|
document.body.classList.remove("menu-open");
|
||||||
|
document.body.classList.remove("toc-open");
|
||||||
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 => {
|
window.addEventListener("click", e => {
|
||||||
const isOpen = document.body.classList.contains("menu-open");
|
const isMenuOpen = document.body.classList.contains("menu-open");
|
||||||
if (!isOpen) return; // This listener is only to close
|
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;
|
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();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
32
packages/share-theme/src/scripts/modules/sidebar.ts
Normal file
32
packages/share-theme/src/scripts/modules/sidebar.ts
Normal file
@ -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");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -80,3 +80,9 @@ body.type-webView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* table styles */
|
||||||
|
.ck-content table td,
|
||||||
|
.ck-content table th {
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|||||||
@ -2,28 +2,76 @@ html,
|
|||||||
body {
|
body {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
#split-pane {
|
#split-pane {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#left-pane {
|
#left-pane {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-width: fit-content;
|
flex-direction: column;
|
||||||
max-width: 20vw;
|
min-width: 0;
|
||||||
height: calc(100vh);
|
width: 20vw;
|
||||||
|
height: 100%;
|
||||||
background: var(--background-secondary);
|
background: var(--background-secondary);
|
||||||
border-right: 5px solid var(--background-highlight);
|
border-right: 5px solid var(--background-highlight);
|
||||||
justify-content: flex-end;
|
justify-content: flex-start;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
flex-shrink: 0;
|
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 {
|
#right-pane {
|
||||||
@ -31,6 +79,7 @@ body {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main {
|
#main {
|
||||||
@ -40,6 +89,16 @@ body {
|
|||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 100%;
|
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) {
|
@media (min-width: 1200px) {
|
||||||
|
|||||||
@ -1,48 +1,54 @@
|
|||||||
#mobile-header {
|
#header {
|
||||||
display: none;
|
|
||||||
background: var(--background-secondary);
|
background: var(--background-secondary);
|
||||||
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
|
border-bottom: 1px solid var(--background-highlight);
|
||||||
}
|
}
|
||||||
|
|
||||||
#mobile-header a {
|
#header-logo {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mobile-header a img {
|
#header-logo img {
|
||||||
max-width: 32px;
|
max-width: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mobile-header button {
|
.header-button {
|
||||||
color: var(--text-menu);
|
color: var(--text-menu);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 4px;
|
||||||
border: 0;
|
border: 0;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
transform: rotate(0);
|
|
||||||
transition: background-color 200ms ease, transform 200ms ease;
|
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) {
|
@media (max-width: 48em) {
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
width: unset;
|
height: 100%;
|
||||||
height: unset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#split-pane {
|
#split-pane {
|
||||||
overflow: auto;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#right-pane, #main {
|
#right-pane, #main {
|
||||||
@ -54,26 +60,42 @@
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mobile-header {
|
#header .header-button svg {
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mobile-header button svg {
|
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#left-pane {
|
#left-pane, #toc-pane {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
bottom: 0;
|
||||||
width: auto;
|
width: 80%;
|
||||||
transform: translateX(-100%);
|
max-width: 300px;
|
||||||
|
background: var(--background-secondary);
|
||||||
transition: transform 200ms ease;
|
transition: transform 200ms ease;
|
||||||
z-index: 2;
|
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);
|
transform: translateX(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,13 +113,13 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.menu-open::before {
|
body.menu-open::before,
|
||||||
|
body.toc-open::before {
|
||||||
background: rgba(0,0,0, 0.6);
|
background: rgba(0,0,0, 0.6);
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toc-pane-collapsed #toc-pane {
|
||||||
body.menu-open #show-menu-button {
|
width: 80%; /* Don't collapse to 0 on mobile */
|
||||||
background: var(--background-highlight);
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,13 +4,6 @@
|
|||||||
gap: 20px;
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#site-header > a {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* The switch - the box around the slider */
|
/* The switch - the box around the slider */
|
||||||
.switch {
|
.switch {
|
||||||
|
|||||||
@ -5,7 +5,26 @@
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
order: 3;
|
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 {
|
#toc-pane h3 {
|
||||||
|
|||||||
@ -66,6 +66,13 @@
|
|||||||
isStatic: <%= !!isStatic %>,
|
isStatic: <%= !!isStatic %>,
|
||||||
theme
|
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");
|
||||||
|
})();
|
||||||
</script>
|
</script>
|
||||||
<!-- HTML Meta Tags -->
|
<!-- HTML Meta Tags -->
|
||||||
<meta name="description" content="<%= note.getLabelValue("shareDescription") %>">
|
<meta name="description" content="<%= note.getLabelValue("shareDescription") %>">
|
||||||
@ -104,21 +111,23 @@ content = content.replaceAll(headingRe, (...match) => {
|
|||||||
%>
|
%>
|
||||||
<body data-note-id="<%= note.noteId %>" class="type-<%= note.type %>" data-ancestor-note-id="<%= subRoot.note.noteId %>">
|
<body data-note-id="<%= note.noteId %>" class="type-<%= note.type %>" data-ancestor-note-id="<%= subRoot.note.noteId %>">
|
||||||
<%- renderSnippets("body:start") %>
|
<%- renderSnippets("body:start") %>
|
||||||
<div id="mobile-header">
|
<div id="header">
|
||||||
<a href="<%= shareRootLink %>">
|
<button aria-label="Toggle Navigation" id="left-pane-toggle-button" class="header-button"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z"></path></svg></button>
|
||||||
|
<a href="<%= shareRootLink %>" id="header-logo">
|
||||||
<img src="<%= logoUrl %>" width="32" height="<%= mobileLogoHeight %>" alt="Logo" />
|
<img src="<%= logoUrl %>" width="32" height="<%= mobileLogoHeight %>" alt="Logo" />
|
||||||
<%= subRoot.note.title %>
|
<%= subRoot.note.title %>
|
||||||
</a>
|
</a>
|
||||||
<button aria-label="Show Mobile Menu" id="show-menu-button"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z"></path></svg></button>
|
<% if (headingMatches.length > 1) { %>
|
||||||
|
<button aria-label="Toggle Table of Contents" id="toc-pane-toggle-button" class="header-button"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2zm0-10V7h2v2h-2zm0 6h2v-2h-2v2z"></path></svg></button>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="header-button-placeholder"></div>
|
||||||
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
<div id="split-pane">
|
<div id="split-pane">
|
||||||
|
<button id="left-pane-toggle" class="pane-toggle" aria-label="Toggle Navigation"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"></path></svg></button>
|
||||||
<div id="left-pane">
|
<div id="left-pane">
|
||||||
<div id="navigation">
|
<div id="navigation">
|
||||||
<div id="site-header">
|
<div id="site-header">
|
||||||
<a href="<%= shareRootLink %>">
|
|
||||||
<img src="<%= logoUrl %>" width="<%= logoWidth %>" height="<%= logoHeight %>" alt="Logo" />
|
|
||||||
<%= subRoot.note.title %>
|
|
||||||
</a>
|
|
||||||
<div class="theme-selection">
|
<div class="theme-selection">
|
||||||
<span id="sitetheme"><%= t("share_theme.site-theme") %></span>
|
<span id="sitetheme"><%= t("share_theme.site-theme") %></span>
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
@ -223,6 +232,7 @@ content = content.replaceAll(headingRe, (...match) => {
|
|||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
<div id="toc-pane">
|
<div id="toc-pane">
|
||||||
|
<button id="toc-pane-toggle" class="pane-toggle" aria-label="Toggle Table of Contents"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"></path></svg></button>
|
||||||
<h3><%= t("share_theme.on-this-page") %></h3>
|
<h3><%= t("share_theme.on-this-page") %></h3>
|
||||||
<ul id="toc">
|
<ul id="toc">
|
||||||
<% for (const entry of toc) { %>
|
<% for (const entry of toc) { %>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user