Skip to content

Instantly share code, notes, and snippets.

@solarkraft
Last active March 2, 2024 12:08
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save solarkraft/b05e9058ca2cda40a4d6e03c52dff025 to your computer and use it in GitHub Desktop.
Save solarkraft/b05e9058ca2cda40a4d6e03c52dff025 to your computer and use it in GitHub Desktop.
Logseq custom.css for publishing
/*** 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 });
});
@candideu
Copy link

Where should interact.js be placed?

@solarkraft
Copy link
Author

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).

@candideu
Copy link

@solarkraft So I should generate the web export first, and then add this file?

@solarkraft
Copy link
Author

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.

@candideu
Copy link

Hey @solarkraft ! Do you know how solve this with CSS?

logseq/logseq#6066

@solarkraft
Copy link
Author

@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
Copy link

@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.

@iamkroot
Copy link

iamkroot commented Nov 4, 2022

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; }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment