feat: show scroll progress in outliner #834, fix: jump to headings in columns

This commit is contained in:
dragonwocky 2024-02-09 15:06:34 +11:00
parent d156d810ba
commit f32cf56a67
Signed by: dragonwocky
GPG Key ID: 7998D08F7D7BD7A8

View File

@ -11,8 +11,8 @@ function Heading({ indent, ...props }, ...children) {
const { html } = globalThis.__enhancerApi; const { html } = globalThis.__enhancerApi;
return html`<div return html`<div
role="button" role="button"
class="notion-enhancer--outliner-heading class="notion-enhancer--outliner-heading block
block cursor-pointer select-none text-[14px] relative cursor-pointer select-none text-[14px]
decoration-(2 [color:var(--theme--fg-border)]) decoration-(2 [color:var(--theme--fg-border)])
hover:bg-[color:var(--theme--bg-hover)] hover:bg-[color:var(--theme--bg-hover)]
py-[6px] pr-[2px] pl-[${indent * 18}px] py-[6px] pr-[2px] pl-[${indent * 18}px]
@ -60,13 +60,7 @@ export default async (api, db) => {
</section>`, </section>`,
}); });
let $page; let $page, $scroller;
const updatePage = () => {
if (document.contains($page)) return;
$page = document.querySelector(page);
updateHeadings();
};
const getHeadings = () => { const getHeadings = () => {
return [...$page.querySelectorAll(headings.join(", "))]; return [...$page.querySelectorAll(headings.join(", "))];
}, },
@ -87,24 +81,57 @@ export default async (api, db) => {
} }
return title; return title;
}, },
getBlockOffset = ($block) => {
let offset = 0;
while (!$block.matches("[data-content-editable-root]")) {
offset += $block.offsetTop;
$block = $block.offsetParent;
}
return offset;
},
updateHeadings = debounce(() => { updateHeadings = debounce(() => {
$toc.innerHTML = ""; $toc.innerHTML = "";
if (!$page) return; if (!$page) return;
const $frag = document.createDocumentFragment(); const $frag = document.createDocumentFragment();
for (const $heading of getHeadings()) { for (const $heading of getHeadings()) {
const $h = html`<${Heading} $heading._$outline = html`<${Heading}
indent=${getHeadingLevel($heading)} indent=${getHeadingLevel($heading)}
onclick=${() => { onclick=${() => {
const $scroller = document.querySelector(scroller); $scroller.scrollTo({
$scroller.scrollTo({ top: $heading.offsetTop - 24, behavior }); top: getBlockOffset($heading) - 24,
}}>${getHeadingTitle($heading)}</p>`; behavior,
$frag.append($h); });
}}
>${getHeadingTitle($heading)}
<//>`;
$frag.append($heading._$outline);
} }
$toc.append($frag); $toc.append($frag);
onScroll();
}); });
const $progressMarker = html`<span
class="absolute block left-[6px] top-[calc(50%-1px)]
size-[6px] rounded-full bg-[color:var(--theme--fg-secondary)]"
></span>`,
onScroll = () => {
const $h = getHeadings().find(($h) => {
return $scroller.scrollTop < getBlockOffset($h) - 16;
})?._$outline;
if ($h) $h.prepend($progressMarker);
},
setup = () => {
if (document.contains($page)) return;
$page = document.querySelector(page);
console.log($page);
$scroller = document.querySelector(scroller);
$scroller?.removeEventListener("scroll", onScroll);
$scroller?.addEventListener("scroll", onScroll);
updateHeadings();
};
const semanticHeadings = '[class$="header-block"] :is(h2, h3, h4)'; const semanticHeadings = '[class$="header-block"] :is(h2, h3, h4)';
addMutationListener(`${page} ${semanticHeadings}`, updateHeadings); addMutationListener(`${page} ${semanticHeadings}`, updateHeadings);
addMutationListener(`${page}, ${scroller}`, updatePage, false); addMutationListener(`${page}, ${scroller}`, setup, false);
updatePage(); setup();
}; };