mirror of
https://github.com/ChenQihan666/MyBlog-Next.git
synced 2026-08-14 07:33:07 +08:00
0cc647c3d3
Update back-to-top button to accommodate properly, even if the max-width of the blog post is updated. Uses `fixed` position on mobile and `sticky` position on large screens.
89 lines
2.9 KiB
Plaintext
89 lines
2.9 KiB
Plaintext
---
|
|
import IconChevronLeft from "@/assets/icons/IconChevronLeft.svg";
|
|
import IconArrowNarrowUp from "@/assets/icons/IconArrowNarrowUp.svg";
|
|
---
|
|
|
|
<div
|
|
id="btt-btn-container"
|
|
class:list={[
|
|
"fixed right-4 bottom-8 z-50",
|
|
"md:sticky md:right-auto md:float-end md:mr-1",
|
|
"translate-y-14 opacity-0 transition duration-500",
|
|
]}
|
|
>
|
|
<button
|
|
data-button="back-to-top"
|
|
class:list={[
|
|
"group relative bg-background px-2 py-1",
|
|
"size-14 rounded-full shadow-xl",
|
|
"md:h-8 md:w-fit md:rounded-md md:shadow-none",
|
|
"md:bg-background/35 md:bg-clip-padding md:backdrop-blur-lg",
|
|
]}
|
|
>
|
|
<span
|
|
id="progress-indicator"
|
|
class="absolute inset-0 -z-10 block size-14 scale-110 rounded-full bg-transparent md:hidden md:h-8 md:rounded-md"
|
|
></span>
|
|
<IconChevronLeft class="inline-block rotate-90 md:hidden" />
|
|
<span class="sr-only text-sm group-hover:text-accent md:not-sr-only">
|
|
<IconArrowNarrowUp class="inline-block size-4" />
|
|
Back To Top
|
|
</span>
|
|
</button>
|
|
</div>
|
|
|
|
<script is:inline data-astro-rerun>
|
|
/** Scrolls the document to the top when
|
|
* the "Back to Top" button is clicked. */
|
|
function backToTop() {
|
|
const rootElement = document.documentElement;
|
|
const btnContainer = document.querySelector("#btt-btn-container");
|
|
const backToTopBtn = document.querySelector("[data-button='back-to-top']");
|
|
const progressIndicator = document.querySelector("#progress-indicator");
|
|
|
|
if (!rootElement || !btnContainer || !backToTopBtn || !progressIndicator)
|
|
return;
|
|
|
|
// Attach click event handler for back-to-top button
|
|
backToTopBtn.addEventListener("click", () => {
|
|
document.body.scrollTop = 0; // For Safari
|
|
document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
|
|
});
|
|
|
|
// Handle button visibility according to scroll position
|
|
let lastVisible = null;
|
|
function handleScroll() {
|
|
const scrollTotal = rootElement.scrollHeight - rootElement.clientHeight;
|
|
const scrollTop = rootElement.scrollTop;
|
|
const scrollPercent = Math.floor((scrollTop / scrollTotal) * 100);
|
|
|
|
progressIndicator.style.setProperty(
|
|
"background-image",
|
|
`conic-gradient(var(--accent), var(--accent) ${scrollPercent}%, transparent ${scrollPercent}%)`
|
|
);
|
|
|
|
const isVisible = scrollTop / scrollTotal > 0.3;
|
|
|
|
if (isVisible !== lastVisible) {
|
|
btnContainer.classList.toggle("opacity-100", isVisible);
|
|
btnContainer.classList.toggle("translate-y-0", isVisible);
|
|
btnContainer.classList.toggle("opacity-0", !isVisible);
|
|
btnContainer.classList.toggle("translate-y-14", !isVisible);
|
|
lastVisible = isVisible;
|
|
}
|
|
}
|
|
|
|
let ticking = false;
|
|
document.addEventListener("scroll", () => {
|
|
if (!ticking) {
|
|
window.requestAnimationFrame(() => {
|
|
handleScroll();
|
|
ticking = false;
|
|
});
|
|
ticking = true;
|
|
}
|
|
});
|
|
}
|
|
backToTop();
|
|
</script>
|