70 lines
2.9 KiB
Plaintext
70 lines
2.9 KiB
Plaintext
component BackToTop {
|
|
props {
|
|
threshold = 500
|
|
label = "Back to top"
|
|
ariaLabel = "Scroll back to top"
|
|
icon = "icon-[lucide--arrow-up]"
|
|
position = "right"
|
|
offset = "md"
|
|
behavior = "smooth"
|
|
showProgress = false
|
|
size = "default"
|
|
color = "primary"
|
|
variant = "solid"
|
|
class = ""
|
|
}
|
|
|
|
state visible = false
|
|
state progress = 0
|
|
|
|
view {
|
|
<button
|
|
data-ui-component="BackToTop"
|
|
type="button"
|
|
aria-label='{ariaLabel}'
|
|
title='{label}'
|
|
data-show='visible'
|
|
class='fixed z-50 inline-flex items-center justify-center rounded-full border border-[var(--wire-color-border)] shadow-xl backdrop-blur transition duration-200 hover:-translate-y-1 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--wire-color-background)] {class}'
|
|
class:bottom-4='offset === "sm"'
|
|
class:bottom-6='offset === "md"'
|
|
class:bottom-8='offset === "lg"'
|
|
class:right-4='position === "right" && offset === "sm"'
|
|
class:right-6='position === "right" && offset === "md"'
|
|
class:right-8='position === "right" && offset === "lg"'
|
|
class:left-4='position === "left" && offset === "sm"'
|
|
class:left-6='position === "left" && offset === "md"'
|
|
class:left-8='position === "left" && offset === "lg"'
|
|
class:left-1/2='position === "center"'
|
|
class:-translate-x-1/2='position === "center"'
|
|
class:size-10='size === "sm"'
|
|
class:size-12='size === "default" || size === "md"'
|
|
class:size-14='size === "lg"'
|
|
class:bg-[var(--wire-color-primary)]='variant === "solid" && color === "primary"'
|
|
class:text-[var(--wire-color-on-primary)]='variant === "solid" && color === "primary"'
|
|
class:bg-[var(--wire-color-danger)]='variant === "solid" && color === "danger"'
|
|
class:text-[var(--wire-color-on-danger)]='variant === "solid" && color === "danger"'
|
|
class:bg-[var(--wire-color-surface-raised)]='variant === "outline" || variant === "soft"'
|
|
class:text-[var(--wire-color-primary)]='variant === "outline" || variant === "soft"'
|
|
style='--wire-back-to-top-progress: {progress}%;'
|
|
@window:scroll='visible = window.scrollY >= threshold; progress = Math.min(100, Math.round((window.scrollY / Math.max(1, document.documentElement.scrollHeight - window.innerHeight)) * 100))'
|
|
@click='window.scrollTo({ top: 0, behavior: behavior })'
|
|
>
|
|
{#if showProgress}
|
|
<span class="wire-back-to-top-progress absolute inset-0 rounded-full" aria-hidden="true"></span>
|
|
{/if}
|
|
<span class='{icon + " relative z-10 size-5"}' aria-hidden="true"></span>
|
|
<span class="sr-only">{label}</span>
|
|
</button>
|
|
}
|
|
|
|
style {
|
|
.wire-back-to-top-progress {
|
|
background: conic-gradient(
|
|
currentColor var(--wire-back-to-top-progress),
|
|
transparent var(--wire-back-to-top-progress)
|
|
);
|
|
opacity: 0.22;
|
|
}
|
|
}
|
|
}
|