-
- {/* 左侧LOGO 标题 */}
-
-
- {isOpen ?
:
}
+ {/* 导航栏 */}
+
+
+ {/* 左侧LOGO 标题 */}
+
+
+
+
+
+
+ {/* 右侧功能 */}
+
+
{ searchDrawer?.current?.show() }}>
+ {locale.NAV.SEARCH}
+
-
-
-
-
- {/* 右侧功能 */}
-
-
{ searchDrawer?.current?.show() }}>
- {locale.NAV.SEARCH}
-
-
+
+ collapseRef.current?.updateCollapseHeight(param)} {...props} from='top' />
+
-
- collapseRef.current?.updateCollapseHeight(param)} {...props} from='top' />
-
-
-
-
)
+
)
}
export default TopNav
diff --git a/themes/next/index.js b/themes/next/index.js
index a1ca8401..8bb3be8b 100644
--- a/themes/next/index.js
+++ b/themes/next/index.js
@@ -1,14 +1,319 @@
import CONFIG_NEXT from './config_next'
-import LayoutIndex from './LayoutIndex'
-import LayoutSearch from './LayoutSearch'
-import LayoutArchive from './LayoutArchive'
-import LayoutSlug from './LayoutSlug'
-import Layout404 from './Layout404'
-import LayoutCategory from './LayoutCategory'
-import LayoutCategoryIndex from './LayoutCategoryIndex'
-import LayoutPage from './LayoutPage'
-import LayoutTag from './LayoutTag'
-import LayoutTagIndex from './LayoutTagIndex'
+
+import CommonHead from '@/components/CommonHead'
+import FloatDarkModeButton from './components/FloatDarkModeButton'
+import Footer from './components/Footer'
+import JumpToBottomButton from './components/JumpToBottomButton'
+import JumpToTopButton from './components/JumpToTopButton'
+import LoadingCover from './components/LoadingCover'
+import SideAreaLeft from './components/SideAreaLeft'
+import SideAreaRight from './components/SideAreaRight'
+import TopNav from './components/TopNav'
+import { useGlobal } from '@/lib/global'
+import { useEffect, useRef, useState } from 'react'
+import BLOG from '@/blog.config'
+import Header from './components/Header'
+import BlogPostListScroll from './components/BlogPostListScroll'
+import BlogPostListPage from './components/BlogPostListPage'
+import StickyBar from './components/StickyBar'
+import { isBrowser } from '@/lib/utils'
+import Mark from 'mark.js'
+import TocDrawerButton from './components/TocDrawerButton'
+import TocDrawer from './components/TocDrawer'
+import { ArticleLock } from './components/ArticleLock'
+import BlogPostArchive from './components/BlogPostArchive'
+import TagItem from './components/TagItem'
+import { useRouter } from 'next/router'
+import ArticleDetail from './components/ArticleDetail'
+import Link from 'next/link'
+import BlogListBar from './components/BlogListBar'
+
+/**
+ * 基础布局 采用左中右三栏布局,移动端使用顶部导航栏
+ * @returns {JSX.Element}
+ * @constructor
+ */
+const LayoutBase = (props) => {
+ const { children, headerSlot, meta, floatSlot, rightAreaSlot, siteInfo } = props
+ const { onLoading } = useGlobal()
+ const targetRef = useRef(null)
+ const floatButtonGroup = useRef(null)
+ const [showRightFloat, switchShow] = useState(false)
+ const [percent, changePercent] = useState(0) // 页面阅读百分比
+
+ const scrollListener = () => {
+ const targetRef = document.getElementById('wrapper')
+ const clientHeight = targetRef?.clientHeight
+ const scrollY = window.pageYOffset
+ const fullHeight = clientHeight - window.outerHeight
+ let per = parseFloat(((scrollY / fullHeight * 100)).toFixed(0))
+ if (per > 100) per = 100
+ const shouldShow = scrollY > 100 && per > 0
+
+ if (shouldShow !== showRightFloat) {
+ switchShow(shouldShow)
+ }
+ changePercent(per)
+ }
+
+ useEffect(() => {
+ // facebook messenger 插件需要调整右下角悬浮按钮的高度
+ const fb = document.getElementsByClassName('fb-customerchat')
+ if (fb.length === 0) {
+ floatButtonGroup?.current?.classList.replace('bottom-24', 'bottom-12')
+ } else {
+ floatButtonGroup?.current?.classList.replace('bottom-12', 'bottom-24')
+ }
+
+ document.addEventListener('scroll', scrollListener)
+ return () => document.removeEventListener('scroll', scrollListener)
+ }, [showRightFloat])
+
+ return (
+
+ {/* SEO相关 */}
+
+ {/* 移动端顶部导航栏 */}
+
+
+ <>{headerSlot}>
+
+ {/* 顶部黑线装饰 */}
+
+
+ {/* 主区 */}
+
+ {/* 左侧栏样式 */}
+
+
+ {/* 中央内容 */}
+
+ {onLoading ? : <> {children}>}
+
+
+ {/* 右侧栏样式 */}
+ {CONFIG_NEXT.RIGHT_BAR && }
+
+
+ {/* 右下角悬浮 */}
+
+
+
+
+
+ {floatSlot}
+
+
+
+ {/* 页脚 */}
+
+
+ )
+}
+
+/**
+ * 首页
+ * 首页就是一个博客列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutIndex = (props) => {
+ return
} {...props} />
+}
+
+/**
+ * 博客列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutPostList = (props) => {
+ return
+
+
+
+ {BLOG.POST_LIST_STYLE !== 'page'
+ ?
+ :
+ }
+
+}
+
+/**
+ * 搜索
+ * @param {*} props
+ * @returns
+ */
+const LayoutSearch = (props) => {
+ const { locale } = useGlobal()
+ const { posts, keyword } = props
+ setTimeout(() => {
+ const container = isBrowser() && document.getElementById('posts-wrapper')
+ if (container && container.innerHTML) {
+ const re = new RegExp(keyword, 'gim')
+ const instance = new Mark(container)
+ instance.markRegExp(re, {
+ element: 'span',
+ className: 'text-red-500 border-b border-dashed'
+ })
+ }
+ }, 200)
+ return (
+
+
+
+ {' '}
+ {posts?.length} {locale.COMMON.RESULT_OF_SEARCH}
+
+
+
+ {BLOG.POST_LIST_STYLE !== 'page'
+ ?
+ :
+ }
+
+
+ )
+}
+
+/**
+ * 404
+ * @param {*} props
+ * @returns
+ */
+const Layout404 = props => {
+ const router = useRouter()
+ useEffect(() => {
+ // 延时3秒如果加载失败就返回首页
+ setTimeout(() => {
+ const article = isBrowser() && document.getElementById('article-wrapper')
+ if (!article) {
+ router.push('/').then(() => {
+ // console.log('找不到页面', router.asPath)
+ })
+ }
+ }, 3000)
+ }, [])
+
+ return
+
+
+
404
+
+
页面无法加载,即将返回首页
+
+
+
+
+}
+
+/**
+ * 归档
+ * @param {*} props
+ * @returns
+ */
+const LayoutArchive = (props) => {
+ const { archivePosts } = props
+
+ return (
+
+
+ {Object.keys(archivePosts).map(archiveTitle => (
+
+ ))}
+
+
+ )
+}
+
+/**
+ * 文章详情
+ * @param {*} props
+ * @returns
+ */
+const LayoutSlug = (props) => {
+ const { post, lock, validPassword } = props
+ const drawerRight = useRef(null)
+ const targetRef = isBrowser() ? document.getElementById('article-wrapper') : null
+ const floatSlot =
+ {
+ drawerRight?.current?.handleSwitchVisible()
+ }} />
+
+
+ return (
+
+
+ {post && !lock && }
+
+ {post && lock && }
+
+ {/* 悬浮目录按钮 */}
+ {post &&
+
+
}
+
+
+ )
+}
+
+/**
+ * 分类列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutCategoryIndex = (props) => {
+ const { allPosts, categoryOptions } = props
+ const { locale } = useGlobal()
+ return (
+
+
+
+ {locale.COMMON.CATEGORY}:
+
+
+ {categoryOptions.map(category => {
+ return (
+
+
+ {category.name}({category.count})
+
+
+ )
+ })}
+
+
+
+ )
+}
+
+/**
+ * 标签列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutTagIndex = (props) => {
+ const { tagOptions } = props
+ const { locale } = useGlobal()
+ return
+
+
{locale.COMMON.TAGS}:
+
+
+
+}
export {
CONFIG_NEXT as THEME_CONFIG,
@@ -17,9 +322,7 @@ export {
LayoutArchive,
LayoutSlug,
Layout404,
- LayoutCategory,
LayoutCategoryIndex,
- LayoutPage,
- LayoutTag,
+ LayoutPostList,
LayoutTagIndex
}