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:
@@ -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 };
|
||||
|
||||
22
_javascript/modules/components/toc/toc-desktop.js
Normal file
22
_javascript/modules/components/toc/toc-desktop.js
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
117
_javascript/modules/components/toc/toc-mobile.js
Normal file
117
_javascript/modules/components/toc/toc-mobile.js
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user