mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-19 19:19:03 +00:00
upload outliner extension
This commit is contained in:
parent
cf1eb203ca
commit
6b6626c966
51
mods/outliner/app.css
Normal file
51
mods/outliner/app.css
Normal 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
8
mods/outliner/icon.svg
Normal 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
23
mods/outliner/mod.js
Normal 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
2
mods/outliner/panel.html
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<div class="outliner">
|
||||||
|
</div>
|
115
mods/outliner/panel.js
Normal file
115
mods/outliner/panel.js
Normal 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user