refactor: improve toc popup module

This commit is contained in:
Cotes Chung 2024-10-19 21:13:21 +08:00
parent 03e302cbf6
commit 6f461132c0
No known key found for this signature in database
GPG key ID: 0D9E54843167A808
4 changed files with 49 additions and 34 deletions

View file

@ -5,7 +5,10 @@ const desktopMode = matchMedia('(min-width: 1200px)');
function refresh(e) { function refresh(e) {
if (e.matches) { if (e.matches) {
if (mobile.popupOpened) {
mobile.hidePopup(); mobile.hidePopup();
}
desktop.refresh(); desktop.refresh();
} else { } else {
mobile.refresh(); mobile.refresh();

View file

@ -12,8 +12,8 @@ const SCROLL_LOCK = 'overflow-hidden';
const CLOSING = 'closing'; const CLOSING = 'closing';
export class TocMobile { export class TocMobile {
static invisible = true; static #invisible = true;
static barHeight = 16 * 3; // 3rem static #barHeight = 16 * 3; // 3rem
static options = { static options = {
tocSelector: '#toc-popup-content', tocSelector: '#toc-popup-content',
@ -23,7 +23,7 @@ export class TocMobile {
orderedList: false, orderedList: false,
scrollSmooth: false, scrollSmooth: false,
collapseDepth: 4, collapseDepth: 4,
headingsOffset: this.barHeight headingsOffset: this.#barHeight
}; };
static initBar() { static initBar() {
@ -33,44 +33,40 @@ export class TocMobile {
$tocBar.classList.toggle('invisible', entry.isIntersecting); $tocBar.classList.toggle('invisible', entry.isIntersecting);
}); });
}, },
{ rootMargin: `-${this.barHeight}px 0px 0px 0px` } { rootMargin: `-${this.#barHeight}px 0px 0px 0px` }
); );
observer.observe($soloTrigger); observer.observe($soloTrigger);
this.invisible = false; this.#invisible = false;
} }
static listenAnchors() { static listenAnchors() {
const $anchors = document.getElementsByClassName('toc-link'); const $anchors = document.getElementsByClassName('toc-link');
[...$anchors].forEach((anchor) => { [...$anchors].forEach((anchor) => {
anchor.onclick = this.hidePopup; anchor.onclick = () => this.hidePopup();
}); });
} }
static refresh() { static refresh() {
if (this.invisible) { if (this.#invisible) {
this.initComponents(); this.initComponents();
} }
tocbot.refresh(this.options); tocbot.refresh(this.options);
this.listenAnchors(); this.listenAnchors();
} }
static get popupOpened() {
return $popup.open;
}
static showPopup() { static showPopup() {
TocMobile.lockScroll(true); this.lockScroll(true);
$popup.showModal(); $popup.showModal();
const activeItem = $popup.querySelector('li.is-active-li'); const activeItem = $popup.querySelector('li.is-active-li');
activeItem.scrollIntoView({ block: 'center' }); activeItem.scrollIntoView({ block: 'center' });
} }
static hidePopup(event) { static hidePopup() {
if (event?.type === 'cancel') {
event.preventDefault();
}
if (!$popup.open) {
return;
}
$popup.toggleAttribute(CLOSING); $popup.toggleAttribute(CLOSING);
$popup.addEventListener( $popup.addEventListener(
@ -82,7 +78,7 @@ export class TocMobile {
{ once: true } { once: true }
); );
TocMobile.lockScroll(false); this.lockScroll(false);
} }
static lockScroll(enable) { static lockScroll(enable) {
@ -91,6 +87,10 @@ export class TocMobile {
} }
static clickBackdrop(event) { static clickBackdrop(event) {
if ($popup.hasAttribute(CLOSING)) {
return;
}
const rect = event.target.getBoundingClientRect(); const rect = event.target.getBoundingClientRect();
if ( if (
event.clientX < rect.left || event.clientX < rect.left ||
@ -98,7 +98,7 @@ export class TocMobile {
event.clientY < rect.top || event.clientY < rect.top ||
event.clientY > rect.bottom event.clientY > rect.bottom
) { ) {
TocMobile.hidePopup(); this.hidePopup();
} }
} }
@ -106,11 +106,15 @@ export class TocMobile {
this.initBar(); this.initBar();
[...$triggers].forEach((trigger) => { [...$triggers].forEach((trigger) => {
trigger.onclick = this.showPopup; trigger.onclick = () => this.showPopup();
}); });
$popup.onclick = this.clickBackdrop; $popup.onclick = (e) => this.clickBackdrop(e);
$btnClose.onclick = $popup.oncancel = this.hidePopup; $btnClose.onclick = () => this.hidePopup();
$popup.oncancel = (e) => {
e.preventDefault();
this.hidePopup();
};
} }
static init() { static init() {

View file

@ -100,7 +100,7 @@ tail_includes:
{% if enable_toc %} {% if enable_toc %}
<div id="toc-bar" class="d-flex align-items-center justify-content-between invisible"> <div id="toc-bar" class="d-flex align-items-center justify-content-between invisible">
<span class="label text-truncate">{{ page.title }}</span> <span class="label text-truncate">{{ page.title }}</span>
<button type="button" class="toc-trigger btn btn-link me-1"> <button type="button" class="toc-trigger btn me-1">
<i class="fa-solid fa-list-ul fa-fw"></i> <i class="fa-solid fa-list-ul fa-fw"></i>
</button> </button>
</div> </div>
@ -113,8 +113,8 @@ tail_includes:
<dialog id="toc-popup" class="p-0"> <dialog id="toc-popup" class="p-0">
<div class="header d-flex flex-row align-items-center justify-content-between"> <div class="header d-flex flex-row align-items-center justify-content-between">
<div class="label text-truncate py-2 ms-4">{{- page.title -}}</div> <div class="label text-truncate py-2 ms-4">{{- page.title -}}</div>
<button id="toc-popup-close" type="button" class="btn btn-link"> <button id="toc-popup-close" type="button" class="btn mx-1 my-1 opacity-75">
<i class="fas fa-close fa-fw"></i> <i class="fas fa-close"></i>
</button> </button>
</div> </div>
<div id="toc-popup-content" class="px-4 py-3 pb-4"></div> <div id="toc-popup-content" class="px-4 py-3 pb-4"></div>

View file

@ -380,12 +380,13 @@ header {
$slide-in: slide-in 0.3s ease-out; $slide-in: slide-in 0.3s ease-out;
$slide-out: slide-out 0.3s ease-out; $slide-out: slide-out 0.3s ease-out;
$curtain-height: 2rem; $curtain-height: 2rem;
$backdrop: blur(5px);
border-color: var(--toc-popup-border-color); border-color: var(--toc-popup-border-color);
border-width: 1px; border-width: 1px;
border-radius: $radius-lg; border-radius: $radius-lg;
color: var(--text-color); color: var(--text-color);
background: var(--main-bg); background: var(--card-bg);
margin-top: $topbar-height; margin-top: $topbar-height;
min-width: 20rem; min-width: 20rem;
font-size: 1.05rem; font-size: 1.05rem;
@ -422,9 +423,16 @@ header {
} }
} }
button:focus-visible { button {
> i {
font-size: 1.25rem;
vertical-align: middle;
}
&:focus-visible {
box-shadow: none; box-shadow: none;
} }
}
ul { ul {
list-style-type: none; list-style-type: none;
@ -461,20 +469,20 @@ header {
} }
&::-webkit-backdrop { &::-webkit-backdrop {
-webkit-backdrop-filter: blur(5px); -webkit-backdrop-filter: $backdrop;
backdrop-filter: blur(5px); backdrop-filter: $backdrop;
} }
&::backdrop { &::backdrop {
-webkit-backdrop-filter: blur(5px); -webkit-backdrop-filter: $backdrop;
backdrop-filter: blur(5px); backdrop-filter: $backdrop;
} }
&::after { &::after {
display: flex; display: flex;
content: ''; content: '';
position: relative; position: relative;
background: linear-gradient(transparent, var(--main-bg) 70%); background: linear-gradient(transparent, var(--card-bg) 70%);
height: $curtain-height; height: $curtain-height;
} }