Skip to content

Commit 4e7aef9

Browse files
committed
feat: add ScrollToTop component
1 parent 5e3a5d8 commit 4e7aef9

1 file changed

Lines changed: 54 additions & 0 deletions

File tree

app/components/ScrollToTop.vue

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<script setup lang="ts">
2+
const route = useRoute()
3+
4+
// Pages where scroll-to-top should NOT be shown
5+
const excludedRoutes = new Set(['index', 'code'])
6+
7+
const isActive = computed(() => !excludedRoutes.has(route.name as string))
8+
9+
const isVisible = ref(false)
10+
const scrollThreshold = 300
11+
12+
function onScroll() {
13+
isVisible.value = window.scrollY > scrollThreshold
14+
}
15+
16+
function scrollToTop() {
17+
window.scrollTo({ top: 0, behavior: 'smooth' })
18+
}
19+
20+
onMounted(() => {
21+
window.addEventListener('scroll', onScroll, { passive: true })
22+
onScroll()
23+
})
24+
25+
onUnmounted(() => {
26+
window.removeEventListener('scroll', onScroll)
27+
})
28+
</script>
29+
30+
<template>
31+
<Transition name="fade">
32+
<button
33+
v-if="isActive && isVisible"
34+
type="button"
35+
class="fixed top-16 left-1/2 -translate-x-1/2 z-50 p-3 bg-bg-elevated border border-border rounded-full shadow-lg md:hidden active:scale-95"
36+
aria-label="Scroll to top"
37+
@click="scrollToTop"
38+
>
39+
<span class="i-carbon-chevron-up w-5 h-5 block text-fg" aria-hidden="true" />
40+
</button>
41+
</Transition>
42+
</template>
43+
44+
<style scoped>
45+
.fade-enter-active,
46+
.fade-leave-active {
47+
transition: opacity 0.2s ease;
48+
}
49+
50+
.fade-enter-from,
51+
.fade-leave-to {
52+
opacity: 0;
53+
}
54+
</style>

0 commit comments

Comments
 (0)