import { useCallback, useEffect, useState } from 'react' import Link from 'next/link' import { useRouter } from 'next/router' import clsx from 'clsx' import { Hero } from '@/components/Hero' import { Logo } from '@/components/Logo' import { MobileNavigation } from '@/components/MobileNavigation' import { Navigation } from '@/components/Navigation' import { Prose } from '@/components/Prose' import { Search } from '@/components/Search' import { ThemeSelector } from '@/components/ThemeSelector' function Header({ navigation }) { let [isScrolled, setIsScrolled] = useState(false) useEffect(() => { function onScroll() { setIsScrolled(window.scrollY > 0) } onScroll() window.addEventListener('scroll', onScroll) return () => { window.removeEventListener('scroll', onScroll) } }, []) return (
Home page
GitHub
) } export function Layout({ children, title, navigation, tableOfContents }) { let router = useRouter() let isHomePage = router.pathname === '/' let allLinks = navigation.flatMap((section) => section.links) let linkIndex = allLinks.findIndex((link) => link.href === router.pathname) let previousPage = allLinks[linkIndex - 1] let nextPage = allLinks[linkIndex + 1] let section = navigation.find((section) => section.links.find((link) => link.href === router.pathname) ) let currentSection = useTableOfContents(tableOfContents) function isActive(section) { if (section.id === currentSection) { return true } if (!section.children) { return false } return section.children.findIndex(isActive) > -1 } return ( <>
{isHomePage && }
{(title || section) && (
{section && (

{section.title}

)} {title && (

{title}

)}
)} {children}
{previousPage && ( )} {nextPage && ( )}
) } function useTableOfContents(tableOfContents) { let [currentSection, setCurrentSection] = useState(tableOfContents[0]?.id) let getHeadings = useCallback(() => { function* traverse(node) { if (Array.isArray(node)) { for (let child of node) { yield* traverse(child) } } else { let el = document.getElementById(node.id) if (!el) return let style = window.getComputedStyle(el) let scrollMt = parseFloat(style.scrollMarginTop) let top = window.scrollY + el.getBoundingClientRect().top - scrollMt yield { id: node.id, top } for (let child of node.children ?? []) { yield* traverse(child) } } } return Array.from(traverse(tableOfContents)) }, [tableOfContents]) useEffect(() => { let headings = getHeadings() if (tableOfContents.length === 0 || headings.length === 0) return function onScroll() { let sortedHeadings = headings.concat([]).sort((a, b) => a.top - b.top) let top = window.pageYOffset let current = sortedHeadings[0].id for (let i = 0; i < sortedHeadings.length; i++) { if (top >= sortedHeadings[i].top) { current = sortedHeadings[i].id } } setCurrentSection(current) } window.addEventListener('scroll', onScroll, { capture: true, passive: true, }) onScroll() return () => { window.removeEventListener('scroll', onScroll, { capture: true, passive: true, }) } }, [getHeadings, tableOfContents]) return currentSection }