-
-
+
-
- {/* 侧边抽屉 */}
-
+
+
+
-
-
-
{headerSlot}
-
{onLoading ? : children}
-
-
+
+ {/* 侧边抽屉 */}
+
+
+
+
+
{headerSlot}
+
{onLoading ? : children}
+
+
+
+
-
-
)
+
+ )
}
/**
* 首页
* @param {*} props notion数据
- * @returns 首页就是一个博客列表
- */
+ * @returns 首页就是一个博客列表
+ */
const LayoutIndex = (props) => {
return
}
@@ -76,7 +102,7 @@ const LayoutIndex = (props) => {
/**
* 博客列表
* @param {*} props
- */
+ */
const LayoutPostList = (props) => {
return
{BLOG.POST_LIST_STYLE === 'page' ? : }
@@ -86,8 +112,8 @@ const LayoutPostList = (props) => {
/**
* 文章详情
* @param {*} props
- * @returns
- */
+ * @returns
+ */
const LayoutSlug = (props) => {
const { lock, validPassword } = props
return (
@@ -140,8 +166,8 @@ const LayoutArchive = (props) => {
/**
* 404
* @param {*} props
- * @returns
- */
+ * @returns
+ */
const Layout404 = props => {
return 404
}
@@ -149,8 +175,8 @@ const Layout404 = props => {
/**
* 分类列表
* @param {*} props
- * @returns
- */
+ * @returns
+ */
const LayoutCategoryIndex = (props) => {
const { locale } = useGlobal()
const { categoryOptions } = props
@@ -184,8 +210,8 @@ const LayoutCategoryIndex = (props) => {
/**
* 标签列表
* @param {*} props
- * @returns
- */
+ * @returns
+ */
const LayoutTagIndex = (props) => {
const { locale } = useGlobal()
const { tagOptions } = props
@@ -206,7 +232,7 @@ const LayoutTagIndex = (props) => {
}
export {
- CONFIG_FUKA as THEME_CONFIG,
+ FUKA_CONFIG as THEME_CONFIG,
LayoutIndex,
LayoutSearch,
LayoutArchive,
diff --git a/themes/nobelium/Layout404.js b/themes/nobelium/Layout404.js
deleted file mode 100644
index c0992ad3..00000000
--- a/themes/nobelium/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/nobelium/LayoutArchive.js b/themes/nobelium/LayoutArchive.js
deleted file mode 100644
index e36a3210..00000000
--- a/themes/nobelium/LayoutArchive.js
+++ /dev/null
@@ -1,47 +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 => (
-
-
- {archiveTitle}
-
-
-
-
- ))}
-
-
- )
-}
-
-export default LayoutArchive
diff --git a/themes/nobelium/LayoutBase.js b/themes/nobelium/LayoutBase.js
deleted file mode 100644
index 8a48ad76..00000000
--- a/themes/nobelium/LayoutBase.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import CommonHead from '@/components/CommonHead'
-import React from 'react'
-import Nav from './components/Nav'
-import { Footer } from './components/Footer'
-import JumpToTopButton from './components/JumpToTopButton'
-import Live2D from '@/components/Live2D'
-import { useGlobal } from '@/lib/global'
-/**
- * 基础布局 采用左右两侧布局,移动端使用顶部导航栏
-
- * @returns {JSX.Element}
- * @constructor
- */
-const LayoutBase = props => {
- const { children, meta, post } = props
-
- const fullWidth = post?.fullWidth ?? false
- const { onLoading } = useGlobal()
-
- const LoadingCover =
- return (
-
-
-
- {/* 顶部导航栏 */}
-
-
-
-
- {onLoading ? LoadingCover : children}
-
-
-
-
-
-
-
-
-
- {/* 左下角悬浮 */}
-
-
-
-
- )
-}
-
-export default LayoutBase
diff --git a/themes/nobelium/LayoutCategory.js b/themes/nobelium/LayoutCategory.js
deleted file mode 100644
index 517a5e82..00000000
--- a/themes/nobelium/LayoutCategory.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import BLOG from '@/blog.config'
-import { BlogListPage } from './components/BlogListPage'
-import { BlogListScroll } from './components/BlogListScroll'
-import LayoutBase from './LayoutBase'
-
-export const LayoutCategory = props => {
- return
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
-}
-
-export default LayoutCategory
diff --git a/themes/nobelium/LayoutCategoryIndex.js b/themes/nobelium/LayoutCategoryIndex.js
deleted file mode 100644
index 6a4f255d..00000000
--- a/themes/nobelium/LayoutCategoryIndex.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import Link from 'next/link'
-import LayoutBase from './LayoutBase'
-
-export const LayoutCategoryIndex = (props) => {
- const { categoryOptions } = props
-
- return (
-
-
- {categoryOptions?.map(category => {
- return (
-
-
- {category.name}({category.count})
-
-
- )
- })}
-
-
- )
-}
-
-export default LayoutCategoryIndex
diff --git a/themes/nobelium/LayoutIndex.js b/themes/nobelium/LayoutIndex.js
deleted file mode 100644
index d1e74923..00000000
--- a/themes/nobelium/LayoutIndex.js
+++ /dev/null
@@ -1,17 +0,0 @@
-
-import BLOG from '@/blog.config'
-import Announcement from './components/Announcement'
-import { BlogListPage } from './components/BlogListPage'
-import { BlogListScroll } from './components/BlogListScroll'
-import LayoutBase from './LayoutBase'
-
-export const LayoutIndex = props => {
- return (
-
-
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
- )
-}
-
-export default LayoutIndex
diff --git a/themes/nobelium/LayoutPage.js b/themes/nobelium/LayoutPage.js
deleted file mode 100644
index 184251a8..00000000
--- a/themes/nobelium/LayoutPage.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { BlogListPage } from './components/BlogListPage'
-import LayoutBase from './LayoutBase'
-
-export const LayoutPage = props => {
- return (
-
-
-
- )
-}
-
-export default LayoutPage
diff --git a/themes/nobelium/LayoutSearch.js b/themes/nobelium/LayoutSearch.js
deleted file mode 100644
index 84988d6a..00000000
--- a/themes/nobelium/LayoutSearch.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import BLOG from '@/blog.config'
-import { BlogListPage } from './components/BlogListPage'
-import { BlogListScroll } from './components/BlogListScroll'
-import { useRouter } from 'next/router'
-import { useEffect } from 'react'
-import SearchInput from './components/SearchInput'
-import Mark from 'mark.js'
-import LayoutBase from './LayoutBase'
-import { isBrowser } from '@/lib/utils'
-import Tags from './components/Tags'
-
-export const LayoutSearch = props => {
- const { keyword } = props
- const router = useRouter()
-
- useEffect(() => {
- 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'
- })
- }
- }, 100)
- }, [router.events])
-
- useEffect(() => {
- setTimeout(() => {
- if (keyword) {
- const targets = document.getElementsByClassName('replace')
- for (const container of targets) {
- if (container && container.innerHTML) {
- const re = new RegExp(`${keyword}`, 'gim')
- container.innerHTML = container.innerHTML.replace(
- re,
- `${keyword}`
- )
- }
- }
- }
- }, 100)
- }, [])
-
- return
-
-
-
-
-
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
-
-}
-
-export default LayoutSearch
diff --git a/themes/nobelium/LayoutSlug.js b/themes/nobelium/LayoutSlug.js
deleted file mode 100644
index b65af371..00000000
--- a/themes/nobelium/LayoutSlug.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import LayoutBase from './LayoutBase'
-import { ArticleLock } from './components/ArticleLock'
-import NotionPage from '@/components/NotionPage'
-import { ArticleInfo } from './components/ArticleInfo'
-import Comment from '@/components/Comment'
-import { ArticleFooter } from './components/ArticleFooter'
-import ShareBar from '@/components/ShareBar'
-
-export const LayoutSlug = props => {
- const { post, lock, validPassword } = props
-
- if (!post) {
- return
- }
-
- return (
-
-
- {lock && }
-
- {!lock && }
-
-
- )
-}
-
-export default LayoutSlug
diff --git a/themes/nobelium/LayoutTag.js b/themes/nobelium/LayoutTag.js
deleted file mode 100644
index 55607f00..00000000
--- a/themes/nobelium/LayoutTag.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import React from 'react'
-import BlogPost from './components/BlogPost'
-import Tags from './components/Tags'
-import LayoutBase from './LayoutBase'
-
-export const LayoutTag = props => {
- const { currentTag } = props
- const [searchValue, setSearchValue] = React.useState('')
- let filteredBlogPosts = []
- const { posts } = props
-
- if (posts) {
- filteredBlogPosts = posts.filter(post => {
- const tagContent = post.tags ? post.tags.join(' ') : ''
- const searchContent = post.title + post.summary + tagContent
- return searchContent.toLowerCase().includes(searchValue.toLowerCase())
- })
- }
-
- return
-
-
-
setSearchValue(e.target.value)}
- />
-
-
-
-
-
- {!filteredBlogPosts.length && (
-
No posts found.
- )}
- {filteredBlogPosts.slice(0, 20).map(post => (
-
- ))}
-
-
-}
-
-export default LayoutTag
diff --git a/themes/nobelium/LayoutTagIndex.js b/themes/nobelium/LayoutTagIndex.js
deleted file mode 100644
index 63ffa7ca..00000000
--- a/themes/nobelium/LayoutTagIndex.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import Link from 'next/link'
-import LayoutBase from './LayoutBase'
-
-export const LayoutTagIndex = (props) => {
- const { tagOptions } = props
- return (
-
-
- )
-}
-
-export default LayoutTagIndex
diff --git a/themes/nobelium/components/ArticleInfo.js b/themes/nobelium/components/ArticleInfo.js
index 6e37cad5..fc6e70fc 100644
--- a/themes/nobelium/components/ArticleInfo.js
+++ b/themes/nobelium/components/ArticleInfo.js
@@ -14,7 +14,7 @@ export const ArticleInfo = (props) => {
- {post.title}
+ {post?.title}
{post?.type !== 'Page' && <>
@@ -34,13 +34,13 @@ export const ArticleInfo = (props) => {
{formatDate(
- post?.publishTime || post.createdTime,
+ post?.publishTime || post?.createdTime,
BLOG.LANG
)}
{post.tags && (
- {post.tags.map(tag => (
+ {post?.tags.map(tag => (
))}
diff --git a/themes/nobelium/components/BlogArchiveItem.js b/themes/nobelium/components/BlogArchiveItem.js
new file mode 100644
index 00000000..3b16fc3b
--- /dev/null
+++ b/themes/nobelium/components/BlogArchiveItem.js
@@ -0,0 +1,41 @@
+import BLOG from '@/blog.config'
+import Link from 'next/link'
+
+/**
+ * 归档分组文章
+ * @param {*} param0
+ * @returns
+ */
+export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
+ return (
+
+
+ {archiveTitle}
+
+
+
+
+ )
+}
diff --git a/themes/nobelium/components/BlogListBar.js b/themes/nobelium/components/BlogListBar.js
new file mode 100644
index 00000000..69076937
--- /dev/null
+++ b/themes/nobelium/components/BlogListBar.js
@@ -0,0 +1,39 @@
+import Tags from './Tags'
+
+export default function BlogListBar(props) {
+ const { tag, setFilterKey } = props
+ const handleSearchChange = (val) => {
+ setFilterKey(val)
+ }
+ if (tag) {
+ return (
+
+
handleSearchChange(e.target.value)}
+ />
+
+
+
+
)
+ } else {
+ return <>>
+ }
+}
diff --git a/themes/nobelium/components/SearchNavBar.js b/themes/nobelium/components/SearchNavBar.js
new file mode 100644
index 00000000..79557cff
--- /dev/null
+++ b/themes/nobelium/components/SearchNavBar.js
@@ -0,0 +1,17 @@
+import SearchInput from './SearchInput'
+import Tags from './Tags'
+
+/**
+ * 搜索页面上方嵌入内容
+ * @param {*} props
+ * @returns
+ */
+export default function SearchNavBar(props) {
+ return (<>
+
+
+
+
+
+ >)
+}
diff --git a/themes/nobelium/index.js b/themes/nobelium/index.js
index 66ee12c8..db8f48f8 100644
--- a/themes/nobelium/index.js
+++ b/themes/nobelium/index.js
@@ -1,14 +1,261 @@
import CONFIG_NOBELIUM from './config_nobelium'
-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 React, { useEffect, useState } from 'react'
+import Nav from './components/Nav'
+import { Footer } from './components/Footer'
+import JumpToTopButton from './components/JumpToTopButton'
+import Live2D from '@/components/Live2D'
+import { useGlobal } from '@/lib/global'
+
+import BLOG from '@/blog.config'
+import Announcement from './components/Announcement'
+import { BlogListPage } from './components/BlogListPage'
+import { BlogListScroll } from './components/BlogListScroll'
+
+import { useRouter } from 'next/router'
+
+import Mark from 'mark.js'
+import { deepClone, isBrowser } from '@/lib/utils'
+import SearchNavBar from './components/SearchNavBar'
+import BlogArchiveItem from './components/BlogArchiveItem'
+
+import { ArticleLock } from './components/ArticleLock'
+import NotionPage from '@/components/NotionPage'
+import { ArticleInfo } from './components/ArticleInfo'
+import Comment from '@/components/Comment'
+import { ArticleFooter } from './components/ArticleFooter'
+import ShareBar from '@/components/ShareBar'
+
+import Link from 'next/link'
+import BlogListBar from './components/BlogListBar'
+
+/**
+ * 基础布局 采用左右两侧布局,移动端使用顶部导航栏
+
+ * @returns {JSX.Element}
+ * @constructor
+ */
+const LayoutBase = props => {
+ const { children, meta, post, topSlot } = props
+
+ const fullWidth = post?.fullWidth ?? false
+ const { onLoading } = useGlobal()
+
+ const LoadingCover =
+ return (
+
+ {/* SEO相关 */}
+
+
+ {/* 顶部导航栏 */}
+
+
+ {/* 主区 */}
+
+ {/* 顶部插槽 */}
+ {topSlot}
+
+ {onLoading ? LoadingCover : children}
+
+
+
+ {/* 页脚 */}
+
+
+ {/* 右下悬浮 */}
+
+
+
+
+ {/* 左下悬浮 */}
+
+
+
+
+ )
+}
+
+/**
+ * 首页
+ * 首页是个博客列表,加上顶部嵌入一个公告
+ * @param {*} props
+ * @returns
+ */
+const LayoutIndex = props => {
+ return (
+ } />
+ )
+}
+
+/**
+ * 博客列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutPostList = props => {
+ const { posts } = props
+
+ // 在列表中进行实时过滤
+ const [filterKey, setFilterKey] = useState('')
+ let filteredBlogPosts = []
+ if (filterKey && posts) {
+ filteredBlogPosts = posts.filter(post => {
+ const tagContent = post.tags ? post.tags.join(' ') : ''
+ const searchContent = post.title + post.summary + tagContent
+ return searchContent.toLowerCase().includes(filterKey.toLowerCase())
+ })
+ } else {
+ filteredBlogPosts = deepClone(posts)
+ }
+
+ return (
+ }>
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
+
+ )
+}
+
+/**
+ * 搜索
+ * 页面是博客列表,上方嵌入一个搜索引导条
+ * @param {*} props
+ * @returns
+ */
+const LayoutSearch = props => {
+ const { keyword } = props
+ const router = useRouter()
+
+ useEffect(() => {
+ 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'
+ })
+ }
+ }, 100)
+ }, [router.events])
+
+ return
} />
+}
+
+/**
+ * 归档
+ * @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 (
+
+
+ {lock && }
+
+ {!lock && }
+
+
+ )
+}
+
+/**
+ * 404 页面
+ * @param {*} props
+ * @returns
+ */
+const Layout404 = (props) => {
+ return
+ 404 Not found.
+
+}
+
+/**
+ * 文章分类列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutCategoryIndex = (props) => {
+ const { categoryOptions } = props
+
+ return (
+
+
+ {categoryOptions?.map(category => {
+ return (
+
+
+ {category.name}({category.count})
+
+
+ )
+ })}
+
+
+ )
+}
+
+/**
+ * 文章标签列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutTagIndex = (props) => {
+ const { tagOptions } = props
+ return (
+
+
+
+ )
+}
export {
CONFIG_NOBELIUM as THEME_CONFIG,
@@ -17,9 +264,7 @@ export {
LayoutArchive,
LayoutSlug,
Layout404,
- LayoutCategory,
+ LayoutPostList,
LayoutCategoryIndex,
- LayoutPage,
- LayoutTag,
LayoutTagIndex
}
diff --git a/themes/simple/Layout404.js b/themes/simple/Layout404.js
deleted file mode 100644
index c0992ad3..00000000
--- a/themes/simple/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/simple/LayoutArchive.js b/themes/simple/LayoutArchive.js
deleted file mode 100644
index e36a3210..00000000
--- a/themes/simple/LayoutArchive.js
+++ /dev/null
@@ -1,47 +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 => (
-
-
- {archiveTitle}
-
-
-
-
- ))}
-
-
- )
-}
-
-export default LayoutArchive
diff --git a/themes/simple/LayoutBase.js b/themes/simple/LayoutBase.js
deleted file mode 100644
index 8946e07f..00000000
--- a/themes/simple/LayoutBase.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import CommonHead from '@/components/CommonHead'
-import React from 'react'
-import { Header } from './components/Header'
-import { NavBar } from './components/NavBar'
-import { Footer } from './components/Footer'
-// import { Title } from './components/Title'
-import { SideBar } from './components/SideBar'
-import JumpToTopButton from './components/JumpToTopButton'
-import BLOG from '@/blog.config'
-import { TopBar } from './components/TopBar'
-import CONFIG_SIMPLE from './config_simple'
-import { isBrowser, loadExternalResource } from '@/lib/utils'
-import { useGlobal } from '@/lib/global'
-import { AdSlot } from '@/components/GoogleAdsense'
-
-/**
- * 基础布局 采用左右两侧布局,移动端使用顶部导航栏
-
- * @returns {JSX.Element}
- * @constructor
- */
-const LayoutBase = props => {
- const { children, meta } = props
- const { onLoading } = useGlobal()
-
- /**
- * 路由跳转时的遮罩
- */
- const LoadingCover =
-
- if (isBrowser()) {
- loadExternalResource('/css/theme-simple.css', 'css')
- }
- return (
-
-
-
- {CONFIG_SIMPLE.TOP_BAR &&
}
-
- {/* 顶部LOGO */}
-
-
- {/* 导航栏 */}
-
-
- {/* 主体 */}
-
-
- {onLoading ? LoadingCover : children}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export default LayoutBase
diff --git a/themes/simple/LayoutCategory.js b/themes/simple/LayoutCategory.js
deleted file mode 100644
index 517a5e82..00000000
--- a/themes/simple/LayoutCategory.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import BLOG from '@/blog.config'
-import { BlogListPage } from './components/BlogListPage'
-import { BlogListScroll } from './components/BlogListScroll'
-import LayoutBase from './LayoutBase'
-
-export const LayoutCategory = props => {
- return
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
-}
-
-export default LayoutCategory
diff --git a/themes/simple/LayoutCategoryIndex.js b/themes/simple/LayoutCategoryIndex.js
deleted file mode 100644
index d969516b..00000000
--- a/themes/simple/LayoutCategoryIndex.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import Link from 'next/link'
-import LayoutBase from './LayoutBase'
-
-export const LayoutCategoryIndex = props => {
- const { categoryOptions } = props
- return (
-
-
- {categoryOptions?.map(category => {
- return (
-
-
- {category.name}({category.count})
-
-
- )
- })}
-
-
- )
-}
-
-export default LayoutCategoryIndex
diff --git a/themes/simple/LayoutIndex.js b/themes/simple/LayoutIndex.js
deleted file mode 100644
index 18024d9c..00000000
--- a/themes/simple/LayoutIndex.js
+++ /dev/null
@@ -1,15 +0,0 @@
-
-import BLOG from '@/blog.config'
-import { BlogListPage } from './components/BlogListPage'
-import { BlogListScroll } from './components/BlogListScroll'
-import LayoutBase from './LayoutBase'
-
-export const LayoutIndex = props => {
- return (
-
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
- )
-}
-
-export default LayoutIndex
diff --git a/themes/simple/LayoutPage.js b/themes/simple/LayoutPage.js
deleted file mode 100644
index 184251a8..00000000
--- a/themes/simple/LayoutPage.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { BlogListPage } from './components/BlogListPage'
-import LayoutBase from './LayoutBase'
-
-export const LayoutPage = props => {
- return (
-
-
-
- )
-}
-
-export default LayoutPage
diff --git a/themes/simple/LayoutSearch.js b/themes/simple/LayoutSearch.js
deleted file mode 100644
index a3e41543..00000000
--- a/themes/simple/LayoutSearch.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import BLOG from '@/blog.config'
-import { BlogListPage } from './components/BlogListPage'
-import { BlogListScroll } from './components/BlogListScroll'
-import { useRouter } from 'next/router'
-import { useEffect } from 'react'
-import Mark from 'mark.js'
-import LayoutBase from './LayoutBase'
-import { isBrowser } from '@/lib/utils'
-
-export const LayoutSearch = props => {
- const { keyword } = props
- const router = useRouter()
-
- useEffect(() => {
- 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'
- })
- }
- }, 100)
- }, [router.events])
-
- useEffect(() => {
- setTimeout(() => {
- if (keyword) {
- const targets = document.getElementsByClassName('replace')
- for (const container of targets) {
- if (container && container.innerHTML) {
- const re = new RegExp(`${keyword}`, 'gim')
- container.innerHTML = container.innerHTML.replace(
- re,
- `
${keyword}`
- )
- }
- }
- }
- }, 100)
- }, [])
-
- return
-
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
-
-}
-
-export default LayoutSearch
diff --git a/themes/simple/LayoutSlug.js b/themes/simple/LayoutSlug.js
deleted file mode 100644
index 48f1f9db..00000000
--- a/themes/simple/LayoutSlug.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import LayoutBase from './LayoutBase'
-import { ArticleLock } from './components/ArticleLock'
-import NotionPage from '@/components/NotionPage'
-import { ArticleInfo } from './components/ArticleInfo'
-import Comment from '@/components/Comment'
-import ArticleAround from './components/ArticleAround'
-import ShareBar from '@/components/ShareBar'
-import { AdSlot } from '@/components/GoogleAdsense'
-
-export const LayoutSlug = props => {
- const { post, lock, validPassword, prev, next } = props
-
- return (
-
-
- {lock && }
-
-
-
-
-
-
-
- {!lock &&
}
-
-
-
-
-
- {post?.type === 'Post' &&
}
-
-
-
-
-
-
- )
-}
-
-export default LayoutSlug
diff --git a/themes/simple/LayoutTag.js b/themes/simple/LayoutTag.js
deleted file mode 100644
index f12ae546..00000000
--- a/themes/simple/LayoutTag.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import BLOG from '@/blog.config'
-import { BlogListPage } from './components/BlogListPage'
-import { BlogListScroll } from './components/BlogListScroll'
-import LayoutBase from './LayoutBase'
-
-export const LayoutTag = props => {
- return
- {BLOG.POST_LIST_STYLE === 'page' ? : }
-
-}
-
-export default LayoutTag
diff --git a/themes/simple/LayoutTagIndex.js b/themes/simple/LayoutTagIndex.js
deleted file mode 100644
index 63ffa7ca..00000000
--- a/themes/simple/LayoutTagIndex.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import Link from 'next/link'
-import LayoutBase from './LayoutBase'
-
-export const LayoutTagIndex = (props) => {
- const { tagOptions } = props
- return (
-
-
- )
-}
-
-export default LayoutTagIndex
diff --git a/themes/simple/components/BlogArchiveItem.js b/themes/simple/components/BlogArchiveItem.js
new file mode 100644
index 00000000..3b16fc3b
--- /dev/null
+++ b/themes/simple/components/BlogArchiveItem.js
@@ -0,0 +1,41 @@
+import BLOG from '@/blog.config'
+import Link from 'next/link'
+
+/**
+ * 归档分组文章
+ * @param {*} param0
+ * @returns
+ */
+export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
+ return (
+
+
+ {archiveTitle}
+
+
+
+
+ )
+}
diff --git a/themes/simple/components/SearchInput.js b/themes/simple/components/SearchInput.js
new file mode 100644
index 00000000..f0b43a39
--- /dev/null
+++ b/themes/simple/components/SearchInput.js
@@ -0,0 +1,86 @@
+import { useRouter } from 'next/router'
+import { useImperativeHandle, useRef, useState } from 'react'
+let lock = false
+
+const SearchInput = ({ keyword, cRef, className }) => {
+ const [onLoading, setLoadingState] = useState(false)
+ const router = useRouter()
+ const searchInputRef = useRef()
+ useImperativeHandle(cRef, () => {
+ return {
+ focus: () => {
+ searchInputRef?.current?.focus()
+ }
+ }
+ })
+
+ const handleSearch = () => {
+ const key = searchInputRef.current.value
+
+ if (key && key !== '') {
+ setLoadingState(true)
+ location.href = '/search/' + key
+ } else {
+ router.push({ pathname: '/' }).then(r => {
+ })
+ }
+ }
+ const handleKeyUp = (e) => {
+ if (e.keyCode === 13) { // 回车
+ handleSearch(searchInputRef.current.value)
+ } else if (e.keyCode === 27) { // ESC
+ cleanSearch()
+ }
+ }
+ const cleanSearch = () => {
+ searchInputRef.current.value = ''
+ }
+
+ const [showClean, setShowClean] = useState(false)
+ const updateSearchKey = (val) => {
+ if (lock) {
+ return
+ }
+ searchInputRef.current.value = val
+
+ if (val) {
+ setShowClean(true)
+ } else {
+ setShowClean(false)
+ }
+ }
+ function lockSearchInput() {
+ lock = true
+ }
+
+ function unLockSearchInput() {
+ lock = false
+ }
+
+ return
+
updateSearchKey(e.target.value)}
+ defaultValue={keyword}
+ />
+
+
+
+
+
+ {(showClean &&
+
+
+
+ )}
+
+}
+
+export default SearchInput
diff --git a/themes/simple/index.js b/themes/simple/index.js
index 91775a1d..c3f18673 100644
--- a/themes/simple/index.js
+++ b/themes/simple/index.js
@@ -1,14 +1,263 @@
import CONFIG_SIMPLE from './config_simple'
-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 { BlogListPage } from './components/BlogListPage'
+import { BlogListScroll } from './components/BlogListScroll'
+
+import { useRouter } from 'next/router'
+import { useEffect } from 'react'
+import Mark from 'mark.js'
+import { isBrowser, loadExternalResource } from '@/lib/utils'
+import BlogArchiveItem from './components/BlogArchiveItem'
+
+import { ArticleLock } from './components/ArticleLock'
+import NotionPage from '@/components/NotionPage'
+import { ArticleInfo } from './components/ArticleInfo'
+import Comment from '@/components/Comment'
+import ArticleAround from './components/ArticleAround'
+import ShareBar from '@/components/ShareBar'
+import { AdSlot } from '@/components/GoogleAdsense'
+import Link from 'next/link'
+import CommonHead from '@/components/CommonHead'
+import { TopBar } from './components/TopBar'
+import { Header } from './components/Header'
+import { NavBar } from './components/NavBar'
+import BLOG from '@/blog.config'
+import { SideBar } from './components/SideBar'
+import JumpToTopButton from './components/JumpToTopButton'
+import { Footer } from './components/Footer'
+import { useGlobal } from '@/lib/global'
+import SearchInput from './components/SearchInput'
+
+/**
+ * 基础布局
+ *
+ * @param {*} props
+ * @returns
+ */
+const LayoutBase = props => {
+ const { children, meta, slotTop } = props
+ const { onLoading } = useGlobal()
+
+ /**
+ * 路由跳转时的遮罩
+ */
+ const LoadingCover =
+
+ if (isBrowser()) {
+ loadExternalResource('/css/theme-simple.css', 'css')
+ }
+ return (
+
+
+
+ {CONFIG_SIMPLE.TOP_BAR &&
}
+
+ {/* 顶部LOGO */}
+
+
+ {/* 导航栏 */}
+
+
+ {/* 主体 */}
+
+
+ {slotTop}
+ {onLoading ? LoadingCover : children}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+/**
+ * 博客首页
+ * 首页就是列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutIndex = props => {
+ return
+}
+/**
+ * 博客列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutPostList = props => {
+ return (
+
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
+
+ )
+}
+
+/**
+ * 搜索页
+ * 也是博客列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutSearch = props => {
+ const { keyword } = props
+ const router = useRouter()
+ useEffect(() => {
+ 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'
+ })
+ }
+ }, 100)
+ }, [router])
+
+ return
} />
+}
+
+/**
+ * 归档页
+ * @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, prev, next } = props
+
+ return (
+
+
+ {lock && }
+
+
+
+ {/* 文章信息 */}
+
+
+ {/* 广告嵌入 */}
+
+
+ {/* Notion文章主体 */}
+ {!lock &&
}
+
+ {/* 分享 */}
+
+
+ {/* 广告嵌入 */}
+
+
+ {post?.type === 'Post' &&
}
+
+ {/* 评论区 */}
+
+
+
+
+
+ )
+}
+
+/**
+ * 404
+ * @param {*} props
+ * @returns
+ */
+const Layout404 = (props) => {
+ return
+ 404 Not found.
+
+}
+
+/**
+ * 分类列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutCategoryIndex = props => {
+ const { categoryOptions } = props
+ return (
+
+
+ {categoryOptions?.map(category => {
+ return (
+
+
+ {category.name}({category.count})
+
+
+ )
+ })}
+
+
+ )
+}
+
+/**
+ * 标签列表
+ * @param {*} props
+ * @returns
+ */
+const LayoutTagIndex = (props) => {
+ const { tagOptions } = props
+ return (
+
+
+
+ )
+}
export {
CONFIG_SIMPLE as THEME_CONFIG,
@@ -17,9 +266,7 @@ export {
LayoutArchive,
LayoutSlug,
Layout404,
- LayoutCategory,
LayoutCategoryIndex,
- LayoutPage,
- LayoutTag,
+ LayoutPostList,
LayoutTagIndex
}