-
-
Save solarkraft/b05e9058ca2cda40a4d6e03c52dff025 to your computer and use it in GitHub Desktop.
| /*** Publishing: Hide things that aren't very useful for a read-only view */ | |
| /** Hide page properties (public pages will always have public: true) */ | |
| .content .pre-block { display: none; } | |
| /** Title */ | |
| /* Make title non-editable */ | |
| #main-container .page-title { pointer-events: none; } | |
| /** Hide useless sidebar stuff */ | |
| .nav-header .flashcards-nav { display: none; } | |
| .nav-header .journals-nav { display: none; } | |
| /*.nav-header .graph-view-nav { display: none; }*/ | |
| /** Header */ | |
| /* Hide right side of header buttons (only useful setting is light/dark theme and can still be done using tt, graph is somewhat broken, home is covered by "All Pages") */ | |
| #head div.r { display: none; } | |
| /** All pages */ | |
| /* Hide selection checkbox (nothing can be done with it) */ | |
| .cp__all_pages table .selector { display: none; } | |
| /* Hide more columns (not that they don't work, they just don't seem very useful) */ | |
| .cp__all_pages table .backlinks { display: none; } | |
| .cp__all_pages table .created-at { display: none; } | |
| /* Hide delete button */ | |
| .cp__all_pages .actions .actions-wrap { display: none; } | |
| /* Hide more page modification options/things that don't work */ | |
| .cp__all_pages .actions div.r { display: none; } | |
| /* Fix search bar spacing */ | |
| .cp__all_pages .actions .search-wrap { margin-left: 0; padding-left: 0; } | |
| /** Image */ | |
| /* Remove delete button */ | |
| a.delete { display: none; } | |
| /* Disable resizing */ | |
| .resize { resize:none; } | |
| /** Hide graph settings (they're ineffective, only the desktop app's while exporting seem to matter, search doesn't work either) */ | |
| .graph-filters { display: none; } | |
| /** Hide recent pages (seems to be ineffective on web)*/ | |
| .nav-content-item.recent { display: none; } | |
| /* Hide context menu (mostly ineffective) */ | |
| #custom-context-menu { display: none; } | |
| /** Disable dragging of blocks (also disables zooming) */ | |
| .ls-block > div > div > a:not(.block-control) { pointer-events: none; } | |
| /** Remove superfluous spacing on block embeds in Firefox */ | |
| .block-content.inline { white-space: revert; } |
| // Interact.js (https://interactjs.io/) is for editing gestures we don't need in a read-only version anyway, | |
| // so let's hijack it for our purposes. | |
| console.debug("Hijacked :-)"); | |
| let page_title = "Lamentable Technology"; | |
| let start_page = "start"; | |
| // This script is loaded before main.js (which is huge), so we can inject a loading message heee. | |
| let loaderImage = "data:image/svg+xml,%3Csvg width='44' height='44' viewBox='0 0 44 44' xmlns='http://www.w3.org/2000/svg' stroke='%23ccc'%3E%3Cg fill='none' fill-rule='evenodd' stroke-width='2'%3E%3Ccircle cx='22' cy='22' r='1'%3E%3Canimate attributeName='r' begin='0s' dur='1.8s' values='1; 20' calcMode='spline' keyTimes='0; 1' keySplines='0.165, 0.84, 0.44, 1' repeatCount='indefinite' /%3E%3Canimate attributeName='stroke-opacity' begin='0s' dur='1.8s' values='1; 0' calcMode='spline' keyTimes='0; 1' keySplines='0.3, 0.61, 0.355, 1' repeatCount='indefinite' /%3E%3C/circle%3E%3Ccircle cx='22' cy='22' r='1'%3E%3Canimate attributeName='r' begin='-0.9s' dur='1.8s' values='1; 20' calcMode='spline' keyTimes='0; 1' keySplines='0.165, 0.84, 0.44, 1' repeatCount='indefinite' /%3E%3Canimate attributeName='stroke-opacity' begin='-0.9s' dur='1.8s' values='1; 0' calcMode='spline' keyTimes='0; 1' keySplines='0.3, 0.61, 0.355, 1' repeatCount='indefinite' /%3E%3C/circle%3E%3C/g%3E%3C/svg%3E"; | |
| let root = document.childNodes[1].childNodes[1].childNodes[0]; | |
| root.innerHTML = `<div class="loading"><span>Logseq is loading ...</span><span class="apology">Sorry about the current size of the bundle. We\'re working on slimming it down. </span><img src="${loaderImage}"/></div>`; | |
| // Add styles that become relevant when this injection is active | |
| let styles = ` | |
| .title { | |
| font-size: 1.2em; | |
| color: var(--ls-primary-text-color); | |
| } | |
| #head .button.title { opacity: 1; } | |
| /* Add margin the hamburger button used to have to the head area */ | |
| #head > .l { margin-left: .4rem; } | |
| /* Loader */ | |
| #root .loading { | |
| color: darkgray; | |
| margin-top: 20vh; | |
| margin-left: 2rem; | |
| margin-right: 2rem; | |
| font-size: 2.5rem; | |
| text-align: center; | |
| } | |
| #root .loading span { | |
| display: block; | |
| line-height: 1.5em; | |
| margin-bottom: 1rem; | |
| } | |
| #root .loading .apology { font-size: .3em; } | |
| #root .loading img { height: 8rem; margin-top: 3rem; } | |
| /* Page title in header */ | |
| #head .page-title { | |
| display: block; | |
| overflow: hidden; | |
| transition: width 1s; | |
| } | |
| `; | |
| let styleSheet = document.createElement("style"); | |
| styleSheet.type = "text/css"; | |
| styleSheet.innerText = styles; | |
| document.head.appendChild(styleSheet); | |
| let redirect = () => { | |
| let hash = window.location.hash; | |
| console.debug("Page hash:", hash); | |
| // Start page redirect (otherweise Logseq opens either the "All Pages" view or the latest Journal page if no page is provided) | |
| if (!hash || hash == "#" || hash == "#/") { | |
| console.debug("Start page redirect"); | |
| window.location.hash = `#/page/${start_page}`; | |
| } | |
| // "All pages" view on #/page/ (equivalent of index) | |
| if (hash == "#/page" || hash == "#/page/") { | |
| console.debug("All pages redirect"); | |
| window.location.hash = "#/all-pages"; | |
| } | |
| // Todo: Something about "404" pages | |
| } | |
| let showOrHideHeadPageTitle = () => { | |
| let el = document.getElementById("main-content-container"); | |
| if(!el) return; | |
| // Yup, that's slow | |
| let title = document.querySelector("#main-content-container .page-title"); | |
| let headTitle = document.querySelector("#head .page-title"); | |
| let y = title.getBoundingClientRect().y; | |
| let titleInView = y > 0; | |
| headTitle.style.width = titleInView? "0px" : headerPageTitleOriginalWidth + "px"; | |
| }; | |
| // Update the page title in the header | |
| let headerPageTitleOriginalWidth; | |
| let updatePageTitle = () => { | |
| let headButtons = document.querySelector("#head > .l"); | |
| // Remove old element if it already exists | |
| document.querySelector("#head .page-title")?.remove(); | |
| let pageTitle = document.title || ""; // hacky indeed | |
| headPageTitle = document.createElement("div"); | |
| headPageTitle.innerHTML = `<a class="title page-title" href="${window.location}">${pageTitle}</a>`; | |
| // After title | |
| headButtons?.insertBefore(headPageTitle, document.querySelector("#head .title").parentNode.nextSibling); | |
| // Title width | |
| headerPageTitleOriginalWidth = headPageTitle.getBoundingClientRect().width; | |
| showOrHideHeadPageTitle(); | |
| }; | |
| let onPageChange = () => { | |
| redirect(); | |
| updatePageTitle(); | |
| }; | |
| onPageChange(); | |
| // window.addEventListener('hashchange', () => onPageChange()); | |
| // hashchange doesn't reliably fire for some reason ... Yep, it's getting hackier and hackier. :-) | |
| new MutationObserver(() => { onPageChange(); }).observe(document.querySelector('title'), { childList: true }); | |
| window.addEventListener("load", () => { | |
| // If you explicitly set it I have to explicitly reset it ... | |
| document.querySelector("#head").style.fontSize = ""; | |
| // Add title | |
| let headButtons = document.querySelector("#head > .l"); | |
| let title = document.createElement("div"); | |
| title.innerHTML = `<a href="#/page/start" class="button title">${page_title}</a>` | |
| headButtons.prepend(title); | |
| // Remove hamburger menu button because now the title can navigate to the start page | |
| // To do: Re-add Graph view and All pages | |
| document.getElementById("left-menu").parentElement.remove(); | |
| //// Cool title-in-header effect | |
| // Add page name to header | |
| updatePageTitle(); | |
| // Title width | |
| let lastScroll = 0; | |
| document.getElementById("main-content-container").addEventListener("scroll", ev => { | |
| showOrHideHeadPageTitle(); | |
| }, { passive: true }); | |
| }); |
Thanks for your interest!
interact.js is located in static/js/ in your web export. You can replace it with the file provided here because it's not needed for a read-only version (and there is no other way to get "custom.js" file into an export that I am aware of so far).
@solarkraft So I should generate the web export first, and then add this file?
Yep! That means you either need to do it after every export or write-protect the file. I have added an ignore rule to Syncthing so the original Logseq versions of these files don't get copied over to the server.
Hey @solarkraft ! Do you know how solve this with CSS?
@candideu I haven't used this in a while so I'm not sure whether it still works, but I initially solved this using #main-container .page-title { pointer-events: none; }.
@candideu I haven't used this in a while so I'm not sure whether it still works, but I initially solved this using
#main-container .page-title { pointer-events: none; }.
It still appears to work. Thanks again for this Gist, it's been invaluable to my project.
Also added this:
/* Make TODO non-clickable */
span:is(.todo, .done) > :is(.marker-switch, input) { pointer-events: none; }
/* Make block ref icon non-clickable, clicking causes a crash for some reason */
.open-block-ref-link { pointer-events: none; }
Where should interact.js be placed?