diff --git a/src/core/islands/FloatingButton.mjs b/src/core/islands/FloatingButton.mjs new file mode 100644 index 0000000..4bcedd4 --- /dev/null +++ b/src/core/islands/FloatingButton.mjs @@ -0,0 +1,56 @@ +/** + * notion-enhancer + * (c) 2024 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +"use strict"; + +let __$wrapper; +const setupWrapper = () => { + const notionHelp = ".notion-help-button", + { html, addMutationListener } = globalThis.__enhancerApi, + { removeMutationListener } = globalThis.__enhancerApi; + return (__$wrapper ??= new Promise((res, rej) => { + const addToDom = () => { + const $help = document.querySelector(notionHelp); + if (!$help) return; + const $wrapper = html`
`; + removeMutationListener(addToDom); + $help.replaceWith($wrapper); + $wrapper.append($help); + res($wrapper); + }; + addMutationListener(notionHelp, addToDom); + addToDom(); + })); + }, + addFloatingButton = async ($btn) => { + if (document.contains($btn)) return; + (await setupWrapper()).prepend($btn); + }, + removeFloatingButton = ($btn) => $btn.remove(); + +function FloatingButton({ icon, ...props }, ...children) { + const { html, extendProps } = globalThis.__enhancerApi; + extendProps(props, { + tabindex: 0, + class: `notion-enhancer--floating-button + size-[36px] flex items-center justify-center rounded-full + text-([20px] [color:var(--theme--fg-primary)]) select-none cursor-pointer + bg-[color:var(--theme--bg-secondary)] hover:bg-[color:var(--theme--bg-hover)] + shadow-[rgba(15,15,15,0.2)_0px_0px_0px_1px,rgba(15,15,15,0.2)_0px_2px_4px]`, + }); + return html``; +} + +Object.assign((globalThis.__enhancerApi ??= {}), { + addFloatingButton, + removeFloatingButton, +}); + +export { addFloatingButton, FloatingButton }; diff --git a/src/extensions/scroll-to-top/client.mjs b/src/extensions/scroll-to-top/client.mjs index d7c7087..67d1f1c 100644 --- a/src/extensions/scroll-to-top/client.mjs +++ b/src/extensions/scroll-to-top/client.mjs @@ -7,45 +7,37 @@ "use strict"; +import { FloatingButton } from "../../core/islands/FloatingButton.mjs"; + export default async (api, db) => { - const { html } = api, + const { html, addFloatingButton, removeFloatingButton } = api, + { addMutationListener, removeMutationListener } = api, + distanceUntilShown = await db.get("distanceScrolledUntilShown"), + scrollUnits = await db.get("scrollDistanceUnits"), behavior = (await db.get("smoothScrolling")) ? "smooth" : "auto", scroller = ".notion-frame > .notion-scroller"; - const $btn = html``; - document.body.append($btn); - - // const topDistancePx = +(await db.get(["top_distance_px"])), - // topDistancePercent = 0.01 * (await db.get(["top_distance_percent"])), - // adjustButtonVisibility = async () => { - // if (!$scroller) return; - // $scrollButton.classList.add("hidden"); - // const scrolledDistance = - // $scroller.scrollTop >= topDistancePx || - // $scroller.scrollTop >= - // ($scroller.scrollHeight - $scroller.clientHeight) * - // topDistancePercent; - // if (scrolledDistance) $scrollButton.classList.remove("hidden"); - // }; - // web.addDocumentObserver(() => { - // $scroller = document.querySelector(".notion-frame > .notion-scroller"); - // $scroller.removeEventListener("scroll", adjustButtonVisibility); - // $scroller.addEventListener("scroll", adjustButtonVisibility); - // }, [".notion-frame > .notion-scroller"]); - // adjustButtonVisibility(); - // if (topDistancePx && topDistancePercent) - // $scrollButton.classList.add("hidden"); + let $scroller; + const $btn = html`<${FloatingButton} + onclick=${() => $scroller?.scroll({ top: 0, left: 0, behavior })} + aria-label="Scroll to top" + > + `, + onScroll = () => { + if (!$scroller) return; + const { scrollTop, scrollHeight, clientHeight } = $scroller, + scrollPercent = (scrollTop / (scrollHeight - clientHeight)) * 100, + scrollDist = scrollUnits === "Percent" ? scrollPercent : scrollTop; + if (distanceUntilShown <= scrollDist) addFloatingButton($btn); + else removeFloatingButton($btn); + }, + setup = () => { + if (document.contains($scroller)) return; + $scroller = document.querySelector(scroller); + $scroller?.removeEventListener("scroll", onScroll); + $scroller?.addEventListener("scroll", onScroll); + onScroll(); + }; + addMutationListener(scroller, setup, true); + setup(); };