upload outliner extension

This commit is contained in:
Ryo Hilmawan 2020-11-23 14:00:59 +07:00 committed by GitHub
parent cf1eb203ca
commit 6b6626c966
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 199 additions and 0 deletions

51
mods/outliner/app.css Normal file
View File

@ -0,0 +1,51 @@
/*
* outliner
* (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (c) 2020 CloudHill
* under the MIT license
*/
.outliner {
max-height: 100%;
overflow: hidden auto;
}
.outline-header {
display: flex;
align-items: center;
height: 2.2em;
cursor: pointer;
user-select: none;
transition: background 20ms ease-in;
}
.outline-header:hover {
background: var(--theme--interactive_hover);
}
.outline-header a {
width: 100%;
height: 100%;
padding: 0 14px;
line-height: 2.2;
color: inherit;
text-decoration: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.outline-header a:empty:before {
color: var(--theme--text_ui_info);
content: attr(placeholder);
display: block;
}
.outline-header.notion-header-block a {
text-indent: 0;
}
.outline-header.notion-sub_header-block a {
text-indent: 18px;
}
.outline-header.notion-sub_sub_header-block a {
text-indent: 36px;
}

8
mods/outliner/icon.svg Normal file
View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<circle cx="5" cy="7" r="2.8"/>
<circle cx="5" cy="17" r="2.79"/>
<path d="M21,5.95H11c-0.55,0-1-0.45-1-1v0c0-0.55,0.45-1,1-1h10c0.55,0,1,0.45,1,1v0C22,5.5,21.55,5.95,21,5.95z"/>
<path d="M17,10.05h-6c-0.55,0-1-0.45-1-1v0c0-0.55,0.45-1,1-1h6c0.55,0,1,0.45,1,1v0C18,9.6,17.55,10.05,17,10.05z"/>
<path d="M21,15.95H11c-0.55,0-1-0.45-1-1v0c0-0.55,0.45-1,1-1h10c0.55,0,1,0.45,1,1v0C22,15.5,21.55,15.95,21,15.95z" />
<path d="M17,20.05h-6c-0.55,0-1-0.45-1-1v0c0-0.55,0.45-1,1-1h6c0.55,0,1,0.45,1,1v0C18,19.6,17.55,20.05,17,20.05z"/>
</svg>

After

Width:  |  Height:  |  Size: 633 B

23
mods/outliner/mod.js Normal file
View File

@ -0,0 +1,23 @@
/*
* outliner
* (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (c) 2020 CloudHill
* under the MIT license
*/
'use strict';
module.exports = {
id: '87e077cc-5402-451c-ac70-27cc4ae65546',
tags: ['extension', 'panel'],
name: 'outliner',
desc: 'table of contents.',
version: '1.0.0',
author: 'CloudHill',
panel: {
html: "panel.html",
name: "Outline",
icon: "icon.svg",
js: "panel.js",
}
};

2
mods/outliner/panel.html Normal file
View File

@ -0,0 +1,2 @@
<div class="outliner">
</div>

115
mods/outliner/panel.js Normal file
View File

@ -0,0 +1,115 @@
/*
* outliner
* (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (c) 2020 CloudHill
* under the MIT license
*/
'use strict';
const { createElement } = require("../../pkg/helpers");
module.exports = (store) => {
function initOutliner() {
// Find headers when switching panels
if (document.querySelector('.notion-page-content')) {
startContentObserver();
};
// Observe for page changes
const pageObserver = new MutationObserver((list, observer) => {
for ( let { addedNodes } of list) {
if (addedNodes[0]) {
if (addedNodes[0].className === 'notion-page-content') {
startContentObserver();
}
// Clear outline on database pages
else if (addedNodes[0].className === 'notion-scroller') {
contentObserver.disconnect();
const outline = document.querySelector('.outliner');
if (outline) outline.textContent = '';
}
}
}
});
pageObserver.observe(document.body, {
childList: true,
subtree: true,
});
// Observe for header changes
const contentObserver = new MutationObserver((list, observer) => {
list.forEach(m => {
if (
(
m.type === 'childList' &&
(
isHeaderElement(m.target) ||
isHeaderElement(m.addedNodes[0]) ||
isHeaderElement(m.removedNodes[0])
)
) ||
(
m.type === 'characterData' &&
isHeaderElement(m.target.parentElement)
)
) findHeaders();
})
});
function startContentObserver() {
findHeaders();
contentObserver.disconnect();
contentObserver.observe(
document.querySelector('.notion-page-content'),
{
childList: true,
subtree: true,
characterData: true,
}
);
}
}
function findHeaders() {
const outline = document.querySelector('.outliner');
if (!outline) {
pageObserver.disconnect();
observer.disconnect();
}
outline.textContent = '';
const pageContent = document.querySelector('.notion-page-content');
const headerBlocks = pageContent.querySelectorAll('[class*="header-block"]');
headerBlocks.forEach(block => {
const blockId = block.dataset.blockId.replace(/-/g, '');
const placeholder = block.querySelector('[placeholder]').getAttribute('placeholder');
const header = createElement(`
<div class="outline-header ${block.classList[1]}">
<a href="${window.location.pathname}#${blockId}"
placeholder="${placeholder}">${block.innerText}</a>
</div>
`);
outline.append(header);
})
}
function isHeaderElement(el) {
let placeholder;
if (el) {
if (
el.querySelector &&
el.querySelector('[placeholder]')
) {
placeholder = el.querySelector('[placeholder]').getAttribute('placeholder')
} else if (el.getAttribute) {
placeholder = el.getAttribute('placeholder');
}
}
if (!placeholder) placeholder = '';
return placeholder.includes('Heading');
}
return initOutliner;
}