| import { useGlobal } from '@/lib/global' |
| import Link from 'next/link' |
| import { useCallback, useEffect, useRef, useState } from 'react' |
| import CategoryGroup from './CategoryGroup' |
| import Logo from './Logo' |
| import SearchDrawer from './SearchDrawer' |
| import TagGroups from './TagGroups' |
| import { MenuListTop } from './MenuListTop' |
| import throttle from 'lodash.throttle' |
| import SideBar from './SideBar' |
| import SideBarDrawer from './SideBarDrawer' |
| import { siteConfig } from '@/lib/config' |
| import SearchButton from './SearchButton' |
| import CONFIG from '../config' |
| import { useRouter } from 'next/router' |
|
|
| let windowTop = 0 |
|
|
| |
| |
| |
| |
| |
| const TopNav = props => { |
| const searchDrawer = useRef() |
| const { tags, currentTag, categories, currentCategory } = props |
| const { locale } = useGlobal() |
| const router = useRouter() |
| const [isOpen, changeShow] = useState(false) |
| const showSearchButton = siteConfig('HEXO_MENU_SEARCH', false, CONFIG) |
|
|
| const toggleMenuOpen = () => { |
| changeShow(!isOpen) |
| } |
|
|
| const toggleSideBarClose = () => { |
| changeShow(false) |
| } |
|
|
| |
| useEffect(() => { |
| window.addEventListener('scroll', topNavStyleHandler) |
| router.events.on('routeChangeComplete', topNavStyleHandler) |
| topNavStyleHandler() |
| return () => { |
| router.events.off('routeChangeComplete', topNavStyleHandler) |
| window.removeEventListener('scroll', topNavStyleHandler) |
| } |
| }, []) |
|
|
| const throttleMs = 200 |
|
|
| const topNavStyleHandler = useCallback(throttle(() => { |
| const scrollS = window.scrollY |
| const nav = document.querySelector('#sticky-nav') |
| |
| const header = document.querySelector('#header') |
| |
| const scrollInHeader = header && (scrollS < 10 || scrollS < header?.clientHeight - 50) |
|
|
| |
|
|
| if (scrollInHeader) { |
| nav && nav.classList.replace('bg-white', 'bg-none') |
| nav && nav.classList.replace('border', 'border-transparent') |
| nav && nav.classList.replace('drop-shadow-md', 'shadow-none') |
| nav && nav.classList.replace('dark:bg-hexo-black-gray', 'transparent') |
| } else { |
| nav && nav.classList.replace('bg-none', 'bg-white') |
| nav && nav.classList.replace('border-transparent', 'border') |
| nav && nav.classList.replace('shadow-none', 'drop-shadow-md') |
| nav && nav.classList.replace('transparent', 'dark:bg-hexo-black-gray') |
| } |
|
|
| if (scrollInHeader) { |
| nav && nav.classList.replace('text-black', 'text-white') |
| } else { |
| nav && nav.classList.replace('text-white', 'text-black') |
| } |
|
|
| |
| const showNav = scrollS <= windowTop || scrollS < 5 || (header && scrollS <= header.clientHeight + 100) |
| if (!showNav) { |
| nav && nav.classList.replace('top-0', '-top-20') |
| windowTop = scrollS |
| } else { |
| nav && nav.classList.replace('-top-20', 'top-0') |
| windowTop = scrollS |
| } |
| }, throttleMs) |
| ) |
|
|
| const searchDrawerSlot = <> |
| {categories && ( |
| <section className='mt-8'> |
| <div className='text-sm flex flex-nowrap justify-between font-light px-2'> |
| <div className='text-gray-600 dark:text-gray-200'><i className='mr-2 fas fa-th-list' />{locale.COMMON.CATEGORY}</div> |
| <Link |
| href={'/category'} |
| passHref |
| className='mb-3 text-gray-400 hover:text-black dark:text-gray-400 dark:hover:text-white hover:underline cursor-pointer'> |
| |
| {locale.COMMON.MORE} <i className='fas fa-angle-double-right' /> |
| |
| </Link> |
| </div> |
| <CategoryGroup currentCategory={currentCategory} categories={categories} /> |
| </section> |
| )} |
| |
| {tags && ( |
| <section className='mt-4'> |
| <div className='text-sm py-2 px-2 flex flex-nowrap justify-between font-light dark:text-gray-200'> |
| <div className='text-gray-600 dark:text-gray-200'><i className='mr-2 fas fa-tag' />{locale.COMMON.TAGS}</div> |
| <Link |
| href={'/tag'} |
| passHref |
| className='text-gray-400 hover:text-black dark:hover:text-white hover:underline cursor-pointer'> |
| |
| {locale.COMMON.MORE} <i className='fas fa-angle-double-right' /> |
| |
| </Link> |
| </div> |
| <div className='p-2'> |
| <TagGroups tags={tags} currentTag={currentTag} /> |
| </div> |
| </section> |
| )} |
| </> |
|
|
| return (<div id='top-nav' className='z-40'> |
| <SearchDrawer cRef={searchDrawer} slot={searchDrawerSlot} /> |
| |
| {/* 导航栏 */} |
| <div id='sticky-nav' style={{ backdropFilter: 'blur(3px)' }} className={'top-0 duration-300 transition-all shadow-none fixed bg-none dark:bg-hexo-black-gray dark:text-gray-200 text-black w-full z-20 transform border-transparent dark:border-transparent'}> |
| <div className='w-full flex justify-between items-center px-4 py-2'> |
| <div className='flex'> |
| <Logo {...props} /> |
| </div> |
| |
| {/* 右侧功能 */} |
| <div className='mr-1 flex justify-end items-center '> |
| <div className='hidden lg:flex'> <MenuListTop {...props} /></div> |
| <div onClick={toggleMenuOpen} className='w-8 justify-center items-center h-8 cursor-pointer flex lg:hidden'> |
| {isOpen ? <i className='fas fa-times' /> : <i className='fas fa-bars' />} |
| </div> |
| {showSearchButton && <SearchButton />} |
| </div> |
| </div> |
| </div> |
| |
| {/* 折叠侧边栏 */} |
| <SideBarDrawer isOpen={isOpen} onClose={toggleSideBarClose}> |
| <SideBar {...props} /> |
| </SideBarDrawer> |
| </div>) |
| } |
|
|
| export default TopNav |
|
|