sideBar目录

This commit is contained in:
tangly1024
2021-11-05 16:25:39 +08:00
parent 299866d570
commit 5bcb50891c
13 changed files with 223 additions and 239 deletions

View File

@@ -1,92 +0,0 @@
import SearchInput from '@/components/SearchInput'
import MenuButtonGroup from '@/components/MenuButtonGroup'
import React, { useImperativeHandle, useState } from 'react'
import InfoCard from '@/components/InfoCard'
import TagList from '@/components/TagList'
import Logo from '@/components/Logo'
import LatestPosts from '@/components/LatestPosts'
import PostsCategories from '@/components/PostsCategories'
/**
* 抽屉面板,可以从侧面拉出
* @returns {JSX.Element}
* @constructor
*/
const Drawer = ({ post, currentTag, cRef, tags, posts, categories, currentCategory }) => {
// 暴露给父组件 通过cRef.current.handleMenuClick 调用
useImperativeHandle(cRef, () => {
return {
handleMenuClick: () => handleMenuClick()
}
})
const [isHidden, changeHiddenStatus] = useState(true)
// 点击按钮更改侧边抽屉状态
const handleMenuClick = () => {
changeHiddenStatus(!isHidden)
}
return <>
<div className='fixed top-0 left-0 z-50 h-screen shadow-2xl bg-white dark:bg-gray-800'>
{/* LOGO */}
<div
className={(isHidden ? '-ml-72' : '') + ' duration-200 w-72 border-r dark:border-gray-600'}>
<div className='w-72 flex space-x-4 px-5 py-1 dark:border-gray-500 '>
<div
className='z-10 py-2 duration-200 mr-2 text-gray-600 text-xl cursor-pointer dark:text-gray-300'>
<i className='fa hover:scale-125 transform duration-200 fa-bars ' onClick={handleMenuClick} />
</div>
<Logo/>
</div>
</div>
{/* 侧边菜单 */}
<div
className={(isHidden ? '-ml-72' : 'shadow-2xl') + ' overflow-y-scroll h-screen w-72 duration-200 overflow-y-auto'}>
<div className='pb-56'>
{/* 搜索框 */}
<div className='px-5 my-3 block md:hidden'>
<SearchInput currentTag={currentTag} />
</div>
{/* 信息卡 */}
<InfoCard />
<hr className='dark:border-gray-700' />
<MenuButtonGroup allowCollapse={true} />
<hr className='dark:border-gray-700 my-2' />
{/* 最新文章 */}
{posts && (
<div className='mt-2 sticky top-0'>
<LatestPosts posts={posts}/>
</div>
)}
{/* 分类 */}
{categories && (
<div className='mt-2'>
<PostsCategories currentCategory={currentCategory} categories={categories}/>
</div>
)}
{/* 标签云 */}
{tags && (
<div className='mt-2'>
<section
className='text-sm font-bold py-3 px-5 text-gray-600 dark:text-gray-400 dark:hover:bg-black duration-100 flex flex-nowrap align-middle'>
<div className='w-32'>标签</div>
</section>
<div className='px-5'>
<TagList tags={tags} currentTag={currentTag} />
</div>
</div>
)}
</div>
</div>
</div>
{/* 背景蒙版 */}
<div id='drawer-background' className={(isHidden ? 'hidden' : 'block') + ' fixed top-0 left-0 z-30 w-full h-full bg-black bg-opacity-30'}
onClick={handleMenuClick} />
</>
}
export default Drawer

View File

