word counter extension (#88) + bugfixes

This commit is contained in:
dragonwocky 2020-09-18 14:21:09 +10:00
parent 1a66d769cc
commit fe2a0115c3
Signed by: dragonwocky
GPG Key ID: C7A48B7846AA706D
8 changed files with 241 additions and 27 deletions

View File

@ -44,6 +44,7 @@ a feature and cleanup update.
- extension: "calendar scroll" = add a button to scroll down to the current week in fullpage/infinite-scroll calendars.
- extension: "hide help button" = hide the help button if you don't need it.
- extension: "bypass preview" = go straight to the normal full view when opening a page.
- extension: "word counter" = add page details: word/character/sentence/block count & speaking/reading times.
notion-deb-builder has been discovered to not generate an app.asar and so is no longer supported.

View File

@ -30,12 +30,18 @@
.notion-frame
.notion-scroller
[style*='env(safe-area-inset-'][style*=' width: 900px'],
.notion-frame
.notion-scroller
[style*='env(safe-area-inset-'][style*=';width: 900px'],
.notion-frame
.notion-scroller
[style*='height: 30vh']
[style*='pointer-events:'][style*='max-width: 100%; width: 900px'] {
width: var(--theme--page_normal-width) !important;
}
.notion-page-content [style*='max-width: 696px'] {
max-width: 100% !important;
}
.notion-frame
.notion-scroller
[style*='env(safe-area-inset-'][style*=' width: 100%'],

View File

@ -222,7 +222,7 @@
--theme_light--card: rgb(247, 247, 247);
--theme_light--gallery: rgba(55, 53, 47, 0.024);
--theme_light--table-border: rgba(55, 53, 47, 0.16);
--theme_light--interactive_hover: rgba(55, 53, 47, 0.08);
--theme_light--interactive_hover: rgb(239, 239, 239);
--theme_light--interactive_hover-border: transparent;
--theme_light--button_close: #e81123;
--theme_light--button_close-fill: white;

View File

@ -203,7 +203,7 @@ window['__start'] = async () => {
($search_input.value &&
!innerText(mod.elem)
.toLowerCase()
.includes($search_input.value.toLowerCase()))
.includes($search_input.value.toLowerCase().trim()))
)
return (mod.elem.style.display = 'none');
mod.elem.style.display = 'block';

View File

@ -16,19 +16,6 @@ module.exports = {
author: 'obahareth',
hacks: {
'renderer/preload.js'(store, __exports) {
function alignPageContentToRight() {
document
.querySelectorAll(
'.notion-page-content > div[data-block-id]:not([dir])'
)
.forEach((block) => block.setAttribute('dir', 'auto'));
document
.querySelectorAll("div[placeholder='List'], div[placeholder='To-do']")
.forEach((item) => {
item.style['text-align'] = '-webkit-auto';
});
}
document.addEventListener('readystatechange', (event) => {
if (document.readyState !== 'complete') return false;
let queue = [];
@ -36,7 +23,7 @@ module.exports = {
if (!queue.length) requestIdleCallback(() => process(queue));
queue.push(...list);
}),
PAGE_OBSERVER = new MutationObserver(alignPageContentToRight);
PAGE_OBSERVER = new MutationObserver(autoAlignPageContent);
DOCUMENT_OBSERVER.observe(document.body, {
childList: true,
subtree: true,
@ -48,21 +35,30 @@ module.exports = {
addedNodes[0] &&
addedNodes[0].className === 'notion-page-content'
) {
alignPageContentToRight();
autoAlignPageContent();
const $page = document.getElementsByClassName(
'notion-page-content'
)[0];
if ($page) {
PAGE_OBSERVER.disconnect();
PAGE_OBSERVER.observe($page, {
childList: true,
subtree: false,
});
}
PAGE_OBSERVER.disconnect();
PAGE_OBSERVER.observe(addedNodes[0], {
childList: true,
subtree: false,
});
}
}
}
function autoAlignPageContent() {
document
.querySelectorAll(
'.notion-page-content > div[data-block-id]:not([dir])'
)
.forEach((block) => block.setAttribute('dir', 'auto'));
document
.querySelectorAll(
"div[placeholder='List'], div[placeholder='To-do']"
)
.forEach((item) => {
item.style['text-align'] = '-webkit-auto';
});
}
});
},
},

150
mods/word-counter/mod.js Normal file
View File

