notion-enhancer/repo/word-counter/client.mjs

123 lines
4.0 KiB
JavaScript

/*
* notion-enhancer: word counter
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
const copyToClipboard = async (str) => {
try {
await navigator.clipboard.writeText(str);
} catch {
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;
};
export default async function ({ web, components }, db) {
const dbNoticeText = 'Open a page to see its word count.',
pageNoticeText = 'Click a stat to copy it.',
$notice = web.html`<p id="word-counter--notice">${dbNoticeText}</p>`;
const $wordCount = web.html`<b>12</b>`,
$characterCount = web.html`<b>12</b>`,
$sentenceCount = web.html`<b>12</b>`,
$blockCount = web.html`<b>12</b>`,
$readingTime = web.html`<b>10 mins</b>`,
$readingTooltip = web.html`${await components.feather('info')}`,
$speakingTime = web.html`<b>18 secs</b>`,
$speakingTooltip = web.html`${await components.feather('info')}`,
$statList = web.render(
web.html`<div></div>`,
web.render(web.html`<p class="word-counter--stat"></p>`, $wordCount, ' words'),
web.render(web.html`<p class="word-counter--stat"></p>`, $characterCount, ' characters'),
web.render(web.html`<p class="word-counter--stat"></p>`, $sentenceCount, ' sentences'),
web.render(web.html`<p class="word-counter--stat"></p>`, $blockCount, ' blocks'),
web.render(
web.html`<p class="word-counter--stat"></p>`,
$readingTooltip,
$readingTime,
' reading time'
),
web.render(
web.html`<p class="word-counter--stat"></p>`,
$speakingTooltip,
$speakingTime,
' speaking time'
)
);
$statList.querySelectorAll('.word-counter--stat').forEach(($stat) => {
$stat.addEventListener('click', () => copyToClipboard($stat.innerText));
});
components.setTooltip($readingTooltip, '**~ 275 wpm**');
components.setTooltip($speakingTooltip, '**~ 180 wpm**');
let viewFocused = false,
$page;
await components.addPanelView({
id: 'b99deb52-6955-43d2-a53b-a31540cd19a5',
icon: await components.feather('type'),
title: 'Word Counter',
$content: web.render(web.html`<div></div>`, $notice, $statList),
onFocus: () => {
viewFocused = true;
updateStats();
},
onBlur: () => {
viewFocused = false;
},
});
function updateStats() {
if (!$page) return;
const words = $page.innerText.split(/[^\w]+/).length;
$wordCount.innerText = words;
$characterCount.innerText = $page.innerText.length;
$sentenceCount.innerText = $page.innerText.split('.').length;
$blockCount.innerText = $page.querySelectorAll('[data-block-id]').length;
$readingTime.innerText = humanTime(words / 275);
$speakingTime.innerText = humanTime(words / 180);
}
const pageObserver = () => {
if (!viewFocused) return;
if (document.contains($page)) {
updateStats();
} else {
$page = document.getElementsByClassName('notion-page-content')[0];
if ($page) {
$notice.innerText = pageNoticeText;
$statList.style.display = '';
updateStats();
} else {
$notice.innerText = dbNoticeText;
$statList.style.display = 'none';
}
}
};
web.addDocumentObserver(pageObserver, [
'.notion-page-content',
'.notion-collection_view_page-block',
]);
pageObserver();
}