[READ-ONLY] a fast, modern browser for the npm registry
at main 93 lines 2.7 kB view raw
1<script setup lang="ts"> 2const route = useRoute() 3 4// Pages where scroll-to-top should NOT be shown 5const excludedRoutes = new Set(['index', 'code']) 6 7const isActive = computed(() => !excludedRoutes.has(route.name as string)) 8 9const isMounted = useMounted() 10const isVisible = shallowRef(false) 11const scrollThreshold = 300 12const { isSupported: supportsScrollStateQueries } = useCssSupports( 13 'container-type', 14 'scroll-state', 15 { ssrValue: false }, 16) 17 18function onScroll() { 19 if (!supportsScrollStateQueries.value) { 20 return 21 } 22 isVisible.value = window.scrollY > scrollThreshold 23} 24 25function scrollToTop() { 26 window.scrollTo({ top: 0, behavior: 'smooth' }) 27} 28 29useEventListener('scroll', onScroll, { passive: true }) 30 31onMounted(() => { 32 onScroll() 33}) 34</script> 35 36<template> 37 <!-- When CSS scroll-state is supported, use CSS-only visibility --> 38 <button 39 v-if="isActive && supportsScrollStateQueries" 40 type="button" 41 class="scroll-to-top-css fixed bottom-4 inset-ie-4 z-50 w-12 h-12 bg-bg-elevated border border-border rounded-full shadow-lg md:hidden flex items-center justify-center text-fg-muted hover:text-fg transition-colors active:scale-95" 42 :aria-label="$t('common.scroll_to_top')" 43 @click="scrollToTop" 44 > 45 <span class="i-lucide:arrow-up w-5 h-5" aria-hidden="true" /> 46 </button> 47 48 <!-- JS fallback for browsers without scroll-state support --> 49 <Transition 50 v-else 51 enter-active-class="transition-all duration-200" 52 enter-from-class="opacity-0 translate-y-2" 53 enter-to-class="opacity-100 translate-y-0" 54 leave-active-class="transition-all duration-200" 55 leave-from-class="opacity-100 translate-y-0" 56 leave-to-class="opacity-0 translate-y-2" 57 > 58 <button 59 v-if="isActive && isMounted && isVisible" 60 type="button" 61 class="fixed bottom-4 inset-ie-4 z-50 w-12 h-12 bg-bg-elevated border border-border rounded-full shadow-lg md:hidden flex items-center justify-center text-fg-muted hover:text-fg transition-colors active:scale-95" 62 :aria-label="$t('common.scroll_to_top')" 63 @click="scrollToTop" 64 > 65 <span class="i-lucide:arrow-up w-5 h-5" aria-hidden="true" /> 66 </button> 67 </Transition> 68</template> 69 70<style scoped> 71/* 72 * CSS scroll-state container queries (Chrome 133+) 73 * Hide button by default, show when page can be scrolled up (user has scrolled down) 74 */ 75@supports (container-type: scroll-state) { 76 .scroll-to-top-css { 77 opacity: 0; 78 transform: translateY(0.5rem); 79 pointer-events: none; 80 transition: 81 opacity 0.2s ease, 82 transform 0.2s ease; 83 } 84 85 @container scroll-state(scrollable: top) { 86 .scroll-to-top-css { 87 opacity: 1; 88 transform: translateY(0); 89 pointer-events: auto; 90 } 91 } 92} 93</style>