UNPKG

nimiq-vitepress-theme

Version:

Nimiq UI theme for VitePress

94 lines (93 loc) 2.88 kB
import { createSharedComposable, useThrottleFn, useWindowSize } from "@vueuse/core"; import { useData, useRoute } from "vitepress"; import { computed, nextTick, onMounted, ref, watch } from "vue"; export const useSecondarySidebar = createSharedComposable(() => { const { frontmatter } = useData(); const headingTree = ref([]); const activeHeadings = ref([]); const { height: windowHeight } = useWindowSize(); function updateHeadingTree() { const nodes = document.querySelectorAll("article :where(h2,h3):not([data-card] *)"); const tree = []; let lastH2 = null; nodes.forEach((node) => { const el = node; if (!el.id || el.id === "changelog") return; const level = Number(el.tagName[1]); const heading = { hashPath: el.id, text: el.textContent?.trim() || "", level, items: [] }; if (level === 2) { tree.push(heading); lastH2 = heading; } else if (level === 3) { if (lastH2) { lastH2.items.push(heading); } else { tree.push(heading); } } }); headingTree.value = tree; } const updateActiveHeadings = useThrottleFn(async () => { await nextTick(); const active = []; function checkHeading(heading) { const el = document.getElementById(heading.hashPath); if (el) { const rect = el.getBoundingClientRect(); if (rect.top < windowHeight.value && rect.bottom > 0) { active.push(heading.hashPath); } } heading.items.forEach(checkHeading); } headingTree.value.forEach(checkHeading); activeHeadings.value = active; }, 100); const { y: scrollY } = typeof window ? { y: ref(0) } : useScroll(window); const route = useRoute(); watch(route, async () => { await nextTick(); updateHeadingTree(); }); onMounted(() => updateHeadingTree()); watch(scrollY, updateActiveHeadings); const layout = computed(() => frontmatter.value.layout || "docs"); const showOutline = computed(() => { if (frontmatter.value.outline !== void 0) return !!frontmatter.value.outline; if (layout.value === "home") return false; return headingTree.value.length > 0; }); const showWidget = computed(() => { if (frontmatter.value.widget !== void 0) return !!frontmatter.value.widget; if (layout.value === "home") return false; return true; }); const showSecondarySidebar = computed(() => { if (frontmatter.value.secondarySidebar !== void 0) return !!frontmatter.value.secondarySidebar; if (layout.value === "home") return false; return true; }); function isHeadingActive(hash) { return activeHeadings.value.includes(hash); } return { headingTree, isHeadingActive, showOutline, showWidget, showSecondarySidebar }; });