1
0
mirror of https://github.com/cotes2020/jekyll-theme-chirpy.git synced 2025-12-18 21:53:26 +00:00

feat: show toc on mobile screens (#1964)

This commit is contained in:
Alexander Fuks
2024-10-11 18:32:10 +04:00
committed by GitHub
parent 740bd84c51
commit 8a064a5e5a
13 changed files with 429 additions and 29 deletions

View File

@@ -1,15 +1,30 @@
export function toc() {
if (document.querySelector('main h2, main h3')) {
// see: https://github.com/tscanlin/tocbot#usage
tocbot.init({
tocSelector: '#toc',
contentSelector: '.content',
ignoreSelector: '[data-toc-skip]',
headingSelector: 'h2, h3, h4',
orderedList: false,
scrollSmooth: false
});
import { TocMobile as mobile } from './toc/toc-mobile';
import { TocDesktop as desktop } from './toc/toc-desktop';
document.getElementById('toc-wrapper').classList.remove('d-none');
const desktopMode = matchMedia('(min-width: 1200px)');
function refresh(e) {
if (e.matches) {
mobile.hidePopup();
desktop.refresh();
} else {
mobile.refresh();
}
}
function init() {
if (document.querySelector('main>article[data-toc="true"]') === null) {
return;
}
// Avoid create multiple instances of Tocbot. Ref: <https://github.com/tscanlin/tocbot/issues/203>
if (desktopMode.matches) {
desktop.init();
} else {
mobile.init();
}
desktopMode.onchange = refresh;
}
export { init as initToc };

View File

@@ -0,0 +1,22 @@
export class TocDesktop {
/* Tocbot options Ref: https://github.com/tscanlin/tocbot#usage */
static options = {
tocSelector: '#toc',
contentSelector: '.content',
ignoreSelector: '[data-toc-skip]',
headingSelector: 'h2, h3, h4',
orderedList: false,
scrollSmooth: false,
headingsOffset: 16 * 2 // 2rem
};
static refresh() {
tocbot.refresh(this.options);
}
static init() {
if (document.getElementById('toc-wrapper')) {
tocbot.init(this.options);
}
}
}

View File

@@ -0,0 +1,117 @@
/**
* TOC button, topbar and popup for mobile devices
*/
const $tocBar = document.getElementById('toc-bar');
const $soloTrigger = document.getElementById('toc-solo-trigger');
const $triggers = document.getElementsByClassName('toc-trigger');
const $popup = document.getElementById('toc-popup');
const $btnClose = document.getElementById('toc-popup-close');
const SCROLL_LOCK = 'overflow-hidden';
const CLOSING = 'closing';
export class TocMobile {
static invisible = true;
static barHeight = 16 * 3; // 3rem
static options = {
tocSelector: '#toc-popup-content',
contentSelector: '.content',
ignoreSelector: '[data-toc-skip]',
headingSelector: 'h2, h3, h4',
orderedList: false,
scrollSmooth: false,
collapseDepth: 4,
headingsOffset: this.barHeight
};
static initBar() {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
$tocBar.classList.toggle('invisible', entry.isIntersecting);
});
},
{ rootMargin: `-${this.barHeight}px 0px 0px 0px` }
);
observer.observe($soloTrigger);
this.invisible = false;
}
static listenAnchors() {
const $anchors = document.getElementsByClassName('toc-link');
[...$anchors].forEach((anchor) => {
anchor.onclick = this.hidePopup;
});
}
static refresh() {
if (this.invisible) {
this.initComponents();
}
tocbot.refresh(this.options);
this.listenAnchors();
}
static showPopup() {
TocMobile.lockScroll(true);
$popup.showModal();
const activeItem = $popup.querySelector('li.is-active-li');
activeItem.scrollIntoView({ block: 'center' });
}
static hidePopup() {
if (!$popup.open) {
return;
}
$popup.toggleAttribute(CLOSING);
$popup.addEventListener(
'animationend',
() => {
$popup.toggleAttribute(CLOSING);
$popup.close();
},
{ once: true }
);
TocMobile.lockScroll(false);
}
static lockScroll(enable) {
document.documentElement.classList.toggle(SCROLL_LOCK, enable);
document.body.classList.toggle(SCROLL_LOCK, enable);
}
static clickBackdrop(event) {
const rect = event.target.getBoundingClientRect();
if (
event.clientX < rect.left ||
event.clientX > rect.right ||
event.clientY < rect.top ||
event.clientY > rect.bottom
) {
TocMobile.hidePopup();
}
}
static initComponents() {
this.initBar();
[...$triggers].forEach((trigger) => {
trigger.onclick = this.showPopup;
});
$popup.onclick = this.clickBackdrop;
$btnClose.onclick = $popup.oncancel = this.hidePopup;
}
static init() {
tocbot.init(this.options);
this.listenAnchors();
this.initComponents();
}
}

View File

@@ -3,4 +3,4 @@ export { initClipboard } from './components/clipboard';
export { loadImg } from './components/img-loading';
export { imgPopup } from './components/img-popup';
export { initLocaleDatetime } from './components/locale-datetime';
export { toc } from './components/toc';
export { initToc } from './components/toc';

View File

@@ -1,14 +1,15 @@
import { basic, initSidebar, initTopbar } from './modules/layouts';
import { basic, initTopbar, initSidebar } from './modules/layouts';
import {
loadImg,
imgPopup,
initLocaleDatetime,
initClipboard,
toc
initToc
} from './modules/plugins';
loadImg();
toc();
initToc();
imgPopup();
initSidebar();
initLocaleDatetime();