'use client' import { Popover, Transition } from '@headlessui/react' import clsx from 'clsx' import Image from 'next/image' import { usePathname } from 'next/navigation' import { Fragment, type HTMLAttributes, type PropsWithChildren, useEffect, useRef, } from 'react' import { Container } from '@/components/Container' import avatarImage from '@/images/me.jpeg' import { PopoverProps } from '@/lib/types' import HybridLink, { Props as HydridLinkProps } from './HybridLink' import { ChevronDownIcon, CloseIcon, MoonIcon, SunIcon } from './icons' const MobileNavItem = ({ href, children, }: PropsWithChildren<{ href: HydridLinkProps['href'] }>) => { return (
  • {children}
  • ) } const MobileNavigation = (props: PopoverProps) => { return ( Menu

    Menu

    ) } const NavItem = ({ href, children }: HydridLinkProps) => { const isActive = usePathname() === href return (
  • {children} {isActive && ( )}
  • ) } const DesktopNavigation = (props: HTMLAttributes) => { return ( ) } const ModeToggle = () => { const disableTransitionsTemporarily = () => { document.documentElement.classList.add('[&_*]:!transition-none') window.setTimeout(() => { document.documentElement.classList.remove('[&_*]:!transition-none') }, 0) } const toggleMode = () => { disableTransitionsTemporarily() const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)') const isSystemDarkMode = darkModeMediaQuery.matches const isDarkMode = document.documentElement.classList.toggle('dark') if (isDarkMode === isSystemDarkMode) { delete window.localStorage.isDarkMode } else { window.localStorage.isDarkMode = isDarkMode } } return ( ) } const clamp = (number: number, a: number, b: number) => { const min = Math.min(a, b) const max = Math.max(a, b) return Math.min(Math.max(number, min), max) } const AvatarContainer = ({ className, ...props }: HTMLAttributes) => { return (
    ) } const Avatar = ({ large = false, className, ...props }: Omit & { large?: boolean }) => { return ( ) } const Header = () => { const isHomePage = usePathname() === '/' const headerRef = useRef(null) const avatarRef = useRef(null) const isInitial = useRef(true) useEffect(() => { const downDelay = avatarRef.current?.offsetTop ?? 0 const upDelay = 64 const setProperty = (property: string, value: string | null) => { document.documentElement.style.setProperty(property, value) } const removeProperty = (property: string) => { document.documentElement.style.removeProperty(property) } const updateHeaderStyles = () => { const { top, height } = headerRef.current!.getBoundingClientRect() const scrollY = clamp( window.scrollY, 0, document.body.scrollHeight - window.innerHeight, ) if (isInitial.current) { setProperty('--header-position', 'sticky') } setProperty('--content-offset', `${downDelay}px`) if (isInitial.current || scrollY < downDelay) { setProperty('--header-height', `${downDelay + height}px`) setProperty('--header-mb', `${-downDelay}px`) } else if (top + height < -upDelay) { const offset = Math.max(height, scrollY - upDelay) setProperty('--header-height', `${offset}px`) setProperty('--header-mb', `${height - offset}px`) } else if (top === 0) { setProperty('--header-height', `${scrollY + height}px`) setProperty('--header-mb', `${-scrollY}px`) } if (top === 0 && scrollY > 0 && scrollY >= downDelay) { setProperty('--header-inner-position', 'fixed') removeProperty('--header-top') removeProperty('--avatar-top') } else { removeProperty('--header-inner-position') setProperty('--header-top', '0px') setProperty('--avatar-top', '0px') } } function updateAvatarStyles() { if (!isHomePage) { return } const fromScale = 1 const toScale = 36 / 64 const fromX = 0 const toX = 2 / 16 const scrollY = downDelay - window.scrollY let scale = (scrollY * (fromScale - toScale)) / downDelay + toScale scale = clamp(scale, fromScale, toScale) let x = (scrollY * (fromX - toX)) / downDelay + toX x = clamp(x, fromX, toX) setProperty( '--avatar-image-transform', `translate3d(${x}rem, 0, 0) scale(${scale})`, ) const borderScale = 1 / (toScale / scale) const borderX = (-toX + x) * borderScale const borderTransform = `translate3d(${borderX}rem, 0, 0) scale(${borderScale})` setProperty('--avatar-border-transform', borderTransform) setProperty('--avatar-border-opacity', scale === toScale ? '1' : '0') } function updateStyles() { updateHeaderStyles() updateAvatarStyles() isInitial.current = false } updateStyles() window.addEventListener('scroll', updateStyles, { passive: true }) window.addEventListener('resize', updateStyles) return () => { window.removeEventListener('scroll', updateStyles) window.removeEventListener('resize', updateStyles) } }, [isHomePage]) return ( <>
    {isHomePage && ( <>
    )}
    {!isHomePage && ( )}
    {isHomePage &&
    } ) } export default Header