@@ -1,51 +0,0 @@
import TocBar from '@/components/TocBar'
import React, { useImperativeHandle, useState } from 'react'
/**
* 右侧边栏
* @param toc
* @param post
* @returns {JSX.Element}
* @constructor
*/
const DrawerRight = ({ post, cRef }) => {
// 暴露给父组件 通过cRef.current.handleMenuClick 调用
useImperativeHandle(cRef, () => {
return {
handleMenuClick: () => handleMenuClick()
}
})
const [showDrawer, switchShowDrawer] = useState(false)
const handleMenuClick = () => {
switchShowDrawer(!showDrawer)
}
return <div>
<div className='fixed top-0 right-0 z-40 h-full'>
<div
className={(showDrawer ? 'shadow-2xl' : '-mr-72') + ' overflow-y-auto duration-200 w-72 h-full bg-white dark:bg-gray-700 border-r dark:border-gray-600'}>
{/* LOGO */}
<div className='sticky top-0 z-20 bg-white w-72 flex space-x-4 px-5 py-3.5 dark:border-gray-500 border-b dark:bg-gray-900 '>
<div className='text-lg font-bold font-semibold px-2 py-1 duration-200 dark:text-gray-300'>文章目录
</div>
<div
className='z-10 p-1 duration-200 mr-2 absolute right-6 text-gray-600 text-xl cursor-pointer dark:text-gray-300'>
<i className='fa hover:scale-125 transform duration-200 fa-bookmark ' onClick={handleMenuClick} />
</div>
</div>
</div>
{/* 侧边菜单 */}
<div
className={(showDrawer ? 'shadow-2xl ' : ' -mr-72 ') + ' w-72 duration-200 h-full fixed right-0 top-16 overflow-y-auto'}>
<div className='z-20'>
{post && <TocBar toc={post.toc}/>}
</div>
</div>
</div>
{/* 背景蒙版 */}
<div id='right-drawer-background' className={(showDrawer ? 'block' : 'hidden') + ' fixed top-0 left-0 z-30 w-full h-full bg-black bg-opacity-50'}
onClick={handleMenuClick} />
</div>
}
export default DrawerRight

View File

@@ -10,7 +10,7 @@ import { useGlobal } from '@/lib/global'
* @returns {JSX.Element}
* @constructor
*/
const JumpToTop = ({ targetRef, showPercent = true }) => {
const JumpToTopButton = ({ targetRef, showPercent = true }) => {
const { locale } = useGlobal()
const [show, switchShow] = useState(false)
const [percent, changePercent] = useState(0)
@@ -33,7 +33,7 @@ const JumpToTop = ({ targetRef, showPercent = true }) => {
}, [show])
return (
<div id='jump-to-top' className='right-0 fixed flex bottom-24 mr-2.5 py-1 duration-500 z-20'>
<div id='jump-to-top' className='right-0 fixed flex bottom-24 mr-2.5 py-1 duration-500 z-20 opacity-75'>
<div className='transform hover:scale-105 duration-200 '>
<div
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
@@ -50,4 +50,4 @@ const JumpToTop = ({ targetRef, showPercent = true }) => {
)
}
export default JumpToTop
export default JumpToTopButton

View File

@@ -4,7 +4,20 @@ import InfoCard from '@/components/InfoCard'
import TagList from '@/components/TagList'
import LatestPosts from '@/components/LatestPosts'
import PostsCategories from '@/components/PostsCategories'
import Toc from '@/components/Toc'
import SearchInput from '@/components/SearchInput'
/**
* 侧边栏
* @param tags
* @param currentTag
* @param post
* @param posts
* @param categories
* @param currentCategory
* @returns {JSX.Element}
* @constructor
*/
const SideBar = ({ tags, currentTag, post, posts, categories, currentCategory }) => {
// 按时间排序
if (posts) {
@@ -15,47 +28,60 @@ const SideBar = ({ tags, currentTag, post, posts, categories, currentCategory })
}).slice(0, 5)
}
return <aside className='z-10 dark:border-gray-500 border-gray-200 bg-white hidden xl:block'>
<div
className='w-72 dark:bg-gray-800 h-full scroll-hidden left-0 duration-500 ease-in-out min-h-screen'>
<div id='sidebar' className='hidden md:block sticky top-20 pb-56 duration-500'>
<>
<InfoCard />
<hr className='dark:border-gray-700' />
<MenuButtonGroup allowCollapse={true} />
</>
return <aside id='sidebar' className='bg-white dark:bg-gray-800 w-72 z-10 dark:border-gray-500 border-gray-200 scroll-hidden h-full'>
<section>
<InfoCard />
</section>
<div className={(!post ? 'sticky top-0' : '') + ' bg-white dark:bg-gray-800'}>
{/* 搜索框 */}
<section className='p-5'>
<SearchInput currentTag={currentTag} />
</section>
<section>
<hr className='dark:border-gray-700' />
<MenuButtonGroup allowCollapse={true} />
<hr className='dark:border-gray-700 my-2' />
</section>
{/* 分类 */}
{categories && (
<div className='mt-2'>
<PostsCategories currentCategory={currentCategory} categories={categories}/>
{/* 分类 */}
{categories && (
<section className='mt-2'>
<PostsCategories currentCategory={currentCategory} categories={categories} />
</section>
)}
{/* 最新文章 */}
{posts && (
<section className='mt-2'>
<LatestPosts posts={posts} />
</section>
)}
{/* 标签云 */}
{tags && (
<section className='mt-2'>
<section
className='text-sm font-bold py-3 px-5 text-gray-600 dark:text-gray-400 duration-100 flex flex-nowrap align-middle'>
<div className='w-32'>标签</div>
</section>
<div className='px-5'>
<TagList tags={tags} currentTag={currentTag} />
</div>
)}
{/* 最新文章 */}
{posts && (
<div className='mt-2'>
<LatestPosts posts={posts}/>
</div>
)}
{/* 标签云 */}
{tags && (
<div className='mt-2'>
<section
className='text-sm font-bold py-3 px-5 text-gray-600 dark:text-gray-400 duration-100 flex flex-nowrap align-middle'>
<div className='w-32'>标签</div>
</section>
<div className='px-5'>
<TagList tags={tags} currentTag={currentTag} />
</div>
</div>
)}
</div>
</section>
)}
</div>
{post && (
<section id='left-toc' className='sticky top-0 bg-white dark:bg-gray-800'>
<Toc toc={post.toc} />
</section>
)}
<section id='blank' className='bg-white dark:bg-gray-800 py-20'/>
</aside>
}
export default SideBar

