I have changed the code, now the script uses cssClass. You can activate the “read view” (i.e. hide Publish page elements, including sidebars for reading or for a clean image browsing) in 4 different ways:
- using a button
- pressing the “r” key
- by defining the reader-view class in the cssClass property in the frontmatter
- adding ?reader=true to the url of the page.
Demo: normal site or reader-view
Problem with sliding-window
In the normal version of Publish it works perfectly, but there is a wrong behavior in the sliding-window version: browsing the web with the “reader-view” activated, when clicking the name of the site to return to the home page, it removes the class and returns to the “normal” state, although in localStorage the “reader-view” state persists. In fact, once returned to the home page from the web logo, and reload page, it reads the localStorage and reactivates the “reader-view”.
I don’t know if I’ve explained myself well… maybe someone will want to get their hands on it at some point…
JS
// READER VIEW
// Iconos SVG para los estados visible y oculto
const iconVisible = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize-2"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" x2="14" y1="3" y2="10"/><line x1="3" x2="10" y1="21" y2="14"/></svg>`; // SVG para cuando las sidebars están visibles
const iconHidden = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-minimize-2"><polyline points="4 14 10 14 10 20"/><polyline points="20 10 14 10 14 4"/><line x1="14" x2="21" y1="10" y2="3"/><line x1="3" x2="10" y1="21" y2="14"/></svg>`; // SVG para cuando las sidebars están ocultas
// Función para alternar la clase 'reader-view' en todas las instancias de .markdown-preview-view
function toggleReaderView() {
const markdownPreviews = document.querySelectorAll('.markdown-preview-view');
const toggleButton = document.querySelector('#toggle-sidebar-btn');
if (markdownPreviews.length > 0 && toggleButton) {
const isReaderView = Array.from(markdownPreviews).some(preview => preview.classList.contains('reader-view'));
markdownPreviews.forEach(preview => {
if (isReaderView) {
preview.classList.remove('reader-view');
} else {
preview.classList.add('reader-view');
}
});
// Cambia el icono del botón según el estado de la clase 'reader-view'
toggleButton.innerHTML = isReaderView ? iconVisible : iconHidden;
// Guardar el estado en localStorage
localStorage.setItem('readerView', !isReaderView);
}
}
// Añadir un evento de escucha para la tecla "r"
document.addEventListener('keydown', function(event) {
const activeElement = document.activeElement;
const isSearchInputFocused = activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA');
if (event.key === 'r' && !event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey && !isSearchInputFocused) {
toggleReaderView();
}
});
// Función para verificar y aplicar el estado de visibilidad inicial
function applyInitialVisibilityState() {
const markdownPreviews = document.querySelectorAll('.markdown-preview-view');
const toggleButton = document.querySelector('#toggle-sidebar-btn');
// Obtener el estado de localStorage
const isReaderView = localStorage.getItem('readerView') === 'true';
markdownPreviews.forEach(preview => {
if (isReaderView) {
preview.classList.add('reader-view');
} else {
preview.classList.remove('reader-view');
}
});
toggleButton.innerHTML = isReaderView ? iconHidden : iconVisible;
}
// Función para crear y añadir el botón de alternar al .site-body-center-column
function addToggleButton() {
const siteBodyCenterColumn = document.querySelector('.site-body-center-column');
if (siteBodyCenterColumn) {
// Crea el botón
const toggleButton = document.createElement('button');
toggleButton.id = 'toggle-sidebar-btn';
toggleButton.setAttribute('aria-label', 'Toggle reader view');
// Establece el icono inicial del botón
toggleButton.innerHTML = iconVisible;
// Añade el evento de clic al botón
toggleButton.addEventListener('click', toggleReaderView);
// Añade el botón al .site-body-center-column
siteBodyCenterColumn.appendChild(toggleButton);
}
}
// Función para iniciar el observador de mutaciones
function waitForSiteBodyCenterColumn() {
const observer = new MutationObserver((mutations, obs) => {
if (document.querySelector('.site-body-center-column')) {
addToggleButton();
applyInitialVisibilityState(); // Aplica el estado de visibilidad inicial
obs.disconnect(); // Detiene el observador una vez que el .site-body-center-column ha sido encontrado
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
}
// Función para verificar el parámetro de la URL y activar el reader-view si es necesario
function checkURLParameter() {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('reader') === 'true') {
const markdownPreviews = document.querySelectorAll('.markdown-preview-view');
markdownPreviews.forEach(preview => {
preview.classList.add('reader-view');
});
// Actualizar el icono del botón
const toggleButton = document.querySelector('#toggle-sidebar-btn');
if (toggleButton) {
toggleButton.innerHTML = iconHidden;
}
// Guardar el estado en localStorage
localStorage.setItem('readerView', true);
}
}
// Función para restablecer el estado de la vista de lectura después de la navegación
function resetReaderViewAfterNavigation() {
document.addEventListener('click', (event) => {
if (event.target.closest('.site-body-left-column-site-logo, .nav-file-title, .nav-folder-title, .nav-file, .nav-folder')) {
setTimeout(applyInitialVisibilityState, 100); // Espera un momento para que la navegación se complete
}
});
}
// Función para restablecer el estado de la vista de lectura después de la carga completa de la página
function resetReaderViewOnLoad() {
window.addEventListener('load', applyInitialVisibilityState);
}
// Ejecuta la función waitForSiteBodyCenterColumn cuando el script se carga
waitForSiteBodyCenterColumn();
// Verifica el parámetro de la URL al cargar la página
checkURLParameter();
// Restablece el estado de la vista de lectura después de la navegación
resetReaderViewAfterNavigation();
// Restablece el estado de la vista de lectura después de la carga completa de la página
resetReaderViewOnLoad();
// END TOGGLE READER VIEW
CSS
/************************ READER ************************/
@media screen and (min-width: 751px) {
#toggle-sidebar-btn {
margin: 0px;
width: 30px;
background: none;
padding: 5px;
position: fixed;
right: 5px;
top: 5px;
background: none;
border-radius: 50%;
background: var(--background-primary);
opacity: 1;
color: var(--component-title-color);
z-index: 100;
}
.sliding-windows #toggle-sidebar-btn {
right: 287px;
top: 25px;
}
#toggle-sidebar-btn:hover {
color: var(--color-base-100);
background: var(--background-secondary);
}
#toggle-sidebar-btn:hover {
cursor: pointer;
}
.theme-dark #toggle-sidebar-btn {
top: 25px;
}
.site-body:has(.reader-view) #toggle-sidebar-btn {
color: var(--component-title-color);
}
.site-body:has(.reader-view) #toggle-sidebar-btn::before {
content: "Press r to switch view";
position: absolute;
right: 33px;
color: var(--text-faint);
font-size: var(--font-smaller);
}
.site-body:has(.reader-view) .page-header {
display: none
}
.site-body:has(.reader-view) .published-container .markdown-rendered h1 {
margin-top: 0px;
}
.site-body:has(.reader-view) .markdown-preview-view {
font-size: calc(0.8rem + 0.30vw);
}
.site-body:has(.reader-view) #toggle-sidebar-btn {
top: 5px;
background: transparent;
}
.site-body:has(.reader-view) #toggle-sidebar-btn:hover {
background: none;
}
.sliding-windows .site-body:has(.reader-view) #toggle-sidebar-btn {
right: 5px;
}
.published-container.has-navigation:has(.reader-view) .site-header {
display: block;
position: fixed;
top: 63px;
right: -49px;
transform: rotate(90deg);
z-index: 10;
}
.sliding-windows .site-body:has(.reader-view) .markdown-preview-view {
padding-top:40px;
}
.published-container.has-navigation:has(.reader-view) .site-header .site-header-text::after {
display: none;
}
.sliding-windows:has(.reader-view) .publish-renderer,
.sliding-windows:has(.reader-view) .render-container,
body:has(.reader-view) {
background-color: var(--background-reader);
}
.site-body:has(.reader-view) .render-container-inner {
margin: 0 auto;
}
body:not(.sliding-windows):has(.reader-view) .is-readable-line-width.has-outline.has-navigation .publish-renderer > .markdown-preview-view > .markdown-preview-sizer {
margin-right: inherit;
}
body:not(.sliding-windows):has(.reader-view) .publish-renderer > .markdown-preview-view > .markdown-preview-sizer {
margin: 0 auto;
}
.sliding-windows .publish-renderer:has(.reader-view) {
position: sticky;
width: 800px;
flex: 0 0 800px;
}
.sliding-windows div.hover-popover.is-loaded .publish-renderer {
width: inherit!important;
flex:inherit!important;
}
.sliding-windows .site-body:has(.reader-view) .site-body-center-column,
.sliding-windows .published-container.has-graph .site-body:has(.reader-view) .site-body-center-column {
padding-right: 40px;
}
.site-body:has(.reader-view) .site-body-center-column {
box-shadow: none;
padding-left: 0px;
}
.site-body:has(.reader-view) .site-body-center-column {
box-shadow: 0 0 10px 3px rgba(0, 0, 0, 0.1);
margin-top: 0px;
}
.theme-dark .site-body:has(.reader-view) .site-body-center-column {
border-top: 1px solid var(--divider-color);
}
.site-body:has(.reader-view) .mod-footer,
.site-body:has(.reader-view) .outline-view-outer,
.site-body:has(.reader-view) .graph-view-outer .published-section-header,
.site-body:has(.reader-view) .site-footer,
.site-body:has(.reader-view) .search-view-container,
.site-body:has(.reader-view) .nav-view-outer,
.site-body:has(.reader-view) .site-body-right-column,
.site-body:has(.reader-view) .site-body-left-column-site-name,
.site-body:has(.reader-view) .site-body-left-column-site-logo,
.site-body:has(.reader-view) .site-body-left-column {
display: none;
}
}
@media screen and (max-width: 750px) {
#toggle-sidebar-btn {
display: none;
}
.site-body:has(.reader-view) .site-body-left-column {
display: flex!important;
}
}
@media screen and (max-width: 1024px) {
#toggle-sidebar-btn {
right: 10px;
}
}
/************************ READER END ************************/