二级菜单,部分

This commit is contained in:
tangly1024
2023-03-19 19:06:33 +08:00
parent 720f2f7dba
commit a64e3d3dce
23 changed files with 390 additions and 322 deletions

View File

@@ -1,4 +1,4 @@
import React from 'react'
import React, { useEffect, useImperativeHandle } from 'react'
/**
* 折叠面板组件,支持水平折叠、垂直折叠
@@ -6,12 +6,27 @@ import React from 'react'
* @returns
*/
const Collapse = props => {
const collapseRef = React.useRef(null)
const { collapseRef } = props
const ref = React.useRef(null)
const type = props.type || 'vertical'
useImperativeHandle(collapseRef, () => {
return {
/**
* 当子元素高度变化时,可调用此方法更新折叠组件的高度
* @param {*} param0
*/
updateCollapseHeight: ({ height, increase }) => {
ref.current.style.height = ref.current.scrollHeight
ref.current.style.height = 'auto'
}
}
})
/**
* 折叠
* @param {*} element
*/
* 折叠
* @param {*} element
*/
const collapseSection = element => {
const sectionHeight = element.scrollHeight
const sectionWidth = element.scrollWidth
@@ -34,9 +49,9 @@ const Collapse = props => {
}
/**
* 展开
* @param {*} element
*/
* 展开
* @param {*} element
*/
const expandSection = element => {
const sectionHeight = element.scrollHeight
const sectionWidth = element.scrollWidth
@@ -58,22 +73,20 @@ const Collapse = props => {
clearTimeout(clearTime)
}
const updateHeight = () => {
collapseRef.current.style.height = 'auto'
}
React.useEffect(() => {
useEffect(() => {
if (props.isOpen) {
expandSection(collapseRef.current)
expandSection(ref.current)
} else {
collapseSection(collapseRef.current)
collapseSection(ref.current)
}
// 通知父组件高度变化
props?.onHeightChange && props.onHeightChange({ height: ref.current.scrollHeight, increase: props.isOpen })
}, [props.isOpen])
return (
<div ref={collapseRef} onClick={updateHeight} style={type === 'vertical' ? { height: '0px' } : { width: '0px' }} className={'overflow-hidden duration-200 ' + props.className }>
{props.children}
</div>
<div ref={ref} style={type === 'vertical' ? { height: '0px' } : { width: '0px' }} className={'overflow-hidden duration-200 ' + props.className}>
{props.children}
</div>
)
}
Collapse.defaultProps = { isOpen: false }

View File

@@ -1,10 +1,21 @@
/* eslint-disable */
import React from 'react'
const id = 'canvasFlutteringRibbon'
export const FlutteringRibbon = () => {
const destroyRibbon = ()=>{
const ribbon = document.getElementById(id)
if(ribbon && ribbon.parentNode){
ribbon.parentNode.removeChild(ribbon)
}
}
React.useEffect(() => {
createFlutteringRibbon()
return () => destroyRibbon()
}, [])
return <></>
}
/**
@@ -125,6 +136,7 @@ function createFlutteringRibbon() {
init: function () {
try {
;(this._canvas = document.createElement('canvas')),
(this._canvas.id = id),
(this._canvas.style.display = 'block'),
(this._canvas.style.position = 'fixed'),
(this._canvas.style.margin = '0'),

View File

@@ -1,10 +1,19 @@
/* eslint-disable */
import React from 'react'
import { useEffect } from 'react'
const id = 'canvasNestCreated'
export const Nest = () => {
React.useEffect(() => {
const destroyNest = ()=>{
const nest = document.getElementById(id)
if(nest && nest.parentNode){
nest.parentNode.removeChild(nest)
}
}
useEffect(() => {
createNest()
return () => destroyNest()
}, [])
return <></>
}
/**
@@ -65,7 +74,7 @@ function createNest() {
m(o)
}
var i = document.createElement('canvas')
i.id = 'canvasNestCreated'
i.id = id
var a = (function () {
const t = e
return {

View File

@@ -1,10 +1,20 @@
/* eslint-disable */
import React from 'react'
import { useEffect } from 'react'
const id = 'canvasRibbon'
export const Ribbon = () => {
React.useEffect(() => {
const destroyRibbon = ()=>{
const ribbon = document.getElementById(id)
if(ribbon && ribbon.parentNode){
ribbon.parentNode.removeChild(ribbon)
}
}
useEffect(() => {
createRibbon()
return () => destroyRibbon()
}, [])
return <></>
}
/**
@@ -29,6 +39,7 @@ function createRibbon() {
a = window.innerWidth,
l = window.innerHeight,
d = e.s
i.id= id
let r, s
const u = Math
let h = 0

View File

@@ -1,10 +1,19 @@
/* eslint-disable */
import React from 'react'
import { useEffect } from 'react'
const id = 'canvas_sakura'
export const Sakura = () => {
React.useEffect(() => {
const destroySakura = ()=>{
const sakura = document.getElementById(id)
if(sakura && sakura.parentNode){
sakura.parentNode.removeChild(sakura)
}
}
useEffect(() => {
createSakura({})
return () => destroyRibbon()
}, [])
return <></>
}
/**
@@ -129,7 +138,7 @@ function createSakura() {
'style',
'position: fixed;left: 0;top: 0;pointer-events: none;'
)
canvas.setAttribute('id', 'canvas_sakura')
canvas.setAttribute('id', id)
document.getElementsByTagName('body')[0].appendChild(canvas)
cxt = canvas.getContext('2d')
var sakuraList = new SakuraList()
@@ -165,15 +174,12 @@ function createSakura() {
stop = requestAnimationFrame(asd)
}
}
window.onresize = function () {
var canvasSnow = document.getElementById('canvas_snow')
}
img.onload = function () {
startSakura()
}
function stopp() {
if (staticx) {
var child = document.getElementById('canvas_sakura')
var child = document.getElementById(id)
child.parentNode.removeChild(child)
window.cancelAnimationFrame(stop)
staticx = false

View File

@@ -95,8 +95,13 @@ function getCustomNav({ allPages }) {
return customNav
}
function getCustomMenu({ collectionData }) {
const menuPages = collectionData.filter(post => (post.type === BLOG.NOTION_PROPERTY_NAME.type_menu || post.type === BLOG.NOTION_PROPERTY_NAME.type_sub_menu) && post.status === 'Published')
/**
* 获取自定义菜单
* @param {*} allPages
* @returns
*/
function getCustomMenu({ allPages }) {
const menuPages = allPages.filter(post => (post.type === BLOG.NOTION_PROPERTY_NAME.type_menu || post.type === BLOG.NOTION_PROPERTY_NAME.type_sub_menu) && post.status === BLOG.NOTION_PROPERTY_NAME.status_publish)
const menus = []
if (menuPages && menuPages.length > 0) {
menuPages.forEach(e => {
@@ -216,14 +221,12 @@ async function getPageRecordMapByNotionAPI({ pageId, from }) {
// 文章计数
let postCount = 0
const allPages = collectionData.filter(post => {
if (post.type === 'Post' && post.status === 'Published') {
if (post.type === BLOG.NOTION_PROPERTY_NAME.type_post && post.status === BLOG.NOTION_PROPERTY_NAME.status_publish) {
postCount++
}
return post &&
post.type &&
(post.type === 'Post' || post.type === 'Page') &&
(post.status === 'Published' || post.status === 'Invisible') &&
(!post.slug.startsWith('http'))
(!post?.slug?.startsWith('http')) &&
(post?.status === BLOG.NOTION_PROPERTY_NAME.status_publish || post?.status === BLOG.NOTION_PROPERTY_NAME.status_invisible)
})
// Sort by date
@@ -241,7 +244,7 @@ async function getPageRecordMapByNotionAPI({ pageId, from }) {
const siteInfo = getBlogInfo({ collection, block })
const customNav = getCustomNav({ allPages: collectionData.filter(post => post.type === 'Page' && post.status === 'Published') })
// 新的菜单
const customMenu = getCustomMenu({ collectionData })
const customMenu = await getCustomMenu({ allPages })
const latestPosts = getLatestPosts({ allPages, from, latestPostCount: 5 })
return {

View File

@@ -0,0 +1,38 @@
import Link from 'next/link'
import { useState } from 'react'
export const DropMenu = ({ link }) => {
const [show, changeShow] = useState(false)
const hasSubMenu = link?.subMenus?.length > 0
return <li className='cursor-pointer' onMouseOver={() => changeShow(true)} onMouseOut={() => changeShow(false)} >
{!hasSubMenu &&
<div className="rounded px-2 md:pl-0 md:mr-3 my-4 md:pr-3 text-gray-700 dark:text-gray-200 no-underline md:border-r border-gray-light">
<Link href={link?.to} >
{link?.name}
{hasSubMenu && <i className='px-2 fa fa-angle-down'></i>}
</Link>
</div>
}
{hasSubMenu &&
<div className='rounded px-2 md:pl-0 md:mr-3 my-4 md:pr-3 text-gray-700 dark:text-gray-200 no-underline md:border-r border-gray-light'>
{link?.name}
<i className='px-2 fa fa-angle-down'></i>
</div>
}
{/* 子菜单 */}
{hasSubMenu && <ul className={`${show ? 'visible opacity-100' : 'invisible opacity-0'} border-gray-100 bg-white dark:bg-black dark:border-gray-800 transition-all duration-300 z-20 top-12 absolute block drop-shadow-lg `}>
{link.subMenus.map(sLink => {
return <li key={sLink.id} className='not:last-child:border-b-0 border-b text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-900 tracking-widest transition-all duration-200 dark:border-gray-800 py-3 pr-6 pl-2'>
<Link href={sLink.to}>
<span className='text-xs font-extralight'>{sLink.title}</span>
</Link>
</li>
})}
</ul>}
</li>
}

View File

@@ -1,6 +1,7 @@
import BLOG from '@/blog.config'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import CONFIG_EXAMPLE from '../config_example'
import { DropMenu } from './DropMenu'
/**
* 菜单导航
@@ -8,8 +9,9 @@ import CONFIG_EXAMPLE from '../config_example'
* @returns
*/
export const Nav = (props) => {
const { customNav } = props
const { customNav, customMenu } = props
const { locale } = useGlobal()
let links = [
{ icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search', show: CONFIG_EXAMPLE.MENU_SEARCH },
{ icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', show: CONFIG_EXAMPLE.MENU_ARCHIVE },
@@ -21,23 +23,22 @@ export const Nav = (props) => {
links = links.concat(customNav)
}
// 如果 开启自定义菜单,则不再使用 Page生成菜单。
if (BLOG.CUSTOM_MENU) {
links = customMenu
}
if (!links || links.length === 0) {
return null
}
return (
<nav className="w-full bg-white md:pt-0 px-6 relative z-20 border-t border-b border-gray-light dark:border-hexo-black-gray dark:bg-black">
<div className="container mx-auto max-w-4xl md:flex justify-between items-center text-sm md:text-md md:justify-start">
<div className="w-full text-center md:text-left flex flex-wrap justify-center items-stretch md:justify-start md:items-start">
{links.map(link => {
if (link.show) {
return link && <Link
href={link.to}
key={link.to}
className="px-2 md:pl-0 md:mr-3 my-4 md:pr-3 text-gray-700 dark:text-gray-200 no-underline md:border-r border-gray-light">
{link.name}
</Link>
} else {
return null
}
})}
</div>
<ul className="w-full text-center md:text-left flex flex-wrap justify-center items-stretch md:justify-start md:items-start">
{/* {links.map(link => <NormalMenuItem key={link.id} link={link}/>)} */}
{links.map(link => <DropMenu key={link.id} link={link} />)}
</ul>
<div className="w-full md:w-1/3 text-center md:text-right">
{/* <!-- extra links --> */}
</div>

View File

@@ -0,0 +1,14 @@
import Link from 'next/link'
/**
* 旧的普通菜单
* @param {*} props
* @returns
*/
export const NormalMenuItem = (props) => {
const { link } = props
return link?.show && <Link href={link.to} key={link.to}
className="px-2 md:pl-0 md:mr-3 my-4 md:pr-3 text-gray-700 dark:text-gray-200 no-underline md:border-r border-gray-light">
{link.name}
</Link>
}

View File

@@ -1,43 +0,0 @@
import React, { useEffect, useRef } from 'react'
const Collapse = props => {
const { id, className } = props
const collapseRef = useRef(null)
const collapseSection = element => {
const sectionHeight = element.scrollHeight
const currentHeight = element.style.height
if (currentHeight === '0px') {
return
}
requestAnimationFrame(function () {
element.style.height = sectionHeight + 'px'
requestAnimationFrame(function () {
element.style.height = 0 + 'px'
})
})
}
const expandSection = element => {
const sectionHeight = element.scrollHeight
element.style.height = sectionHeight + 'px'
const clearTime = setTimeout(() => {
element.style.height = 'auto'
}, 400)
clearTimeout(clearTime)
}
useEffect(() => {
const element = collapseRef.current
if (props.isOpen) {
expandSection(element)
} else {
collapseSection(element)
}
}, [props.isOpen])
return (
<div id={id} ref={collapseRef} style={{ height: '0px' }} className={'overflow-hidden duration-200 ' + className}>
{props.children}
</div>
)
}
Collapse.defaultProps = { isOpen: false }
export default Collapse

View File

@@ -2,7 +2,6 @@ import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import { useCallback, useEffect, useRef, useState } from 'react'
import CategoryGroup from './CategoryGroup'
import Collapse from './Collapse'
import Logo from './Logo'
import SearchDrawer from './SearchDrawer'
import TagGroups from './TagGroups'
@@ -10,6 +9,7 @@ import MenuButtonGroupTop from './MenuButtonGroupTop'
import MenuList from './MenuList'
import { useRouter } from 'next/router'
import throttle from 'lodash.throttle'
import Collapse from '@/components/Collapse'
let windowTop = 0

View File

@@ -1,75 +0,0 @@
import React from 'react'
/**
* 折叠面板组件,支持水平折叠、垂直折叠
* @param {type:['horizontal','vertical'],isOpen} props
* @returns
*/
const Collapse = props => {
const collapseRef = React.useRef(null)
const type = props.type || 'vertical'
const collapseSection = element => {
const sectionHeight = element.scrollHeight
const sectionWidth = element.scrollWidth
requestAnimationFrame(function () {
switch (type) {
case 'horizontal':
element.style.width = sectionWidth + 'px'
requestAnimationFrame(function () {
element.style.width = 0 + 'px'
})
break
case 'vertical':
element.style.height = sectionHeight + 'px'
requestAnimationFrame(function () {
element.style.height = 0 + 'px'
})
}
})
}
/**
* 展开
* @param {*} element
*/
const expandSection = element => {
const sectionHeight = element.scrollHeight
const sectionWidth = element.scrollWidth
let clearTime = 0
switch (type) {
case 'horizontal':
element.style.width = sectionWidth + 'px'
clearTime = setTimeout(() => {
element.style.width = 'auto'
}, 400)
break
case 'vertical':
element.style.height = sectionHeight + 'px'
clearTime = setTimeout(() => {
element.style.height = 'auto'
}, 400)
}
clearTimeout(clearTime)
}
React.useEffect(() => {
const element = collapseRef.current
if (props.isOpen) {
expandSection(element)
} else {
collapseSection(element)
}
}, [props.isOpen])
return (
<div ref={collapseRef} style={type === 'vertical' ? { height: '0px' } : { width: '0px' }}
className={'overflow-hidden duration-200 fixed z-50 ' + props.className }>
{props.children}
</div>
)
}
Collapse.defaultProps = { isOpen: false }
export default Collapse

View File

@@ -1,38 +0,0 @@
import React, { useEffect, useRef } from 'react'
const Collapse = props => {
const collapseRef = useRef(null)
const collapseSection = element => {
const sectionHeight = element.scrollHeight
requestAnimationFrame(function () {
element.style.height = sectionHeight + 'px'
requestAnimationFrame(function () {
element.style.height = 0 + 'px'
})
})
}
const expandSection = element => {
const sectionHeight = element.scrollHeight
element.style.height = sectionHeight + 'px'
const clearTime = setTimeout(() => {
element.style.height = 'auto'
}, 400)
clearTimeout(clearTime)
}
useEffect(() => {
const element = collapseRef.current
if (props.isOpen) {
expandSection(element)
} else {
collapseSection(element)
}
}, [props.isOpen])
return (
<div ref={collapseRef} style={{ height: '0px' }} className='overflow-hidden duration-200'>
{props.children}
</div>
)
}
Collapse.defaultProps = { isOpen: false }
export default Collapse

View File

@@ -0,0 +1,54 @@
import Collapse from '@/components/Collapse'
import Link from 'next/link'
import { useState } from 'react'
/**
* 折叠菜单
* @param {*} param0
* @returns
*/
export const CollapseMenu = (props) => {
const { link } = props
const [show, changeShow] = useState(false)
const hasSubMenu = link?.subMenus?.length > 0
const [isOpen, changeIsOpen] = useState(false)
const toggleShow = () => {
changeShow(!show)
}
const toggleOpenSubMenu = () => {
changeIsOpen(!isOpen)
}
return <>
<div className='px-5 py-2 w-full text-left duration-200 hover:bg-gray-700 hover:text-white not:last-child:border-b-0 border-b dark:bg-hexo-black-gray dark:border-black' onClick={toggleShow} >
{!hasSubMenu && <Link
href={link?.to}
className='w-full my-auto items-center justify-between flex '>
<div><div className={`${link.icon} text-center w-4 mr-4`} />{link.name}</div>
</Link>}
{hasSubMenu && <div
onClick={hasSubMenu ? toggleOpenSubMenu : null}
className="font-extralight flex justify-between cursor-pointer dark:text-gray-200 no-underline tracking-widest">
<div><div className={`${link.icon} text-center w-4 mr-4`} />{link.name}</div>
<div className='inline-flex items-center '><i className='px-2 fa fa-plus text-gray-400'></i></div>
</div>}
</div>
{/* 折叠子菜单 */}
{hasSubMenu && <Collapse isOpen={isOpen} onHeightChange={props.onHeightChange}>
{link.subMenus.map(sLink => {
return <div key={sLink.id} className='
not:last-child:border-b-0 border-b dark:border-gray-800 py-2 px-14 cursor-pointer hover:bg-gray-100
font-extralight dark:bg-black text-left justify-start text-gray-600 bg-gray-50 dark:hover:bg-gray-900 tracking-widest transition-all duration-200'>
<Link href={sLink.to}>
<div><div className={`${sLink.icon} text-center w-3 mr-3 text-xs`} />{sLink.title}</div>
</Link>
</div>
})}
</Collapse>}
</>
}

View File

@@ -0,0 +1,35 @@
import Link from 'next/link'
import { useState } from 'react'
export const DropMenu = ({ link }) => {
const [show, changeShow] = useState(false)
const hasSubMenu = link?.subMenus?.length > 0
return <li onMouseOver={() => changeShow(true)} onMouseOut={() => changeShow(false)}
className='relative py-1.5 px-5 duration-300 text-base justify-between hover:bg-gray-700 hover:text-white hover:shadow-lg cursor-pointer font-light flex flex-nowrap items-center '>
{!hasSubMenu &&
<Link href={link?.to} className='w-full my-auto items-center justify-between flex ' >
<div><div className={`${link.icon} text-center w-4 mr-4`} />{link.name}</div>
{link.slot}
</Link>}
{hasSubMenu &&
<div className='w-full my-auto items-center justify-between flex '>
<div><div className={`${link.icon} text-center w-4 mr-4`} />{link.name}</div>
{link.slot}
{hasSubMenu && <div className='text-right'><i className='px-2 fa fa-angle-right'></i></div>}
</div>}
{/* 子菜单 */}
{hasSubMenu && <ul className={`${show ? 'visible opacity-100' : 'invisible opacity-0'} left-56 absolute right-0 top-0 w-full border-gray-100 bg-white dark:bg-black dark:border-gray-800 transition-all duration-300 drop-shadow-lg `}>
{link.subMenus.map(sLink => {
return <li key={sLink.id} className='my-auto h-9 px-2 items-center justify-start flex not:last-child:border-b-0 border-b text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-900 tracking-widest transition-all duration-200 dark:border-gray-800 '>
<i className={`${sLink.icon} w-4 text-center`} />
<div className={'ml-4'}>{sLink.name}</div>
{sLink.slot}
</li>
})} </ul>}
</li>
}

View File

@@ -1,13 +1,13 @@
import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useGlobal } from '@/lib/global'
import CONFIG_NEXT from '../config_next'
import BLOG from '@/blog.config'
import { DropMenu } from './DropMenu'
import { CollapseMenu } from './CollapseMenu'
const MenuButtonGroup = (props) => {
const { postCount, customNav } = props
const { postCount, customNav, customMenu } = props
const { locale } = useGlobal()
const router = useRouter()
const archiveSlot = <div className='bg-gray-300 dark:bg-gray-500 rounded-md text-gray-50 px-1 text-xs'>{postCount}</div>
const defaultLinks = [
@@ -21,33 +21,23 @@ const MenuButtonGroup = (props) => {
links = defaultLinks.concat(customNav)
}
// 如果 开启自定义菜单则覆盖Page生成的菜单
if (BLOG.CUSTOM_MENU) {
links = customMenu
}
return (
<nav id='nav' className='leading-8 text-gray-500 dark:text-gray-400 font-sans'>
{links.map(link => {
if (link && link.show) {
const selected = (router.pathname === link.to) || (router.asPath === link.to)
return (
<Link
key={link.to}
title={link.to}
href={link.to}
target={link.to.indexOf('http') === 0 ? '_blank' : '_self'}
className={'py-1.5 px-5 duration-300 text-base justify-between hover:bg-gray-700 hover:text-white hover:shadow-lg cursor-pointer font-light flex flex-nowrap items-center ' +
(selected ? 'bg-gray-200 text-black' : ' ')}>
<>
{/* 大屏模式菜单 */}
<nav id='nav' className='hidden md:block leading-8 text-gray-500 dark:text-gray-400 font-sans'>
{links.map(link => link && link.show && <DropMenu key={link.id} link={link} />)}
</nav>
<div className='my-auto items-center justify-center flex '>
<i className={`${link.icon} w-4 text-center`} />
<div className={'ml-4'}>{link.name}</div>
</div>
{link.slot}
</Link>
)
} else {
return <></>
}
})}
</nav>
{/* 移动端菜单 */}
<div id='nav-menu-mobile' className='block md:hidden my-auto justify-start bg-white'>
{links?.map(link => link && link.show && <CollapseMenu onHeightChange={props.onHeightChange} key={link.id} link={link} />)}
</div>
</>
)
}
export default MenuButtonGroup

View File

@@ -23,7 +23,7 @@ const SideAreaLeft = props => {
const { post, slot, postCount } = props
const { locale } = useGlobal()
const showToc = post && post.toc && post.toc.length > 1
return <aside id='left' className={(BLOG.LAYOUT_SIDEBAR_REVERSE ? 'ml-4' : 'mr-4') + ' hidden lg:block flex-col w-60 z-10 relative'}>
return <aside id='left' className={(BLOG.LAYOUT_SIDEBAR_REVERSE ? 'ml-4' : 'mr-4') + ' hidden lg:block flex-col w-60 z-20 relative'}>
<section
data-aos="fade-down"

View File

@@ -3,7 +3,7 @@ import throttle from 'lodash.throttle'
import Link from 'next/link'
import { useCallback, useEffect, useRef, useState } from 'react'
import CategoryGroup from './CategoryGroup'
import Collapse from './Collapse'
import Collapse from '@/components/Collapse'
import Logo from './Logo'
import MenuButtonGroup from './MenuButtonGroup'
import SearchDrawer from './SearchDrawer'
@@ -21,6 +21,7 @@ const TopNav = (props) => {
const { tags, currentTag, categories, currentCategory } = props
const { locale } = useGlobal()
const searchDrawer = useRef()
const collapseRef = useRef(null)
const scrollTrigger = useCallback(throttle(() => {
const scrollS = window.scrollY
@@ -53,76 +54,74 @@ const TopNav = (props) => {
}
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'>
{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' />
{locale.COMMON.MORE} <i className='fas fa-angle-double-right' />
</Link>
</div>
<CategoryGroup currentCategory={currentCategory} categories={categories} />
</section>
) }
</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'>
{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'/>
{locale.COMMON.MORE} <i className='fas fa-angle-double-right' />
</Link>
</div>
<div className='p-2'>
<TagGroups tags={tags} currentTag={currentTag} />
</div>
</section>
) }
</Link>
</div>
<div className='p-2'>
<TagGroups tags={tags} currentTag={currentTag} />
</div>
</section>
)}
</>
return (<div id='top-nav' className='block lg:hidden'>
<SearchDrawer cRef={searchDrawer} slot={searchDrawerSlot}/>
<SearchDrawer cRef={searchDrawer} slot={searchDrawerSlot} />
{/* 导航栏 */}
<div id='sticky-nav' className={`${CONFIG_NEXT.NAV_TYPE !== 'normal' ? 'fixed' : 'relative'} lg:relative w-full top-0 z-20 transform duration-500`}>
<div className='w-full flex justify-between items-center p-4 bg-black dark:bg-gray-800 text-white'>
{/* 左侧LOGO 标题 */}
<div className='flex flex-none flex-grow-0'>
<div onClick={toggleMenuOpen} className='w-8 cursor-pointer'>
{ isOpen ? <i className='fas fa-times'/> : <i className='fas fa-bars'/> }
</div>
{/* 导航栏 */}
<div id='sticky-nav' className={`${CONFIG_NEXT.NAV_TYPE !== 'normal' ? 'fixed' : 'relative'} lg:relative w-full top-0 z-20 transform duration-500`}>
<div className='w-full flex justify-between items-center p-4 bg-black dark:bg-gray-800 text-white'>
{/* 左侧LOGO 标题 */}
<div className='flex flex-none flex-grow-0'>
<div onClick={toggleMenuOpen} className='w-8 cursor-pointer'>
{isOpen ? <i className='fas fa-times' /> : <i className='fas fa-bars' />}
</div>
</div>
<div className='flex'>
<Logo {...props} />
</div>
{/* 右侧功能 */}
<div className='mr-1 flex justify-end items-center text-sm space-x-4 font-serif dark:text-gray-200'>
<div className="cursor-pointer block lg:hidden" onClick={() => { searchDrawer?.current?.show() }}>
<i className="mr-2 fas fa-search" />{locale.NAV.SEARCH}
</div>
</div>
</div>
<Collapse collapseRef={collapseRef} type='vertical' isOpen={isOpen}>
<MenuButtonGroup onHeightChange={(param) => collapseRef.current?.updateCollapseHeight(param)} {...props} from='top' />
</Collapse>
</div>
<div className='flex'>
<Logo {...props}/>
</div>
{/* 右侧功能 */}
<div className='mr-1 flex justify-end items-center text-sm space-x-4 font-serif dark:text-gray-200'>
<div className="cursor-pointer block lg:hidden" onClick={() => { searchDrawer?.current?.show() }}>
<i className="mr-2 fas fa-search" />{locale.NAV.SEARCH}
</div>
</div>
</div>
<Collapse type='vertical' isOpen={isOpen}>
<div className='bg-white py-1 px-5'>
<MenuButtonGroup {...props} from='top'/>
</div>
</Collapse>
</div>
</div>)
</div>)
}
export default TopNav

View File

@@ -0,0 +1,38 @@
import Link from 'next/link'
import { useState } from 'react'
export const DropMenu = ({ link }) => {
const [show, changeShow] = useState(false)
const hasSubMenu = link?.subMenus?.length > 0
return <li className='cursor-pointer' onMouseOver={() => changeShow(true)} onMouseOut={() => changeShow(false)} >
{!hasSubMenu &&
<div className="block ml-4 text-black dark:text-gray-50 nav">
<Link href={link?.to} >
{link?.name}
{hasSubMenu && <i className='px-2 fa fa-angle-down'></i>}
</Link>
</div>
}
{hasSubMenu &&
<div className='block ml-4 text-black dark:text-gray-50 nav'>
{link?.name}
<i className='px-2 fa fa-angle-down'></i>
</div>
}
{/* 子菜单 */}
{hasSubMenu && <ul className={`${show ? 'visible opacity-100' : 'invisible opacity-0'} border-gray-100 bg-white dark:bg-black dark:border-gray-800 transition-all duration-300 z-20 top-12 absolute block drop-shadow-lg `}>
{link.subMenus.map(sLink => {
return <li key={sLink.id} className='not:last-child:border-b-0 border-b text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-900 tracking-widest transition-all duration-200 dark:border-gray-800 py-3 pr-6 pl-2'>
<Link href={sLink.to}>
<span className='text-xs font-extralight'>{sLink.title}</span>
</Link>
</li>
})}
</ul>}
</li>
}

View File

@@ -4,6 +4,7 @@ import BLOG from '@/blog.config'
import { useGlobal } from '@/lib/global'
import CONFIG_NOBELIUM from '../config_nobelium'
import { SvgIcon } from './SvgIcon'
import { DropMenu } from './DropMenu'
const Nav = props => {
const { navBarTitle, fullWidth, siteInfo } = props
@@ -54,12 +55,12 @@ const Nav = props => {
</Link>
{navBarTitle
? (
<p className="ml-2 font-medium text-day dark:text-night header-name">
<p className="ml-2 font-medium text-gray-800 dark:text-gray-300 header-name">
{navBarTitle}
</p>
)
: (
<p className="ml-2 font-medium text-day dark:text-night header-name">
<p className="ml-2 font-medium text-gray-800 dark:text-gray-300 header-name">
{siteInfo?.title}
{/* ,{' '}<span className="font-normal">{siteInfo?.description}</span> */}
</p>
@@ -71,7 +72,7 @@ const Nav = props => {
}
const NavBar = props => {
const { customNav } = props
const { customMenu, customNav } = props
const { locale } = useGlobal()
let links = [
@@ -84,21 +85,17 @@ const NavBar = props => {
if (customNav) {
links = links.concat(customNav)
}
// 如果 开启自定义菜单则覆盖Page生成的菜单
if (BLOG.CUSTOM_MENU) {
links = customMenu
}
return (
<div className="flex-shrink-0">
<ul className="flex flex-row">
{links.map(
link =>
link.show && (
<li
key={link.id}
className="block ml-4 text-black dark:text-gray-50 nav"
>
<Link href={link.to} target={link.target}>
{link.name}
</Link>
</li>
)
link => link && link.show && <DropMenu key={link.id} link={link}/>
)}
</ul>
</div>

View File

@@ -35,7 +35,7 @@ const LayoutBase = props => {
loadExternalResource('/css/theme-simple.css', 'css')
}
return (
<div id='theme-simple' className='dark:text-gray-300 bg-white dark:bg-black'>
<div id='theme-simple' className='min-h-screen flex flex-col dark:text-gray-300 bg-white dark:bg-black'>
<CommonHead meta={meta} />
{CONFIG_SIMPLE.TOP_BAR && <TopBar {...props} />}
@@ -47,7 +47,7 @@ const LayoutBase = props => {
<NavBar {...props} />
{/* 主体 */}
<div id='container-wrapper' className={(BLOG.LAYOUT_SIDEBAR_REVERSE ? 'flex-row-reverse' : '') + ' flex items-start max-w-9/10 mx-auto pt-12'}>
<div id='container-wrapper' className={(BLOG.LAYOUT_SIDEBAR_REVERSE ? 'flex-row-reverse' : '') + ' flex-1 flex items-start max-w-9/10 mx-auto pt-12'}>
<div id='container-inner ' className='w-full flex-grow'>
{onLoading ? LoadingCover : children}
</div>

View File

@@ -23,9 +23,9 @@ export const DropMenu = ({ link }) => {
</>}
{/* 子菜单 */}
{hasSubMenu && <ul className={`${show ? 'visible opacity-100' : 'invisible opacity-0'} border-gray-100 bg-white dark:bg-black dark:border-gray-800 transition-all duration-300 z-20 top-12 absolute block border drop-shadow-lg `}>
{hasSubMenu && <ul className={`${show ? 'visible opacity-100' : 'invisible opacity-0'} border-gray-100 bg-white dark:bg-black dark:border-gray-800 transition-all duration-300 z-20 top-12 absolute block drop-shadow-lg `}>
{link.subMenus.map(sLink => {
return <li key={sLink.id} className=' text-blue-500 hover:bg-gray-50 dark:hover:bg-gray-900 tracking-widest transition-all duration-200 border-b dark:border-gray-800 py-3 pr-6 pl-2'>
return <li key={sLink.id} className='not:last-child:border-b-0 border-b text-blue-500 hover:bg-gray-50 dark:hover:bg-gray-900 tracking-widest transition-all duration-200 dark:border-gray-800 py-3 pr-6 pl-2'>
<Link href={sLink.to}>
<span className='text-xs font-extralight'>{sLink.title}</span>
</Link>

View File

@@ -37,14 +37,17 @@ export const NavBarMenu = ({ customNav, customMenu }) => {
links = links.concat(customNav)
}
// 如果 开启自定义菜单则覆盖Page生成的菜单
if (BLOG.CUSTOM_MENU) {
links = customMenu
}
if (!links || links.length === 0) {
return null
}
return (<>
{/* 大屏模式菜单 */}
<div id='nav-menu-pc' className='hidden md:flex my-auto'>
{links?.map(link => {
if (link?.show) {
@@ -54,6 +57,7 @@ export const NavBarMenu = ({ customNav, customMenu }) => {
}
})}
</div>
{/* 移动端小屏菜单 */}
<div id='nav-menu-mobile' className='flex md:hidden my-auto justify-start'>
<div onClick={toggleIsOpen} className='cursor-pointer hover:text-red-400 transition-all duration-200'>
<i className='fa fa-bars mr-3' />