diff --git a/themes/matery/Layout404.js b/themes/matery/Layout404.js
deleted file mode 100644
index dff7a952..00000000
--- a/themes/matery/Layout404.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import LayoutBase from './LayoutBase'
-import { useRouter } from 'next/router'
-import { useEffect } from 'react'
-
-export const Layout404 = props => {
- const router = useRouter()
- useEffect(() => {
- // 延时3秒如果加载失败就返回首页
- setTimeout(() => {
- const article = typeof document !== 'undefined' && document.getElementById('notion-article')
- if (!article) {
- router.push('/').then(() => {
- // console.log('找不到页面', router.asPath)
- })
- }
- }, 3000)
- })
- return (
-
-
-
- )
-}
-
-export default Layout404
diff --git a/themes/matery/LayoutArchive.js b/themes/matery/LayoutArchive.js
deleted file mode 100644
index 94b40239..00000000
--- a/themes/matery/LayoutArchive.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { useEffect } from 'react'
-import BlogPostArchive from './components/BlogPostArchive'
-import Card from './components/Card'
-import HeaderArticle from './components/HeaderArticle'
-import LayoutBase from './LayoutBase'
-
-export const LayoutArchive = (props) => {
- const { archivePosts } = props
-
- useEffect(() => {
- const anchor = window.location.hash
- if (anchor) {
- setTimeout(() => {
- const anchorElement = document.getElementById(anchor.substring(1))
- if (anchorElement) {
- anchorElement.scrollIntoView({ block: 'start', behavior: 'smooth' })
- }
- }, 300)
- }
- }, [])
- return } >
-
-
- {Object.keys(archivePosts).map(archiveTitle => (
-
- ))}
-
-
-
-}
-
-export default LayoutArchive
diff --git a/themes/matery/LayoutBase.js b/themes/matery/LayoutBase.js
deleted file mode 100644
index 66954859..00000000
--- a/themes/matery/LayoutBase.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import CommonHead from '@/components/CommonHead'
-import { useCallback, useEffect, useState } from 'react'
-
-import Footer from './components/Footer'
-import JumpToTopButton from './components/JumpToTopButton'
-import TopNav from './components/TopNav'
-import Live2D from '@/components/Live2D'
-import LoadingCover from './components/LoadingCover'
-import { useGlobal } from '@/lib/global'
-import BLOG from '@/blog.config'
-import FloatDarkModeButton from './components/FloatDarkModeButton'
-import throttle from 'lodash.throttle'
-import { isBrowser, loadExternalResource } from '@/lib/utils'
-import SocialButton from './components/SocialButton'
-import CONFIG_MATERY from './config_matery'
-
-/**
- * 基础布局 采用左右两侧布局,移动端使用顶部导航栏
- * @param props
- * @returns {JSX.Element}
- * @constructor
- */
-const LayoutBase = props => {
- const { children, headerSlot, meta, siteInfo } = props
- const [show, switchShow] = useState(false)
- const { onLoading } = useGlobal()
-
- const throttleMs = 200
- const scrollListener = useCallback(throttle(() => {
- const scrollY = window.pageYOffset
- const shouldShow = scrollY > 300
- if (shouldShow !== show) {
- switchShow(shouldShow)
- }
- }, throttleMs))
-
- useEffect(() => {
- document.addEventListener('scroll', scrollListener)
- return () => document.removeEventListener('scroll', scrollListener)
- }, [])
-
- if (isBrowser()) {
- loadExternalResource('/css/theme-matery.css', 'css')
- }
-
- return (
-
-
-
-
-
-
- {headerSlot}
-
-
- {/* 嵌入区域 */}
-
- {props.containerSlot}
-
-
-
- {onLoading ? : children}
-
-
-
-
- {/* 左下角悬浮 */}
-
-
-
-
- {/* 右下角悬浮 */}
-
-
-
-
- {/* 可扩展的右下角悬浮 */}
- {props.floatRightBottom}
-
-
-
-
- )
-}
-
-export default LayoutBase
diff --git a/themes/matery/LayoutCategory.js b/themes/matery/LayoutCategory.js
deleted file mode 100644
index d21f8b0b..00000000
--- a/themes/matery/LayoutCategory.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import BlogPostListScroll from './components/BlogPostListScroll'
-import BlogPostListPage from './components/BlogPostListPage'
-import LayoutBase from './LayoutBase'
-import BLOG from '@/blog.config'
-import Link from 'next/link'
-import HeaderArticle from './components/HeaderArticle'
-
-export const LayoutCategory = props => {
- const { category, categoryOptions } = props
- return (
- } >
-
-
-
-
-
-
- {categoryOptions?.map(e => {
- const selected = e.name === category
- return (
-
-
-
- {e.name}({e.count})
-
-
- )
- })}
-
-
-
- {BLOG.POST_LIST_STYLE === 'page' ?
:
}
-
-
-
-
- )
-}
-
-export default LayoutCategory
diff --git a/themes/matery/LayoutCategoryIndex.js b/themes/matery/LayoutCategoryIndex.js
deleted file mode 100644
index f6fd0023..00000000
--- a/themes/matery/LayoutCategoryIndex.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import Link from 'next/link'
-import HeaderArticle from './components/HeaderArticle'
-import LayoutBase from './LayoutBase'
-
-export const LayoutCategoryIndex = props => {
- const { categoryOptions } = props
-
- return (
- } >
-
-
-
-
-
-
- {categoryOptions.map(e => {
- return (
-
-
-
- {e.name}({e.count})
-
-
- )
- })}
-
-
-
-
-
- )
-}
-
-export default LayoutCategoryIndex
diff --git a/themes/matery/LayoutIndex.js b/themes/matery/LayoutIndex.js
deleted file mode 100644
index 6c92d2c4..00000000
--- a/themes/matery/LayoutIndex.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import BLOG from '@/blog.config'
-import BlogPostListPage from './components/BlogPostListPage'
-import BlogPostListScroll from './components/BlogPostListScroll'
-import Header from './components/Header'
-import CONFIG_MATERY from './config_matery'
-import LayoutBase from './LayoutBase'
-import React from 'react'
-import Announcement from './components/Announcement'
-
-export const LayoutIndex = (props) => {
- return } headerSlot={CONFIG_MATERY.HOME_BANNER_ENABLE && }>
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
-}
-
-export default LayoutIndex
diff --git a/themes/matery/LayoutSearch.js b/themes/matery/LayoutSearch.js
deleted file mode 100644
index 0de3ed54..00000000
--- a/themes/matery/LayoutSearch.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import { useRouter } from 'next/router'
-import { useEffect, useRef } from 'react'
-import BLOG from '@/blog.config'
-import BlogPostListScroll from './components/BlogPostListScroll'
-import BlogPostListPage from './components/BlogPostListPage'
-import LayoutBase from './LayoutBase'
-import SearchInput from './components/SearchInput'
-import { useGlobal } from '@/lib/global'
-import Mark from 'mark.js'
-import TagItemMini from './components/TagItemMini'
-import Card from './components/Card'
-import Link from 'next/link'
-
-export const LayoutSearch = props => {
- const { keyword, tagOptions, categoryOptions } = props
- const { locale } = useGlobal()
- const router = useRouter()
- const currentSearch = keyword || router?.query?.s
- const cRef = useRef(null)
-
- useEffect(() => {
- setTimeout(() => {
- // 自动聚焦到搜索框
- cRef?.current?.focus()
- if (currentSearch) {
- const targets = document.getElementsByClassName('replace')
- for (const container of targets) {
- if (container && container.innerHTML) {
- const re = new RegExp(currentSearch, 'gim')
- const instance = new Mark(container)
- instance.markRegExp(re, {
- element: 'span',
- className: 'text-red-500 border-b border-dashed'
- })
- }
- }
- }
- }, 100)
- })
- return (
-
- {!currentSearch && <>
-
-
- {/* 分类 */}
-
-
-
- {locale.COMMON.CATEGORY}:
-
-
- {categoryOptions?.map(category => {
- return (
-
-
-
- {category.name}({category.count})
-
-
- )
- })}
-
-
- {/* 标签 */}
-
-
-
- {locale.COMMON.TAGS}:
-
-
-
-
- >}
-
- {currentSearch && <>
-
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
- >}
-
-
- )
-}
-
-export default LayoutSearch
diff --git a/themes/matery/LayoutSlug.js b/themes/matery/LayoutSlug.js
deleted file mode 100644
index e5a4fc53..00000000
--- a/themes/matery/LayoutSlug.js
+++ /dev/null
@@ -1,122 +0,0 @@
-import React, { useCallback, useEffect } from 'react'
-import { ArticleLock } from './components/ArticleLock'
-import HeaderArticle from './components/HeaderArticle'
-import LayoutBase from './LayoutBase'
-import Comment from '@/components/Comment'
-import NotionPage from '@/components/NotionPage'
-import ArticleAdjacent from './components/ArticleAdjacent'
-import ArticleCopyright from './components/ArticleCopyright'
-import { ArticleInfo } from './components/ArticleInfo'
-import Catalog from './components/Catalog'
-import JumpToCommentButton from './components/JumpToCommentButton'
-import throttle from 'lodash.throttle'
-import ShareBar from '@/components/ShareBar'
-import Announcement from './components/Announcement'
-
-export const LayoutSlug = props => {
- const { post, lock, validPassword } = props
-
- const [show, switchShow] = React.useState(false)
- const throttleMs = 200
-
- const scrollListener = useCallback(throttle(() => {
- const scrollY = window.pageYOffset
- const shouldShow = scrollY > 220 && post?.toc?.length > 0
- if (shouldShow !== show) {
- switchShow(shouldShow)
- }
- }, throttleMs))
-
- useEffect(() => {
- document.addEventListener('scroll', scrollListener)
- return () => document.removeEventListener('scroll', scrollListener)
- }, [])
-
- if (!post) {
- return }
- {...props}
- showCategory={false}
- showTag={false}
- >
- }
-
- return (}
- {...props}
- showCategory={false}
- showTag={false}
- floatRightBottom={}
- >
-
-
- {/* 文章主体卡片 */}
-
- {lock &&
}
-
- {!lock &&
- {post?.type && post?.type === 'Post' && <>
-
-
- >}
-
-
-
- {/* Notion文章主体 */}
-
-
- {/* 分享 */}
-
- {/* 文章版权说明 */}
- {post.type === 'Post' && }
-
-
-
-
-
- {/* 评论互动 */}
-
-
-
-
-
-
}
-
-
- {/* 底部文章推荐 */}
- {post.type === 'Post' &&
}
-
-
-
- {/* 右侧文章目录 */}
- {post?.toc?.length > 0 &&
}
-
-
-
-
- )
-}
-
-export default LayoutSlug
diff --git a/themes/matery/LayoutTag.js b/themes/matery/LayoutTag.js
deleted file mode 100644
index 0de70bbd..00000000
--- a/themes/matery/LayoutTag.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import BLOG from '@/blog.config'
-import BlogPostListScroll from './components/BlogPostListScroll'
-import BlogPostListPage from './components/BlogPostListPage'
-import LayoutBase from './LayoutBase'
-import React from 'react'
-import HeaderArticle from './components/HeaderArticle'
-import { useGlobal } from '@/lib/global'
-import TagItemMiddle from './components/TagItemMiddle'
-
-export const LayoutTag = (props) => {
- const { tagOptions, tag } = props
-
- const { locale } = useGlobal()
-
- return } >
-
-
-
-
-
-
- {locale.COMMON.TAGS}
-
-
-
-
-
- {BLOG.POST_LIST_STYLE === 'page' ?
:
}
-
-
-
-
-}
-
-export default LayoutTag
diff --git a/themes/matery/LayoutTagIndex.js b/themes/matery/LayoutTagIndex.js
deleted file mode 100644
index f25ba122..00000000
--- a/themes/matery/LayoutTagIndex.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import { useGlobal } from '@/lib/global'
-import HeaderArticle from './components/HeaderArticle'
-import TagItemMiddle from './components/TagItemMiddle'
-import LayoutBase from './LayoutBase'
-
-export const LayoutTagIndex = props => {
- const { tagOptions } = props
- const { locale } = useGlobal()
- return (
- } >
-
-
-
-
-
- {locale.COMMON.TAGS}
-
-
-
-
-
-
- )
-}
-
-export default LayoutTagIndex
diff --git a/themes/matery/components/BlogListBar.js b/themes/matery/components/BlogListBar.js
new file mode 100644
index 00000000..4d4b2387
--- /dev/null
+++ b/themes/matery/components/BlogListBar.js
@@ -0,0 +1,50 @@
+import Link from 'next/link'
+import { useGlobal } from '@/lib/global'
+import TagItemMiddle from './components/TagItemMiddle'
+
+export default function BlogListBar(props) {
+ const { category, categoryOptions, tag, tagOptions } = props
+ const { locale } = useGlobal()
+
+ if (category) {
+ return (
+
+
+
+ {categoryOptions?.map(e => {
+ const selected = e.name === category
+ return (
+
+
+
+ {e.name}({e.count})
+
+
+ )
+ })}
+
+
+
+ )
+ } else if (tag) {
+ return
+
+
+ {locale.COMMON.TAGS}
+
+
+
+
+ } else {
+ return <>>
+ }
+}
diff --git a/themes/matery/components/Catalog.js b/themes/matery/components/Catalog.js
index 56bff03e..448b6b08 100644
--- a/themes/matery/components/Catalog.js
+++ b/themes/matery/components/Catalog.js
@@ -1,4 +1,4 @@
-import React, { useRef } from 'react'
+import { useEffect, useRef } from 'react'
import throttle from 'lodash.throttle'
import { uuidToId } from 'notion-utils'
import Progress from './Progress'
@@ -13,7 +13,7 @@ import { useGlobal } from '@/lib/global'
const Catalog = ({ toc }) => {
const { locale } = useGlobal()
// 监听滚动事件
- React.useEffect(() => {
+ useEffect(() => {
window.addEventListener('scroll', actionSectionScrollSpy)
actionSectionScrollSpy()
return () => {
diff --git a/themes/matery/components/CatalogWrapper.js b/themes/matery/components/CatalogWrapper.js
new file mode 100644
index 00000000..7d64e2ad
--- /dev/null
+++ b/themes/matery/components/CatalogWrapper.js
@@ -0,0 +1,27 @@
+import Catalog from './Catalog'
+
+/**
+ * 目录
+ * @param {*} param0
+ * @returns
+ */
+export default function CatalogWrapper({ post }) {
+ if (post?.toc?.length > 0) {
+ return
+ } else {
+ return <>>
+ }
+}
diff --git a/themes/matery/components/Header.js b/themes/matery/components/Hero.js
similarity index 98%
rename from themes/matery/components/Header.js
rename to themes/matery/components/Hero.js
index 42a75663..c573703d 100644
--- a/themes/matery/components/Header.js
+++ b/themes/matery/components/Hero.js
@@ -11,7 +11,7 @@ let wrapperTop = 0
*
* @returns 头图
*/
-const Header = props => {
+const Hero = props => {
const [typed, changeType] = useState()
const { siteInfo } = props
const { locale } = useGlobal()
@@ -71,4 +71,4 @@ const Header = props => {
)
}
-export default Header
+export default Hero
diff --git a/themes/matery/components/RightFloatButtons.js b/themes/matery/components/RightFloatButtons.js
new file mode 100644
index 00000000..dc4a1bd8
--- /dev/null
+++ b/themes/matery/components/RightFloatButtons.js
@@ -0,0 +1,19 @@
+import JumpToTopButton from './components/JumpToTopButton'
+import FloatDarkModeButton from './components/FloatDarkModeButton'
+import SocialButton from './components/SocialButton'
+
+/**
+ * 右下角悬浮按钮
+ * @param {*} param0
+ * @returns
+ */
+export default function RightFloatButtons({ props }) {
+ const { floatRightBottom } = props
+ return
+
+
+
+ {/* 可扩展的右下角悬浮 */}
+ {floatRightBottom}
+
+}
diff --git a/themes/matery/components/SearchNav.js b/themes/matery/components/SearchNav.js
new file mode 100644
index 00000000..0c992ebf
--- /dev/null
+++ b/themes/matery/components/SearchNav.js
@@ -0,0 +1,63 @@
+
+import SearchInput from './components/SearchInput'
+import TagItemMini from './components/TagItemMini'
+import Card from './components/Card'
+import Link from 'next/link'
+import { useEffect, useRef } from 'react'
+import { useGlobal } from '@/lib/global'
+
+/**
+ * 搜索页面的导航条
+ * @param {*} props
+ * @returns
+ */
+export default function SearchNave(props) {
+ const cRef = useRef(null)
+ const { locale } = useGlobal()
+ const { tagOptions, categoryOptions } = props
+
+ useEffect(() => {
+ setTimeout(() => {
+ // 自动聚焦到搜索框
+ cRef?.current?.focus()
+ }, 100)
+ })
+ return <>
+
+
+ {/* 分类 */}
+
+
+
+ {locale.COMMON.CATEGORY}:
+
+
+ {categoryOptions?.map(category => {
+ return (
+
+
+ {category.name}({category.count})
+
+
+ )
+ })}
+
+
+ {/* 标签 */}
+
+
+ {locale.COMMON.TAGS}:
+
+
+
+
+ >
+}
diff --git a/themes/matery/index.js b/themes/matery/index.js
index c767fcd3..1537b68c 100644
--- a/themes/matery/index.js
+++ b/themes/matery/index.js
@@ -1,25 +1,353 @@
import CONFIG_MATERY from './config_matery'
-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 TopNav from './components/TopNav'
+import Live2D from '@/components/Live2D'
+import LoadingCover from './components/LoadingCover'
+import { useGlobal } from '@/lib/global'
+import BLOG from '@/blog.config'
+import { isBrowser, loadExternalResource } from '@/lib/utils'
+import Footer from './components/Footer'
+import { useEffect } from 'react'
+import RightFloatButtons from './components/RightFloatButtons'
+import { useRouter } from 'next/router'
+import Mark from 'mark.js'
+import SearchNave from './components/SearchNav'
+import BlogPostListPage from './components/BlogPostListPage'
+import BlogPostListScroll from './components/BlogPostListScroll'
+import Hero from './components/Hero'
+import Announcement from './components/Announcement'
+import CatalogWrapper from './components/CatalogWrapper'
+import TagItemMiddle from './components/TagItemMiddle'
+import HeaderArticle from './components/HeaderArticle'
+import Link from 'next/link'
+import ArticleAdjacent from './components/ArticleAdjacent'
+import Comment from '@/components/Comment'
+import ArticleCopyright from './components/ArticleCopyright'
+import ShareBar from '@/components/ShareBar'
+import NotionPage from '@/components/NotionPage'
+import { ArticleInfo } from './components/ArticleInfo'
+import { ArticleLock } from './components/ArticleLock'
+import BlogPostArchive from './components/BlogPostArchive'
+import Card from './components/Card'
+import JumpToCommentButton from './components/JumpToCommentButton'
+import BlogListBar from './components/BlogListBar'
+
+/**
+ * 基础布局
+ * 采用左右两侧布局,移动端使用顶部导航栏
+ * @param props
+ * @returns {JSX.Element}
+ * @constructor
+ */
+const LayoutBase = props => {
+ const { children, headerSlot, meta, siteInfo, containerSlot, post } = props
+ const { onLoading } = useGlobal()
+
+ if (isBrowser()) {
+ loadExternalResource('/css/theme-matery.css', 'css')
+ }
+
+ return (
+
+ {/* SEO相关 */}
+
+
+ {/* 顶部导航栏 */}
+
+
+ {/* 顶部嵌入 */}
+ {headerSlot}
+
+
+ {/* 嵌入区域 */}
+
+ {containerSlot}
+
+
+
+ {onLoading ? : children}
+
+
+
+
+ {/* 左下角悬浮 */}
+
+
+
+
+ {/* 右下角悬浮 */}
+
+
+ {/* 页脚 */}
+
+
+ )
+}
+
+/**
+ * 首页
+ * 首页就是一个文章列表,但是嵌入了Hero大图和公告
+ * @param {*} props
+ * @returns
+ */
+const LayoutIndex = (props) => {
+ return } headerSlot={CONFIG_MATERY.HOME_BANNER_ENABLE && } />
+}
+
+/**
+ * 博客列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutPostList = (props) => {
+ return (
+
+
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
+
+ )
+}
+
+/**
+ * 搜搜
+ * @param {*} props
+ * @returns
+ */
+const LayoutSearch = props => {
+ const { keyword } = props
+ const router = useRouter()
+ const currentSearch = keyword || router?.query?.s
+
+ useEffect(() => {
+ setTimeout(() => {
+ if (currentSearch) {
+ const targets = document.getElementsByClassName('replace')
+ for (const container of targets) {
+ if (container && container.innerHTML) {
+ const re = new RegExp(currentSearch, 'gim')
+ const instance = new Mark(container)
+ instance.markRegExp(re, {
+ element: 'span',
+ className: 'text-red-500 border-b border-dashed'
+ })
+ }
+ }
+ }
+ }, 100)
+ })
+ return (
+
+ {!currentSearch
+ ?
+ :
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
+
}
+
+ )
+}
+
+/**
+ * 归档
+ * @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
+
+ return (} showCategory={false} showTag={false} floatRightBottom={}>
+
+
+
+ {/* 文章主体卡片 */}
+
+
+ {lock &&
}
+
+ {!lock &&
+
+ {/* 文章信息 */}
+ {post?.type && post?.type === 'Post' && <>
+
+
+ >}
+
+
+
+
+
+ {/* Notion文章主体 */}
+
+
+ {/* 分享 */}
+
+
+ {/* 版权说明 */}
+ {post.type === 'Post' && }
+
+
+
+
+
+ {/* 评论互动 */}
+
+
+
+
+
+
}
+
+
+ {/* 底部文章推荐 */}
+ {post.type === 'Post' &&
}
+
+ {/* 底部公告 */}
+
+
+ {/* 右侧文章目录 */}
+
+
+
+
+
+ )
+}
+
+/**
+ * 404
+ * @param {*} props
+ * @returns
+ */
+const Layout404 = props => {
+ const router = useRouter()
+ useEffect(() => {
+ // 延时3秒如果加载失败就返回首页
+ setTimeout(() => {
+ const article = typeof document !== 'undefined' && document.getElementById('notion-article')
+ if (!article) {
+ router.push('/').then(() => {
+ // console.log('找不到页面', router.asPath)
+ })
+ }
+ }, 3000)
+ })
+ return (
+
+
+
+ )
+}
+
+/**
+ * 分类列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutCategoryIndex = props => {
+ const { categoryOptions } = props
+
+ return (
+ } >
+
+
+
+
+ {categoryOptions.map(e => {
+ return (
+
+
+ {e.name}({e.count})
+
+
+ )
+ })}
+
+
+
+
+ )
+}
+
+/**
+ * 标签列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutTagIndex = props => {
+ const { tagOptions } = props
+ const { locale } = useGlobal()
+ return (
+ } >
+
+
+
+
+
+ {locale.COMMON.TAGS}
+
+
+
+
+
+
+ )
+}
export {
CONFIG_MATERY as THEME_CONFIG,
LayoutIndex,
+ LayoutPostList,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404,
- LayoutCategory,
LayoutCategoryIndex,
- LayoutPage,
- LayoutTag,
LayoutTagIndex
}
diff --git a/themes/medium/Layout404.js b/themes/medium/Layout404.js
deleted file mode 100644
index 68b656cc..00000000
--- a/themes/medium/Layout404.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import LayoutBase from './LayoutBase'
-
-export const Layout404 = props => {
- return
- 404 Not found.
-
-}
-
-export default Layout404
diff --git a/themes/medium/LayoutArchive.js b/themes/medium/LayoutArchive.js
deleted file mode 100644
index 083dd8ac..00000000
--- a/themes/medium/LayoutArchive.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import BLOG from '@/blog.config'
-import Link from 'next/link'
-import LayoutBase from './LayoutBase'
-
-export const LayoutArchive = props => {
- const { archivePosts } = props
-
- return (
-
-
- {Object.keys(archivePosts)?.map(archiveTitle => (
-
- ))}
-
-
- )
-}
-
-export default LayoutArchive
diff --git a/themes/medium/LayoutBase.js b/themes/medium/LayoutBase.js
deleted file mode 100644
index be8cfa41..00000000
--- a/themes/medium/LayoutBase.js
+++ /dev/null
@@ -1,89 +0,0 @@
-import CommonHead from '@/components/CommonHead'
-import { useState, createContext, useContext } from 'react'
-import Footer from './components/Footer'
-import InfoCard from './components/InfoCard'
-import RevolverMaps from './components/RevolverMaps'
-import CONFIG_MEDIUM from './config_medium'
-import Tabs from '@/components/Tabs'
-import TopNavBar from './components/TopNavBar'
-import SearchInput from './components/SearchInput'
-import BottomMenuBar from './components/BottomMenuBar'
-import { useGlobal } from '@/lib/global'
-import { useRouter } from 'next/router'
-import Live2D from '@/components/Live2D'
-import BLOG from '@/blog.config'
-import Announcement from './components/Announcement'
-import JumpToTopButton from './components/JumpToTopButton'
-const ThemeGlobalMedium = createContext()
-
-/**
- * 基础布局 采用左右两侧布局,移动端使用顶部导航栏
-
- * @returns {JSX.Element}
- * @constructor
- */
-const LayoutBase = props => {
- const { children, meta, showInfoCard = true, slotRight, slotTop, siteInfo, notice } = props
- const { locale } = useGlobal()
- const router = useRouter()
- const [tocVisible, changeTocVisible] = useState(false)
- const { onLoading } = useGlobal()
-
- const LoadingCover =
-
- return (
-
-
-
-
-
-
- {/* 桌面端左侧菜单 */}
- {/* */}
-
-
- {/* 顶部导航栏 */}
-
-
-
- {slotTop}
-
- {onLoading ? LoadingCover : children}
-
-
-
-
- {/* 底部 */}
-
-
-
- {/* 桌面端右侧 */}
-
-
-
- {slotRight}
-
- {router.pathname !== '/search' && }
- {showInfoCard && }
- {CONFIG_MEDIUM.WIDGET_REVOLVER_MAPS === 'true' && }
-
-
-
-
-
-
-
-
- {/* 移动端底部导航栏 */}
-
-
-
- )
-}
-
-export default LayoutBase
-export const useMediumGlobal = () => useContext(ThemeGlobalMedium)
diff --git a/themes/medium/LayoutCategory.js b/themes/medium/LayoutCategory.js
deleted file mode 100644
index a947b70e..00000000
--- a/themes/medium/LayoutCategory.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import LayoutBase from './LayoutBase'
-import BlogPostListScroll from './components/BlogPostListScroll'
-import BlogPostListPage from './components/BlogPostListPage'
-import BLOG from '@/blog.config'
-
-export const LayoutCategory = props => {
- const { category } = props
- const slotTop =
-
- return
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
-}
-
-export default LayoutCategory
diff --git a/themes/medium/LayoutCategoryIndex.js b/themes/medium/LayoutCategoryIndex.js
deleted file mode 100644
index 2c8121ad..00000000
--- a/themes/medium/LayoutCategoryIndex.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import { useGlobal } from '@/lib/global'
-import Link from 'next/link'
-import LayoutBase from './LayoutBase'
-
-export const LayoutCategoryIndex = (props) => {
- const { categoryOptions } = props
- const { locale } = useGlobal()
- return (
-
-
-
- {locale.COMMON.CATEGORY}:
-
-
- {categoryOptions?.map(category => {
- return (
-
-
- {category.name}({category.count})
-
-
- )
- })}
-
-
-
- )
-}
-export default LayoutCategoryIndex
diff --git a/themes/medium/LayoutIndex.js b/themes/medium/LayoutIndex.js
deleted file mode 100644
index 41410467..00000000
--- a/themes/medium/LayoutIndex.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import BLOG from '@/blog.config'
-import BlogPostListPage from './components/BlogPostListPage'
-import BlogPostListScroll from './components/BlogPostListScroll'
-import LayoutBase from './LayoutBase'
-
-export const LayoutIndex = (props) => {
- return
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
-}
-
-export default LayoutIndex
diff --git a/themes/medium/LayoutPage.js b/themes/medium/LayoutPage.js
deleted file mode 100644
index 563df90b..00000000
--- a/themes/medium/LayoutPage.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import LayoutBase from './LayoutBase'
-import BlogPostListPage from './components/BlogPostListPage'
-
-export const LayoutPage = (props) => {
- return
-
-
-}
-
-export default LayoutPage
diff --git a/themes/medium/LayoutSearch.js b/themes/medium/LayoutSearch.js
deleted file mode 100644
index e7fee4c2..00000000
--- a/themes/medium/LayoutSearch.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import LayoutBase from './LayoutBase'
-import SearchInput from './components/SearchInput'
-import { useGlobal } from '@/lib/global'
-import TagGroups from './components/TagGroups'
-import CategoryGroup from './components/CategoryGroup'
-import { useEffect } from 'react'
-import { isBrowser } from '@/lib/utils'
-import BLOG from '@/blog.config'
-import Mark from 'mark.js'
-import BlogPostListScroll from './components/BlogPostListScroll'
-import BlogPostListPage from './components/BlogPostListPage'
-import { useRouter } from 'next/router'
-
-export const LayoutSearch = (props) => {
- const { locale } = useGlobal()
- const { keyword } = props
- const router = useRouter()
- const currentSearch = keyword || router?.query?.s
-
- useEffect(() => {
- setTimeout(() => {
- const container = isBrowser() && document.getElementById('posts-wrapper')
- if (container && container.innerHTML) {
- const re = new RegExp(currentSearch, 'gim')
- const instance = new Mark(container)
- instance.markRegExp(re, {
- element: 'span',
- className: 'text-red-500 border-b border-dashed'
- })
- }
- },
- 100)
- })
- return
-
-
-
{locale.NAV.SEARCH}
-
-
- {!currentSearch && <>
-
-
- >}
-
-
-
- {currentSearch &&
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
}
-
-}
-
-export default LayoutSearch
diff --git a/themes/medium/LayoutSlug.js b/themes/medium/LayoutSlug.js
deleted file mode 100644
index e0ddfbde..00000000
--- a/themes/medium/LayoutSlug.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import LayoutBase from './LayoutBase'
-import { useGlobal } from '@/lib/global'
-import React from 'react'
-import Catalog from './components/Catalog'
-import { ArticleLock } from './components/ArticleLock'
-import formatDate from '@/lib/formatDate'
-import BLOG from '@/blog.config'
-import Link from 'next/link'
-import NotionPage from '@/components/NotionPage'
-import CONFIG_MEDIUM from './config_medium'
-import Comment from '@/components/Comment'
-import ArticleAround from './components/ArticleAround'
-import TocDrawer from './components/TocDrawer'
-import CategoryItem from './components/CategoryItem'
-import TagItemMini from './components/TagItemMini'
-import ShareBar from '@/components/ShareBar'
-
-export const LayoutSlug = props => {
- const { post, prev, next, siteInfo, lock, validPassword } = props
- const { locale } = useGlobal()
-
- const date = formatDate(
- post?.publishTime || post?.createdTime,
- locale.LOCALE
- )
- if (!post) {
- return
- }
-
- const slotRight = post?.toc && post?.toc?.length >= 3 && (
-
-
- {/* */}
-
- )
-
- return (
-
- {/* 文章锁 */}
- {lock && }
-
- {!lock &&
-
- {/* title */}
-
{post?.title}
-
- {/* meta */}
-
-
-
{date}
-
|
-
{post.lastEditedTime}
-
-
-
-
-
-
- {/* eslint-disable-next-line @next/next/no-img-element */}
-

-
-
- {BLOG.AUTHOR}
-
-
-
-
-
- {/* Notion文章主体 */}
-
-
-
-
- {/* 分享 */}
-
- {/* 文章分类和标签信息 */}
-
- {CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post.category &&
}
-
- {CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => )}
-
-
-
- {post.type === 'Post' && }
-
-
-
-
-
}
-
- )
-}
-
-export default LayoutSlug
diff --git a/themes/medium/LayoutTag.js b/themes/medium/LayoutTag.js
deleted file mode 100644
index bedb51ef..00000000
--- a/themes/medium/LayoutTag.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import LayoutBase from './LayoutBase'
-import BLOG from '@/blog.config'
-import BlogPostListScroll from './components/BlogPostListScroll'
-import BlogPostListPage from './components/BlogPostListPage'
-
-export const LayoutTag = (props) => {
- const { tag } = props
- const slotTop =
-
- return
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
-}
-
-export default LayoutTag
diff --git a/themes/medium/LayoutTagIndex.js b/themes/medium/LayoutTagIndex.js
deleted file mode 100644
index cc9f8c94..00000000
--- a/themes/medium/LayoutTagIndex.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { useGlobal } from '@/lib/global'
-import TagItemMini from './components/TagItemMini'
-import LayoutBase from './LayoutBase'
-
-export const LayoutTagIndex = props => {
- const { tagOptions } = props
- const { locale } = useGlobal()
- return (
-
-
-
-
- {locale.COMMON.TAGS}:
-
-
-
-
- )
-}
-
-export default LayoutTagIndex
diff --git a/themes/medium/components/ArticleInfo.js b/themes/medium/components/ArticleInfo.js
new file mode 100644
index 00000000..17fd3ce2
--- /dev/null
+++ b/themes/medium/components/ArticleInfo.js
@@ -0,0 +1,41 @@
+import BLOG from '@/blog.config'
+import formatDate from '@/lib/formatDate'
+import Link from 'next/link'
+
+/**
+ * 文章详情页介绍
+ * @param {*} props
+ * @returns
+ */
+export default function ArticleInfo(props) {
+ const { post, siteInfo } = props
+
+ const date = formatDate(post?.publishTime || post?.createdTime)
+
+ return (<>
+ {/* title */}
+ {post?.title}
+
+ {/* meta */}
+
+
+
{date}
+
|
+
{post.lastEditedTime}
+
+
+
+
+
+
+ {/* eslint-disable-next-line @next/next/no-img-element */}
+

+
+
+ {BLOG.AUTHOR}
+
+
+
+
+ >)
+}
diff --git a/themes/medium/components/BlogArchiveItem.js b/themes/medium/components/BlogArchiveItem.js
new file mode 100644
index 00000000..52b2fefb
--- /dev/null
+++ b/themes/medium/components/BlogArchiveItem.js
@@ -0,0 +1,36 @@
+import BLOG from '@/blog.config'
+import Link from 'next/link'
+
+/**
+ * 归档分组
+ * @param {*} param0
+ * @returns
+ */
+export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
+ return (
+
+ )
+}
diff --git a/themes/medium/components/BlogPostBar.js b/themes/medium/components/BlogPostBar.js
new file mode 100644
index 00000000..7cada8fa
--- /dev/null
+++ b/themes/medium/components/BlogPostBar.js
@@ -0,0 +1,19 @@
+import { useGlobal } from '@/lib/global'
+
+/**
+ * 文章列表上方嵌入
+ * @param {*} props
+ * @returns
+ */
+export default function BlogPostBar(props) {
+ const { tag, category } = props
+ const { locale } = useGlobal()
+
+ if (tag) {
+ return {locale.COMMON.TAGS}:
{tag}
+ } else if (category) {
+ {locale.COMMON.CATEGORY}:
{category}
+ } else {
+ return <>>
+ }
+}
diff --git a/themes/medium/components/LoadingCover.js b/themes/medium/components/LoadingCover.js
new file mode 100644
index 00000000..4d8fa828
--- /dev/null
+++ b/themes/medium/components/LoadingCover.js
@@ -0,0 +1,7 @@
+export default function LoadingCover() {
+ return
+}
diff --git a/themes/medium/index.js b/themes/medium/index.js
index cd3239ec..c488ca32 100644
--- a/themes/medium/index.js
+++ b/themes/medium/index.js
@@ -1,14 +1,314 @@
import CONFIG_MEDIUM from './config_medium'
-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 { useState, createContext, useContext, useEffect } from 'react'
+import Footer from './components/Footer'
+import InfoCard from './components/InfoCard'
+import RevolverMaps from './components/RevolverMaps'
+import Tabs from '@/components/Tabs'
+import TopNavBar from './components/TopNavBar'
+import SearchInput from './components/SearchInput'
+import BottomMenuBar from './components/BottomMenuBar'
+import { useGlobal } from '@/lib/global'
+import { useRouter } from 'next/router'
+import Live2D from '@/components/Live2D'
+import BLOG from '@/blog.config'
+import Announcement from './components/Announcement'
+import JumpToTopButton from './components/JumpToTopButton'
+import LoadingCover from './components/LoadingCover'
+import BlogPostListPage from './components/BlogPostListPage'
+import BlogPostListScroll from './components/BlogPostListScroll'
+import Catalog from './components/Catalog'
+import { ArticleLock } from './components/ArticleLock'
+import TagGroups from './components/TagGroups'
+import CategoryGroup from './components/CategoryGroup'
+import { isBrowser } from '@/lib/utils'
+import Mark from 'mark.js'
+import BlogArchiveItem from './components/BlogArchiveItem'
+import BlogPostBar from './components/BlogPostBar'
+import NotionPage from '@/components/NotionPage'
+import Comment from '@/components/Comment'
+import ArticleAround from './components/ArticleAround'
+import TocDrawer from './components/TocDrawer'
+import CategoryItem from './components/CategoryItem'
+import TagItemMini from './components/TagItemMini'
+import ShareBar from '@/components/ShareBar'
+import Link from 'next/link'
+
+// 主题全局状态
+const ThemeGlobalMedium = createContext()
+export const useMediumGlobal = () => useContext(ThemeGlobalMedium)
+
+/**
+ * 基础布局
+ * 采用左右两侧布局,移动端使用顶部导航栏
+ * @returns {JSX.Element}
+ * @constructor
+ */
+const LayoutBase = props => {
+ const { children, meta, showInfoCard = true, slotRight, slotTop, siteInfo, notice } = props
+ const { locale } = useGlobal()
+ const router = useRouter()
+ const [tocVisible, changeTocVisible] = useState(false)
+ const { onLoading } = useGlobal()
+
+ return (
+
+
+
+
+
+
+ {/* 桌面端左侧菜单 */}
+ {/* */}
+
+ {/* 主区 */}
+
+
+ {/* 顶部导航栏 */}
+
+
+
+ {slotTop}
+
+ {onLoading ? : children}
+
+
+
+
+ {/* 底部 */}
+
+
+
+ {/* 桌面端右侧 */}
+
+
+
+ {slotRight}
+
+ {router.pathname !== '/search' && }
+ {showInfoCard && }
+ {CONFIG_MEDIUM.WIDGET_REVOLVER_MAPS === 'true' && }
+
+
+
+
+
+
+
+
+ {/* 移动端底部导航栏 */}
+
+
+
+ )
+}
+
+/**
+ * 首页
+ * 首页就是一个博客列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutIndex = (props) => {
+ return
+}
+
+/**
+ * 博客列表
+ * @returns
+ */
+const LayoutPostList = (props) => {
+ const slotTop =
+ return
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
+
+}
+
+/**
+ * 文章详情
+ * @param {*} props
+ * @returns
+ */
+const LayoutSlug = props => {
+ const { post, prev, next, lock, validPassword } = props
+ const { locale } = useGlobal()
+ const slotRight = post?.toc && post?.toc?.length >= 3 && (
+
+
+
+ )
+
+ return (
+
+ {/* 文章锁 */}
+ {lock && }
+
+ {!lock &&
+
+ {/* Notion文章主体 */}
+
+
+ {/* 文章底部区域 */}
+
+ {/* 分享 */}
+
+ {/* 文章分类和标签信息 */}
+
+ {CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post?.category &&
}
+
+ {CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => )}
+
+
+ {/* 上一篇下一篇文章 */}
+ {post.type === 'Post' && }
+ {/* 评论区 */}
+
+
+
+ {/* 移动端目录 */}
+
+
}
+
+ )
+}
+
+/**
+ * 搜索
+ * @param {*} props
+ * @returns
+ */
+const LayoutSearch = (props) => {
+ const { locale } = useGlobal()
+ const { keyword } = props
+ const router = useRouter()
+ const currentSearch = keyword || router?.query?.s
+
+ useEffect(() => {
+ setTimeout(() => {
+ const container = isBrowser() && document.getElementById('posts-wrapper')
+ if (container && container.innerHTML) {
+ const re = new RegExp(currentSearch, 'gim')
+ const instance = new Mark(container)
+ instance.markRegExp(re, {
+ element: 'span',
+ className: 'text-red-500 border-b border-dashed'
+ })
+ }
+ }, 100)
+ })
+ return
+
+ {/* 搜索导航栏 */}
+
+
{locale.NAV.SEARCH}
+
+ {!currentSearch && <>
+
+
+ >}
+
+
+ {/* 文章列表 */}
+ {currentSearch &&
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
+
}
+
+}
+
+/**
+ * 归档
+ * @param {*} props
+ * @returns
+ */
+const LayoutArchive = props => {
+ const { archivePosts } = props
+ return (
+
+
+ {Object.keys(archivePosts)?.map(archiveTitle =>
+ )}
+
+
+ )
+}
+
+/**
+ * 404
+ * @param {*} props
+ * @returns
+ */
+const Layout404 = props => {
+ return
+ 404 Not found.
+
+}
+
+/**
+ * 分类列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutCategoryIndex = (props) => {
+ const { 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_MEDIUM as THEME_CONFIG,
@@ -17,9 +317,6 @@ export {
LayoutArchive,
LayoutSlug,
Layout404,
- LayoutCategory,
LayoutCategoryIndex,
- LayoutPage,
- LayoutTag,
LayoutTagIndex
}