View File

@@ -0,0 +1,31 @@
import React, { useImperativeHandle, useState } from 'react'
import SideBar from '@/components/SideBar'
/**
* 侧边栏抽屉面板,可以从侧面拉出
* @returns {JSX.Element}
* @constructor
*/
const SideBarDrawer = ({ post, currentTag, cRef, tags, posts, categories, currentCategory }) => {
// 暴露给父组件 通过cRef.current.handleMenuClick 调用
useImperativeHandle(cRef, () => {
return {
handleSwitchSideDrawerVisible: () => switchSideDrawerVisible()
}
})
const [isHidden, changeHiddenStatus] = useState(true)
// 点击按钮更改侧边抽屉状态
const switchSideDrawerVisible = () => {
changeHiddenStatus(!isHidden)
}
return <div>
<div className={(isHidden ? '-ml-72' : 'shadow-2xl') + ' flex flex-col duration-300 fixed h-full left-0 overflow-y-scroll scroll-hidden top-0 z-50'}>
<SideBar tags={tags} post={post} posts={posts} categories={categories} currentCategory={currentCategory} />
</div>
{/* 背景蒙版 */}
<div id='drawer-background'
className={(isHidden ? 'hidden' : 'block') + ' fixed top-0 left-0 z-30 w-full h-full bg-black bg-opacity-30'}
onClick={switchSideDrawerVisible} />
</div>
}
export default SideBarDrawer

View File

