feat(theme): add backTop button
This commit is contained in:
parent
c0ea46b8c5
commit
93e034fa9f
63
packages/theme/src/client/components/BackToTop.vue
Normal file
63
packages/theme/src/client/components/BackToTop.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
import { scrollTo } from '../utils'
|
||||
import { BackTopIcon } from './icons'
|
||||
|
||||
const opacity = ref<number>(0)
|
||||
const MAX_TOP = 300
|
||||
|
||||
const canShow = (): void => {
|
||||
if (__VUEPRESS_SSR__) return
|
||||
opacity.value = document.documentElement.scrollTop >= MAX_TOP ? 1 : 0
|
||||
}
|
||||
|
||||
const scrollToTop = (): void => {
|
||||
scrollTo(document, 0)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (__VUEPRESS_SSR__) return
|
||||
canShow()
|
||||
window.addEventListener('scroll', canShow, false)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (__VUEPRESS_SSR__) return
|
||||
window.removeEventListener('scroll', canShow)
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="btn-back-top" :style="{ opacity: opacity }" @click="scrollToTop">
|
||||
<BackTopIcon />
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
.btn-back-top {
|
||||
position: fixed;
|
||||
right: 3rem;
|
||||
bottom: 3rem;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
text-align: center;
|
||||
padding: 0.75rem 0;
|
||||
border-radius: 50%;
|
||||
background-color: var(--c-bg-container);
|
||||
box-shadow: var(--shadow-md);
|
||||
cursor: pointer;
|
||||
transition: opacity var(--t-color);
|
||||
z-index: 99;
|
||||
|
||||
.back-top-icon {
|
||||
width: 1.75rem;
|
||||
height: 1.75rem;
|
||||
color: var(--c-brand);
|
||||
transition: color var(--t-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.back-top-icon {
|
||||
color: var(--c-brand-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -64,3 +64,11 @@ export const ArrowRightIcon: FunctionalComponent = () =>
|
||||
})
|
||||
)
|
||||
ArrowRightIcon.displayName = 'ArrowRightIcon'
|
||||
|
||||
export const BackTopIcon: FunctionalComponent = () =>
|
||||
h(IconBase, { name: 'back-top', viewBox: '0 0 1024 1024' }, () =>
|
||||
h('path', {
|
||||
d: 'M832 64H192c-17.6 0-32 14.4-32 32s14.4 32 32 32h640c17.6 0 32-14.4 32-32s-14.4-32-32-32zM852.484 519.469L538.592 205.577a30.79 30.79 0 0 0-3.693-4.476c-6.241-6.241-14.556-9.258-22.899-9.09-8.343-0.168-16.658 2.849-22.899 9.09a30.778 30.778 0 0 0-3.693 4.476L171.419 519.566C164.449 525.448 160 534.228 160 544c0 0.058 0.004 0.115 0.004 0.172-0.124 8.285 2.899 16.529 9.096 22.727 6.202 6.202 14.453 9.224 22.743 9.096 0.066 0 0.131 0.005 0.197 0.005H352v320c0 35.2 28.8 64 64 64h192c35.2 0 64-28.8 64-64V576h160c0.058 0 0.115-0.004 0.172-0.004 8.285 0.124 16.529-2.899 22.727-9.096 6.198-6.198 9.22-14.442 9.096-22.727 0-0.058 0.004-0.115 0.004-0.172 0.001-9.826-4.489-18.65-11.515-24.532z',
|
||||
})
|
||||
)
|
||||
BackTopIcon.displayName = 'BackTopIcon'
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import Archive from '@theme-plume/Archive.vue'
|
||||
import AsideNavbar from '@theme-plume/AsideNavbar.vue'
|
||||
import BackToTop from '@theme-plume/BackToTop.vue'
|
||||
import Category from '@theme-plume/Category.vue'
|
||||
import Home from '@theme-plume/Home.vue'
|
||||
import Navbar from '@theme-plume/Navbar.vue'
|
||||
@ -58,6 +59,7 @@ const pageMap = {
|
||||
</template>
|
||||
</Page>
|
||||
</slot>
|
||||
<BackToTop />
|
||||
<slot name="footer">
|
||||
<PageFooter></PageFooter>
|
||||
</slot>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user