mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-19 23:16:48 +00:00
theme-heo top-nav
This commit is contained in:
@@ -17,7 +17,6 @@ export const MenuItemDrop = ({ link }) => {
|
||||
href={link?.to}
|
||||
className="font-sans hover:bg-black hover:bg-opacity-10 rounded-2xl flex justify-center items-center px-3 py-1 no-underline tracking-widest">
|
||||
{link?.icon && <i className={link?.icon} />} {link?.name}
|
||||
{hasSubMenu && <i className='px-2 fa fa-angle-down'></i>}
|
||||
</Link>}
|
||||
|
||||
{/* 含子菜单的按钮 */}
|
||||
|
||||
@@ -5,7 +5,9 @@ import RandomPostButton from './RandomPostButton'
|
||||
import SearchButton from './SearchButton'
|
||||
import SlideOver from './SlideOver'
|
||||
import ReadingProgress from './ReadingProgress'
|
||||
import NavBarSwipe from './NavBarSwipe'
|
||||
import { MenuListTop } from './MenuListTop'
|
||||
import { isBrowser } from '@/lib/utils'
|
||||
import BLOG from '@/blog.config'
|
||||
/**
|
||||
* 顶部导航
|
||||
* @param {*} param0
|
||||
@@ -15,6 +17,9 @@ const NavBar = props => {
|
||||
const [fixedNav, setFixedNav] = useState(false)
|
||||
const [textWhite, setTextWhite] = useState(false)
|
||||
const [navBgWhite, setBgWhite] = useState(false)
|
||||
|
||||
const [activeIndex, setActiveIndex] = useState(0)
|
||||
|
||||
const slideOverRef = useRef()
|
||||
|
||||
const toggleMenuOpen = () => {
|
||||
@@ -33,8 +38,8 @@ const NavBar = props => {
|
||||
const throttleMs = 200
|
||||
|
||||
/**
|
||||
* 根据滚动条,切换导航栏样式
|
||||
*/
|
||||
* 根据滚动条,切换导航栏样式
|
||||
*/
|
||||
const scrollTrigger = useCallback(throttle(() => {
|
||||
const scrollS = window.scrollY
|
||||
|
||||
@@ -57,7 +62,74 @@ const NavBar = props => {
|
||||
}
|
||||
}, throttleMs))
|
||||
|
||||
// 监听导航栏显示文字
|
||||
useEffect(() => {
|
||||
let prevScrollY = 0
|
||||
let ticking = false
|
||||
|
||||
const handleScroll = () => {
|
||||
if (!ticking) {
|
||||
window.requestAnimationFrame(() => {
|
||||
const currentScrollY = window.scrollY
|
||||
|
||||
if (currentScrollY > prevScrollY) {
|
||||
setActiveIndex(1) // 向下滚动时设置activeIndex为1
|
||||
} else {
|
||||
setActiveIndex(0) // 向上滚动时设置activeIndex为0
|
||||
}
|
||||
|
||||
prevScrollY = currentScrollY
|
||||
ticking = false
|
||||
})
|
||||
|
||||
ticking = true
|
||||
}
|
||||
}
|
||||
|
||||
if (isBrowser()) {
|
||||
window.addEventListener('scroll', handleScroll)
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (isBrowser()) {
|
||||
window.removeEventListener('scroll', handleScroll)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (<>
|
||||
<style jsx>{`
|
||||
@keyframes fade-in-down {
|
||||
0% {
|
||||
opacity: 0.5;
|
||||
transform: translateY(-30%);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in-up {
|
||||
0% {
|
||||
opacity: 0.5;
|
||||
transform: translateY(30%);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.fade-in-down {
|
||||
animation: fade-in-down 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.fade-in-up {
|
||||
animation: fade-in-up 0.3s ease-in-out;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
{/* 顶部导航菜单栏 */}
|
||||
<nav id='nav' className={`${fixedNav ? 'fixed' : 'relative bg-none'} ${textWhite ? 'text-white ' : 'text-black dark:text-white'} ${navBgWhite ? 'bg-white dark:bg-[#18171d]' : 'bg-none'} z-20 h-16 top-0 w-full`}>
|
||||
<div className='flex h-full mx-auto justify-between items-center max-w-[86rem] px-8'>
|
||||
@@ -67,13 +139,16 @@ const NavBar = props => {
|
||||
</div>
|
||||
|
||||
{/* 中间菜单 */}
|
||||
<NavBarSwipe {...props}/>
|
||||
<div id='nav-bar-swipe' className={`hidden lg:flex flex-grow flex-col items-center justify-center h-full relative w-full ${activeIndex === 0 ? 'fade-in-down' : 'fade-in-up'}`}>
|
||||
{activeIndex === 0 && <MenuListTop {...props} />}
|
||||
{activeIndex === 1 && <h1 className='font-bold text-center text-light-400 dark:text-gray-400'>{BLOG.AUTHOR || BLOG.TITLE} | {BLOG.BIO}</h1>}
|
||||
</div>
|
||||
|
||||
{/* 右侧固定 */}
|
||||
<div className='flex justify-center items-center space-x-1'>
|
||||
<div className='flex flex-shrink-0 justify-center items-center space-x-1'>
|
||||
<RandomPostButton {...props} />
|
||||
<SearchButton />
|
||||
<ReadingProgress/>
|
||||
<ReadingProgress />
|
||||
|
||||
{/* 移动端菜单按钮 */}
|
||||
<div onClick={toggleMenuOpen} className='flex lg:hidden w-8 justify-center items-center h-8 cursor-pointer'>
|
||||
@@ -82,7 +157,7 @@ const NavBar = props => {
|
||||
</div>
|
||||
|
||||
{/* 右边侧拉抽屉 */}
|
||||
<SlideOver cRef={slideOverRef} {...props}/>
|
||||
<SlideOver cRef={slideOverRef} {...props} />
|
||||
</div>
|
||||
</nav>
|
||||
</>)
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { isBrowser } from '@/lib/utils'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { MenuListTop } from './MenuListTop'
|
||||
|
||||
/**
|
||||
* 一个swipe组件
|
||||
* 垂直方向,g给导航栏用
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
export default function NavSwipe(props) {
|
||||
const [activeIndex, setActiveIndex] = useState(0)
|
||||
|
||||
const item1 = (
|
||||
<div className='mr-1 justify-end items-center hidden lg:block'>
|
||||
<div className='hidden lg:flex'>
|
||||
<MenuListTop {...props} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const item2 = <h1 className='font-bold text-light-400 dark:text-gray-400'>{BLOG.AUTHOR || BLOG.TITLE} | {BLOG.BIO}</h1>
|
||||
const items = [item1, item2]
|
||||
|
||||
useEffect(() => {
|
||||
let prevScrollY = 0
|
||||
let ticking = false
|
||||
|
||||
const handleScroll = () => {
|
||||
if (!ticking) {
|
||||
window.requestAnimationFrame(() => {
|
||||
const currentScrollY = window.scrollY
|
||||
|
||||
if (currentScrollY > prevScrollY) {
|
||||
setActiveIndex(1) // 向下滚动时设置activeIndex为1
|
||||
} else {
|
||||
setActiveIndex(0) // 向上滚动时设置activeIndex为0
|
||||
}
|
||||
|
||||
prevScrollY = currentScrollY
|
||||
ticking = false
|
||||
})
|
||||
|
||||
ticking = true
|
||||
}
|
||||
}
|
||||
|
||||
if (isBrowser()) {
|
||||
window.addEventListener('scroll', handleScroll)
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (isBrowser()) {
|
||||
window.removeEventListener('scroll', handleScroll)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="hidden lg:block h-full relative w-full overflow-hidden">
|
||||
{items.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`absolute top-0 bottom-0 w-full h-full flex justify-center items-center line-clamp-1 transform transition-transform duration-500 ${
|
||||
index === activeIndex ? 'slide-in' : 'slide-out'
|
||||
}`}
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
|
||||
<style jsx>{`
|
||||
.slide-in {
|
||||
animation-name: slide-in;
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
.slide-out {
|
||||
animation-name: slide-out;
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes slide-in {
|
||||
from {
|
||||
transform: translateY(${activeIndex === 1 ? '100%' : '-100%'});
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-out {
|
||||
from {
|
||||
transform: translateY(0);
|
||||
}
|
||||
to {
|
||||
transform: translateY(${activeIndex === 1 ? '-100%' : '100%'});
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
Reference in New Issue
Block a user