@@ -10,7 +10,7 @@ import TagItemMini from '@/components/TagItemMini'
const TagList = ({ tags, currentTag }) => {
if (!tags) return <></>
return (
<div id='tags-list' className='duration-500 dark:border-gray-600 dark:bg-gray-800 w-66'>
<div id='tags-list' className='duration-500 dark:border-gray-600 dark:bg-gray-800 w-66'>
{Object.keys(tags).map(tag => {
const selected = tag === currentTag
return (

View File

@@ -9,7 +9,7 @@ import { cs } from 'react-notion-x'
* @returns {JSX.Element}
* @constructor
*/
const TocBar = ({ toc }) => {
const Toc = ({ toc }) => {
// 无目录就直接返回空
if (!toc || toc.length < 1) return <></>
@@ -50,8 +50,12 @@ const TocBar = ({ toc }) => {
setActiveSection(currentSectionId)
}, throttleMs))
return <div>
<nav className='text-gray-500 dark:text-gray-400 underline overflow-auto scroll-hidden py-2'>
return <>
<div
className=' dark:border-gray-600 border-b text-2xl bg-white font-bold text-black dark:bg-gray-900 dark:text-white py-6 px-6'>
文章目录
</div>
<nav className='text-gray-500 dark:text-gray-400 underline overflow-y-auto scroll-hidden p-2'>
{toc.map((tocItem) => {
const id = uuidToId(tocItem.id)
return (
@@ -78,7 +82,7 @@ const TocBar = ({ toc }) => {
)
})}
</nav>
</div>
</>
}
export default TocBar
export default Toc

38
components/TocDrawer.js Normal file
View File

@@ -0,0 +1,38 @@
import Toc from '@/components/Toc'
import React, { useImperativeHandle, useState } from 'react'
/**
* 目录抽屉栏
* @param toc
* @param post
* @returns {JSX.Element}
* @constructor
*/
const TocDrawer = ({ post, cRef }) => {
// 暴露给父组件 通过cRef.current.handleMenuClick 调用
useImperativeHandle(cRef, () => {
return {
handleSwitchVisible: () => switchVisible()
}
})
const [showDrawer, switchShowDrawer] = useState(false)
const switchVisible = () => {
switchShowDrawer(!showDrawer)
}
return <div>
<div className='fixed top-0 right-0 z-40 '>
{/* 侧边菜单 */}
<div
className={(showDrawer ? 'shadow-2xl ' : ' -mr-72 ') + ' w-72 duration-200 h-full bg-white fixed right-0 top-0 overflow-y-auto'}>
<div className='z-20'>
{post && <Toc toc={post.toc}/>}
</div>
</div>
</div>
{/* 背景蒙版 */}
<div id='right-drawer-background' className={(showDrawer ? 'block' : 'hidden') + ' fixed top-0 left-0 z-30 w-full h-full bg-black bg-opacity-50'}
onClick={switchVisible} />
</div>
}
export default TocDrawer

View File

@@ -0,0 +1,28 @@
import React from 'react'
/**
* 点击召唤目录抽屉
* 当屏幕下滑500像素后会出现该控件
* @param targetRef 关联高度的目标html标签
* @param showPercent 是否显示百分比
* @returns {JSX.Element}
* @constructor
*/
const TocDrawerButton = (props) => {
return (
<div id='jump-to-top' className='right-0 fixed flex bottom-40 mr-2.5 py-1 duration-500 z-20 opacity-70' onClick={props.onClick}>
<div className='transform hover:scale-105 duration-200 '>
<div style={{ boxShadow: 'rgba(41, 50, 60, 0.5) 0px 2px 16px', borderRadius: '28px' }}
className={'animate__fadeInUp bg-gray-700 px-2.5 py-2 cursor-pointer animate__animated animate__faster shadow-2xl'}>
<div className='text-center text-gray-100'>
<div className='w-10 text-xl ' title='目录' ><i className='fa fa-book'/> </div>
<div className='text-sm'>目录</div>
</div>
</div>
</div>
</div>
)
}
export default TocDrawerButton

View File

@@ -1,45 +1,35 @@
import { useRef } from 'react'
import DarkModeButton from '@/components/DarkModeButton'
import SearchInput from '@/components/SearchInput'
import Drawer from '@/components/Drawer'
import DrawerRight from '@/components/DrawerRight'
import Logo from '@/components/Logo'
import SideBarDrawer from '@/components/SideBarDrawer'
const TopNav = ({ tags, currentTag, post, posts, currentSearch, categories, currentCategory }) => {
const drawer = useRef()
const drawerRight = useRef()
return (<>
{/* 侧面抽屉 */}
<Drawer post={post} currentTag={currentTag} cRef={drawer} tags={tags} posts={posts} categories={categories} currentCategory={currentCategory}/>
<DrawerRight post={post} cRef={drawerRight}/>
<SideBarDrawer post={post} currentTag={currentTag} cRef={drawer} tags={tags} posts={posts} categories={categories} currentCategory={currentCategory}/>
{/* 导航栏 */}
<div id='sticky-nav' className='fixed w-full top-0 z-20 transform duration-500 bg-white dark:bg-gray-800 border-b dark:border-gray-700'>
<div id='sticky-nav' className='fixed w-full top-0 z-20 transform duration-500 bg-white dark:bg-gray-900 border-b dark:border-gray-700'>
<div className='text-sm m-auto w-full flex flex-row justify-between items-center px-4 py-2 shadow-md'>
{/* 左侧LOGO */}
<div className='flex ml-12'>
<div onClick={() => { drawer.current.handleMenuClick() }}
<div onClick={() => { drawer.current.handleSwitchSideDrawerVisible() }}
className='fixed top-3 left-0 z-30 py-1 px-5 text-gray-600 text-2xl cursor-pointer dark:text-gray-300'>
<i className='fa hover:scale-125 transform duration-200 fa-bars '
/>
</div>
<Logo/>
</div>
{/* 中间搜索框 */}
<div className='hidden sm:block w-96'>
<div className='w-96'>
<SearchInput currentTag={currentTag} currentSearch={currentSearch}/>
</div>
{/* 右侧功能 */}
<div className='flex flex-nowrap space-x-1'>
<DarkModeButton />
{post && (
<div className='block xl:hidden z-10 p-1 duration-200 mr-2 h-12 text-xl cursor-pointer dark:text-gray-300 '>
<i className='fa p-2.5 hover:scale-125 transform duration-200 fa-bookmark-o' onClick={() => { drawerRight.current.handleMenuClick() }}/>
</div>
)}
</div>
</div>
</div>