diff --git a/src/extensions/outliner/client.mjs b/src/extensions/outliner/client.mjs index e318094..fb27ae7 100644 --- a/src/extensions/outliner/client.mjs +++ b/src/extensions/outliner/client.mjs @@ -11,8 +11,8 @@ function Heading({ indent, ...props }, ...children) { const { html } = globalThis.__enhancerApi; return html`
{ `, }); - let $page; - const updatePage = () => { - if (document.contains($page)) return; - $page = document.querySelector(page); - updateHeadings(); - }; - + let $page, $scroller; const getHeadings = () => { return [...$page.querySelectorAll(headings.join(", "))]; }, @@ -87,24 +81,57 @@ export default async (api, db) => { } return title; }, + getBlockOffset = ($block) => { + let offset = 0; + while (!$block.matches("[data-content-editable-root]")) { + offset += $block.offsetTop; + $block = $block.offsetParent; + } + return offset; + }, updateHeadings = debounce(() => { $toc.innerHTML = ""; if (!$page) return; const $frag = document.createDocumentFragment(); for (const $heading of getHeadings()) { - const $h = html`<${Heading} + $heading._$outline = html`<${Heading} indent=${getHeadingLevel($heading)} onclick=${() => { - const $scroller = document.querySelector(scroller); - $scroller.scrollTo({ top: $heading.offsetTop - 24, behavior }); - }}>${getHeadingTitle($heading)}

`; - $frag.append($h); + $scroller.scrollTo({ + top: getBlockOffset($heading) - 24, + behavior, + }); + }} + >${getHeadingTitle($heading)} + `; + $frag.append($heading._$outline); } $toc.append($frag); + onScroll(); }); + const $progressMarker = html``, + 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)'; addMutationListener(`${page} ${semanticHeadings}`, updateHeadings); - addMutationListener(`${page}, ${scroller}`, updatePage, false); - updatePage(); + addMutationListener(`${page}, ${scroller}`, setup, false); + setup(); };