UNPKG

valaxy-theme-sakura

Version:

<h1 align="center">valaxy-theme-sakura</h1> <pre align="center"> 一个简单、个性化、可爱的动漫风格博客主题 ❥(ゝω・✿ฺ) </pre>

170 lines (138 loc) 3.69 kB
import { isClient } from '@vueuse/core' import { type ComputedRef, type Ref, computed, onMounted, onUnmounted, ref, watch, watchEffect, watchPostEffect, } from 'vue' import { useRoute } from 'vue-router' import type { SidebarItem } from '../types' export interface SidebarControl { collapsed: Ref<boolean> collapsible: ComputedRef<boolean> isLink: ComputedRef<boolean> isActiveLink: Ref<boolean> hasActiveLink: ComputedRef<boolean> hasChildren: ComputedRef<boolean> toggle: () => void } export const HASH_RE = /#.*$/ export const EXT_RE = /(index)?\.(md|html)$/ export function normalize(path: string): string { return decodeURI(path).replace(HASH_RE, '').replace(EXT_RE, '') } export function isActive( currentPath: string, matchPath?: string, asRegex: boolean = false, ): boolean { if (matchPath === undefined) return false currentPath = normalize(`/${currentPath}`) if (asRegex) return new RegExp(matchPath).test(currentPath) if (normalize(matchPath) !== currentPath) return false const hashMatch = matchPath.match(HASH_RE) if (hashMatch) return (isClient ? location.hash : '') === hashMatch[0] return true } /** * a11y: cache the element that opened the Sidebar (the menu button) then * focus that button again when Menu is closed with Escape key. */ export function useCloseSidebarOnEscape( isOpen: Ref<boolean>, close: () => void, ) { let triggerElement: HTMLButtonElement | undefined watchEffect(() => { triggerElement = isOpen.value ? (document.activeElement as HTMLButtonElement) : undefined }) onMounted(() => { window.addEventListener('keyup', onEscape) }) onUnmounted(() => { window.removeEventListener('keyup', onEscape) }) function onEscape(e: KeyboardEvent) { if (e.key === 'Escape' && isOpen.value) { close() triggerElement?.focus() } } } const hashRef = ref(isClient ? location.hash : '') if (isClient) { window.addEventListener('hashchange', () => { hashRef.value = location.hash }) } /** * Check if the given sidebar item contains any active link. */ export function containsActiveLink( path: string, items: SidebarItem | SidebarItem[], ): boolean { if (Array.isArray(items)) return items.some(item => containsActiveLink(path, item)) return isActive(path, items.link) ? true : items.items ? containsActiveLink(path, items.items) : false } export function useSidebarControl( item: ComputedRef<SidebarItem>, ): SidebarControl { const collapsed = ref(false) const collapsible = computed(() => { return item.value.collapsed != null }) const isLink = computed(() => { return !!item.value.link }) const isActiveLink = ref(false) const route = useRoute() const updateIsActiveLink = () => { isActiveLink.value = route.path === item.value.link } watch([route, item, hashRef], updateIsActiveLink) onMounted(updateIsActiveLink) const hasActiveLink = computed(() => { if (isActiveLink.value) return true return item.value.items ? containsActiveLink(route.path, item.value.items) : false }) const hasChildren = computed(() => { return !!(item.value.items && item.value.items.length) }) watchEffect(() => { collapsed.value = !!(collapsible.value && item.value.collapsed) }) watchPostEffect(() => (isActiveLink.value || hasActiveLink.value) && (collapsed.value = false)) function toggle() { if (collapsible.value) collapsed.value = !collapsed.value } return { collapsed, collapsible, isLink, isActiveLink, hasActiveLink, hasChildren, toggle, } }