new mod: scroll-to-top (#172)

* Basic Functionality

* Added smooth scrolling option

* Added scroll down distance option

* Button hide/show animation

* Add percentage distance option

* Calculate percentage every update (as opposed to every page change)

* Calculate percentage height based on scroller and content height

* Licensing and Conventions

* Hide button on initialization if top distance is set

* Fixed bug with button visibility when opening pages
This commit is contained in:
Ryo Hilmawan 2020-10-21 18:32:10 +07:00 committed by GitHub
parent cdbce12b11
commit fb63601ebf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 177 additions and 0 deletions

123
mods/scroll-to-top/mod.js Normal file
View File

@ -0,0 +1,123 @@
/*
* scroll-to-top
* (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (c) 2020 CloudHill
* under the MIT license
*/
"use strict";
const { createElement } = require("../../pkg/helpers.js");
module.exports = {
id: "0a958f5a-17c5-48b5-8713-16190cae1959",
tags: ["extension"],
name: "scroll-to-top",
desc: "add a scroll to top button.",
version: "1.0.0",
author: "CloudHill",
options: [
{
key: "smooth",
label: "smooth scrolling",
type: "toggle",
value: true,
},
{
key: "top",
label: "scroll down distance to show button",
type: "input",
value: 80,
},
{
key: "percent",
label: "set distance as a percentage",
type: "toggle",
value: true,
},
],
hacks: {
"renderer/preload.js"(store, __exports) {
document.addEventListener("readystatechange", (event) => {
if (document.readyState !== "complete") return false;
const attempt_interval = setInterval(enhance, 500);
function enhance() {
if (!document.querySelector(".notion-frame")) return;
clearInterval(attempt_interval);
const $container = document.createElement('div');
const $help = document.querySelector('.notion-help-button');
const $scroll = createElement(
'<div class="notion-scroll-button" role="button">&#129049;</div>' // 🠙;
)
$container.className = "bottom-right-buttons";
$help.after($container);
$container.append($scroll);
$container.append($help);
if (store().top > 0)
$scroll.classList.add('hidden');
$scroll.addEventListener('click', () => {
document
.querySelector('.notion-frame > .notion-scroller')
.scroll({
top: 0,
left: 0,
behavior: store().smooth ? 'smooth' : 'auto',
});
})
let queue = [];
let $scroller = document.querySelector('.notion-frame > .notion-scroller');
let top = store().top || 0;
const observer = new MutationObserver((list, observer) => {
if (!queue.length) requestAnimationFrame(() => process(queue));
queue.push(...list);
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
function process(list) {
queue = [];
setScrollDistance();
for (let { addedNodes } of list) {
if (
addedNodes[0] && (
addedNodes[0].className === 'notion-page-content' ||
addedNodes[0].className === 'notion-scroller'
) && (top > 0)
) {
$scroll.classList.add('hidden');
$scroller = document.querySelector('.notion-frame > .notion-scroller');
setScrollDistance();
$scroller.addEventListener('scroll', (event) => {
if (Math.ceil(event.target.scrollTop) < $scroller.top_distance)
$scroll.classList.add('hidden');
else
$scroll.classList.remove('hidden');
});
}
}
}
function setScrollDistance() {
$scroller.top_distance = top;
if (top > 0 && store().percent) {
let content_height = Array.from($scroller.children)
.reduce((h, c) => h + c.offsetHeight, 0);
$scroller.top_distance *= (content_height - $scroller.offsetHeight) / 100;
}
}
}
});
}
},
};

View File

@ -0,0 +1,54 @@
/*
* scroll-to-top
* (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (c) 2020 CloudHill
* under the MIT license
*/
.bottom-right-buttons {
position: absolute;
bottom: 33px;
right: 33px;
z-index: 101;
cursor: default;
pointer-events: none;
}
.bottom-right-buttons > div {
margin-top: 8px;
pointer-events: auto;
user-select: none;
transition: opacity 700ms ease 0s, color 700ms ease 0s, transform 700ms ease 0s;
cursor: pointer;
position: static !important;
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 100%;
font-size: 20px;
background: var(--theme--interactive_hover);
box-shadow: 0 0 0 0.5px var(--theme--interactive_hover-border);
}
.notion-scroll-button {
display: flex !important;
}
.notion-scroll-button.hidden {
pointer-events: none;
visibility: hidden;
opacity: 0;
transform: translateY(10px);
transition-property: opacity, transform, visibility;
transition-delay: 0, 0, 700ms
}