@ -0,0 +1,150 @@
/*
* word counter
* (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* under the MIT license
*/
'use strict';
const { createElement } = require('../../pkg/helpers.js'),
fs = require('fs-extra'),
path = require('path');
module.exports = {
id: 'b99deb52-6955-43d2-a53b-a31540cd19a5',
tags: ['extension'],
name: 'word counter',
desc:
'add page details: word/character/sentence/block count & speaking/reading times.',
version: '0.1.0',
author: 'dragonwocky',
hacks: {
'renderer/preload.js'(store, __exports) {
const copyToClipboard = (str) => {
const el = document.createElement('textarea');
el.value = str;
el.setAttribute('readonly', '');
el.style.position = 'absolute';
el.style.left = '-9999px';
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
},
humanTime = (mins) => {
let readable = '';
if (1 <= mins) {
readable += `${Math.floor(mins)} min`;
if (2 <= mins) readable += 's';
}
const secs = Math.round((mins % 1) * 60);
if (1 <= secs) {
if (1 <= mins) readable += ' ';
readable += `${secs} sec`;
if (2 <= secs) readable += 's';
}
return readable;
},
questionBubble = fs
.readFileSync(path.resolve(`${__dirname}/question.svg`))
.toString();
document.addEventListener('readystatechange', (event) => {
if (document.readyState !== 'complete') return false;
let queue = [],
$page = document.getElementsByClassName('notion-page-content')[0];
const DOCUMENT_OBSERVER = new MutationObserver((list, observer) => {
if (!queue.length) requestIdleCallback(() => process(queue));
queue.push(...list);
}),
PAGE_OBSERVER = new MutationObserver(showPageWordDetails);
DOCUMENT_OBSERVER.observe(document.body, {
childList: true,
subtree: true,
});
function process(list) {
queue = [];
for (let { addedNodes } of list) {
if (
addedNodes[0] &&
addedNodes[0].className === 'notion-page-content'
) {
$page = addedNodes[0];
showPageWordDetails();
PAGE_OBSERVER.disconnect();
PAGE_OBSERVER.observe($page, {
childList: true,
subtree: true,
characterData: true,
});
}
}
}
const $container = createElement(
`<div id="word-counter-details"><div></div></div>`
),
$tooltip = createElement(
`<span id="word-counter-details-tooltip"></span>`
);
function showPageWordDetails() {
const details = {
words: $page.innerText.replace(/\s+/g, ' ').split(' ').length,
characters: $page.innerText.length,
sentences: $page.innerText.split('.').length,
blocks: $page.querySelectorAll('[data-block-id]').length,
};
details['reading time'] = [
humanTime(details.words / 275),
'~275 wpm',
];
details['speaking time'] = [
humanTime(details.words / 180),
'~180 wpm',
];
$container.children[0].innerHTML = `
<span><b>page details<br></b> (click to copy)</span>
${Object.keys(details).reduce(
(prev, key) =>
prev +
(Array.isArray(details[key])
? `<p><b>${
details[key][0]
}</b> ${key} ${questionBubble.replace(
'<svg',
`<svg data-tooltip="${details[key][1]}"`
)}</p>`
: `<p><b>${details[key]}</b> ${key}</p>`),
''
)}`;
$page.previousElementSibling.children[0].appendChild($container);
$container.offsetParent.appendChild($tooltip);
$container
.querySelectorAll('p')
.forEach((p) =>
p.addEventListener('click', (e) =>
copyToClipboard(e.target.innerText)
)
);
$container.querySelectorAll('[data-tooltip]').forEach((el) => {
el.addEventListener('mouseenter', (e) => {
$tooltip.innerText = el.getAttribute('data-tooltip');
console.log(e.target);
$tooltip.style.top = el.parentElement.offsetTop + 2.5 + 'px';
$tooltip.style.left =
el.parentElement.offsetLeft +
el.parentElement.offsetWidth -
5 +
'px';
$tooltip.classList.add('active');
});
el.addEventListener('mouseleave', (e) =>
$tooltip.classList.remove('active')
);
});
}
});
},
},
};

View File

@ -0,0 +1,2 @@
<!-- from https://fontawesome.com/icons/question-circle?style=regular -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 448c-110.532 0-200-89.431-200-200 0-110.495 89.472-200 200-200 110.491 0 200 89.471 200 200 0 110.53-89.431 200-200 200zm107.244-255.2c0 67.052-72.421 68.084-72.421 92.863V300c0 6.627-5.373 12-12 12h-45.647c-6.627 0-12-5.373-12-12v-8.659c0-35.745 27.1-50.034 47.579-61.516 17.561-9.845 28.324-16.541 28.324-29.579 0-17.246-21.999-28.693-39.784-28.693-23.189 0-33.894 10.977-48.942 29.969-4.057 5.12-11.46 6.071-16.666 2.124l-27.824-21.098c-5.107-3.872-6.251-11.066-2.644-16.363C184.846 131.491 214.94 112 261.794 112c49.071 0 101.45 38.304 101.45 88.8zM298 368c0 23.159-18.841 42-42 42s-42-18.841-42-42 18.841-42 42-42 42 18.841 42 42z"></path></svg>

After

Width:  |  Height:  |  Size: 929 B

View File

@ -0,0 +1,59 @@
/*
* word counter
* (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* under the MIT license
*/
#word-counter-details {
width: 100%;
margin-bottom: 2em;
}
#word-counter-details > div {
display: flex;
flex-wrap: wrap;
margin: -0.5em;
}
#word-counter-details > div > p {
margin: 0.5em;
font-size: var(--theme--font_label-size);
color: var(--theme--text);
border-radius: 3px;
padding: 0.25rem 0.5rem;
background: var(--theme--interactive_hover);
border: 1px solid transparent;
}
#word-counter-details > div > p:hover {
background: transparent;
border: 1px solid var(--theme--interactive_hover);
}
#word-counter-details > div > span {
max-width: 10em;
padding: 0.4rem 0.5rem 0.25rem 0.5rem;
font-size: calc(var(--theme--font_label-size) * 0.8);
color: var(--theme--text_ui_info);
}
#word-counter-details > div > p > svg {
height: 1em;
width: 1em;
margin: 0 0 -2px 0.3em;
color: var(--theme--text_ui_info);
}
#word-counter-details-tooltip {
pointer-events: none;
position: absolute;
padding: 0.25em 0.5em;
border-radius: 3px;
box-shadow: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px,
rgba(15, 15, 15, 0.1) 0px 3px 6px, rgba(15, 15, 15, 0.2) 0px 9px 24px;
border-right-width: 1px;
font-size: calc(var(--theme--font_label-size) * 0.8);
background: var(--theme--interactive_hover);
opacity: 0;
transition: opacity 120ms ease-in;
}
#word-counter-details-tooltip.active {
opacity: 1;
}