diff --git a/pages/404.js b/pages/404.js
index 7fd48806..64cc2dc7 100644
--- a/pages/404.js
+++ b/pages/404.js
@@ -6,6 +6,6 @@ import { Layout404 } from '@/themes'
* @constructor
*/
-export default function Custom404 () {
- return
+export default function Custom404 (props) {
+ return
}
diff --git a/pages/about.js b/pages/about.js
index af382f68..895a94f3 100644
--- a/pages/about.js
+++ b/pages/about.js
@@ -11,7 +11,7 @@ import { LayoutSlug } from '@/themes'
*/
const About = (props) => {
if (!props.post) {
- return
+ return
}
return
}
diff --git a/pages/article/[slug].js b/pages/article/[slug].js
index 7903994f..bdc6d706 100644
--- a/pages/article/[slug].js
+++ b/pages/article/[slug].js
@@ -11,7 +11,7 @@ import Custom404 from '@/pages/404'
*/
const Slug = (props) => {
if (!props.post) {
- return
+ return
}
return
}
diff --git a/pages/page/[page].js b/pages/page/[page].js
index 2c5cadf0..43d16aec 100644
--- a/pages/page/[page].js
+++ b/pages/page/[page].js
@@ -6,7 +6,7 @@ import Custom404 from '@/pages/404'
const Page = (props) => {
if (!props?.meta) {
- return
+ return
}
return
}
diff --git a/pages/tag/[tag].js b/pages/tag/[tag].js
index 908c329d..2c72b75f 100644
--- a/pages/tag/[tag].js
+++ b/pages/tag/[tag].js
@@ -16,7 +16,7 @@ export async function getStaticProps ({ params }) {
latestPosts
} = await getGlobalNotionData({
from,
- includePage: true,
+ includePage: false,
tagsCount: 0
})
const filteredPosts = allPosts.filter(
diff --git a/themes/Hexo/Layout404.js b/themes/Hexo/Layout404.js
index cd28a607..a1dfe4cd 100644
--- a/themes/Hexo/Layout404.js
+++ b/themes/Hexo/Layout404.js
@@ -1,6 +1,39 @@
+import BLOG from '@/blog.config'
+import { faSpinner } from '@fortawesome/free-solid-svg-icons'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { useRouter } from 'next/router'
+import { useEffect } from 'react'
+import LayoutBase from './LayoutBase'
-export const Layout404 = () => {
- return
- 404 Not found.
-
+export const Layout404 = props => {
+ const router = useRouter()
+ useEffect(() => {
+ // 延时3秒如果加载失败就返回首页
+ setTimeout(() => {
+ if (window) {
+ const article = document.getElementById('container')
+ if (!article) {
+ router.push('/').then(() => {
+ console.log('找不到页面', router.asPath)
+ })
+ }
+ }
+ }, 3000)
+ })
+
+ return (
+
+
+
+
+
+ 404
+
+
+
页面无法加载,即将返回首页
+
+
+
+
+ )
}
diff --git a/themes/Hexo/LayoutArchive.js b/themes/Hexo/LayoutArchive.js
index e46502fc..a42b7993 100644
--- a/themes/Hexo/LayoutArchive.js
+++ b/themes/Hexo/LayoutArchive.js
@@ -1,5 +1,64 @@
-export const LayoutArchive = ({ posts, tags, categories, postCount }) => {
- return
- Archive Page
-
+import BLOG from '@/blog.config'
+import { useGlobal } from '@/lib/global'
+import { useEffect } from 'react'
+import BlogPostArchive from './components/BlogPostArchive'
+import Card from './components/Card'
+import LayoutBase from './LayoutBase'
+
+export const LayoutArchive = (props) => {
+ const { posts } = props
+ const { locale } = useGlobal()
+ // 深拷贝
+ const postsSortByDate = Object.create(posts)
+
+ // 时间排序
+ postsSortByDate.sort((a, b) => {
+ const dateA = new Date(a?.date.start_date || a.createdTime)
+ const dateB = new Date(b?.date.start_date || b.createdTime)
+ return dateB - dateA
+ })
+
+ const meta = {
+ title: `${locale.NAV.ARCHIVE} | ${BLOG.TITLE}`,
+ description: BLOG.DESCRIPTION,
+ type: 'website'
+ }
+
+ const archivePosts = {}
+
+ postsSortByDate.forEach(post => {
+ const date = post.date.start_date.slice(0, 7)
+ if (archivePosts[date]) {
+ archivePosts[date].push(post)
+ } else {
+ archivePosts[date] = [post]
+ }
+ })
+
+ useEffect(() => {
+ if (window) {
+ 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 => (
+
+ ))}
+
+
+
}
diff --git a/themes/Hexo/LayoutCategory.js b/themes/Hexo/LayoutCategory.js
index 60e0d11a..92c5a8a1 100644
--- a/themes/Hexo/LayoutCategory.js
+++ b/themes/Hexo/LayoutCategory.js
@@ -1,5 +1,17 @@
-export const LayoutCategory = ({ tags, posts, category, categories, latestPosts, postCount }) => {
- return
- Category - {category}
-
+import BLOG from '@/blog.config'
+import { useGlobal } from '@/lib/global'
+import BlogPostListScroll from './components/BlogPostListScroll'
+import LayoutBase from './LayoutBase'
+
+export const LayoutCategory = (props) => {
+ const { tags, posts, category } = props
+ const { locale } = useGlobal()
+ const meta = {
+ title: `${category} | ${locale.COMMON.CATEGORY} | ${BLOG.TITLE}`,
+ description: BLOG.DESCRIPTION,
+ type: 'website'
+ }
+ return
+
+
}
diff --git a/themes/Hexo/LayoutCategoryIndex.js b/themes/Hexo/LayoutCategoryIndex.js
index 467bde1c..f0d1e978 100644
--- a/themes/Hexo/LayoutCategoryIndex.js
+++ b/themes/Hexo/LayoutCategoryIndex.js
@@ -1,11 +1,43 @@
-export const LayoutCategoryIndex = ({
- tags,
- allPosts,
- categories,
- postCount,
- latestPosts
-}) => {
- return
- CategoryIndex
-
+import BLOG from '@/blog.config'
+import { useGlobal } from '@/lib/global'
+import { faFolder, faTh } from '@fortawesome/free-solid-svg-icons'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import Link from 'next/link'
+import Card from './components/Card'
+import LayoutBase from './LayoutBase'
+
+export const LayoutCategoryIndex = props => {
+ const { categories } = props
+ const { locale } = useGlobal()
+ const meta = {
+ title: `${locale.COMMON.CATEGORY} | ${BLOG.TITLE}`,
+ description: BLOG.DESCRIPTION,
+ type: 'website'
+ }
+ return (
+
+
+
+
+ {locale.COMMON.CATEGORY}:
+
+
+ {Object.keys(categories).map(category => {
+ return (
+
+
+
+ {category}({categories[category]})
+
+
+ )
+ })}
+
+
+
+ )
}
diff --git a/themes/Hexo/LayoutPage.js b/themes/Hexo/LayoutPage.js
index c025ff3c..d4ab7079 100644
--- a/themes/Hexo/LayoutPage.js
+++ b/themes/Hexo/LayoutPage.js
@@ -1,5 +1,9 @@
-export const LayoutPage = ({ page, posts, tags, meta, categories, postCount, latestPosts }) => {
- return
- Page - {page}
-
+import BlogPostListPage from './components/BlogPostListPage'
+import LayoutBase from './LayoutBase'
+
+export const LayoutPage = (props) => {
+ const { page, posts, postCount } = props
+ return
+
+
}
diff --git a/themes/Hexo/LayoutSearch.js b/themes/Hexo/LayoutSearch.js
index 76e4867c..77be5014 100644
--- a/themes/Hexo/LayoutSearch.js
+++ b/themes/Hexo/LayoutSearch.js
@@ -1,11 +1,11 @@
+import BLOG from '@/blog.config'
+import { useGlobal } from '@/lib/global'
import { useRouter } from 'next/router'
+import BlogPostListPage from './components/BlogPostListPage'
+import LayoutBase from './LayoutBase'
-export const LayoutSearch = ({
- posts,
- tags,
- categories,
- postCount
-}) => {
+export const LayoutSearch = (props) => {
+ const { posts } = props
let filteredPosts
const searchKey = getSearchKey()
if (searchKey) {
@@ -18,11 +18,15 @@ export const LayoutSearch = ({
filteredPosts = posts
}
- console.log(filteredPosts)
-
- return
- Search {searchKey}
-
+ const { locale } = useGlobal()
+ const meta = {
+ title: `${searchKey || ''} | ${locale.NAV.SEARCH} | ${BLOG.TITLE} `,
+ description: BLOG.DESCRIPTION,
+ type: 'website'
+ }
+ return
+
+
}
function getSearchKey () {
diff --git a/themes/Hexo/LayoutTag.js b/themes/Hexo/LayoutTag.js
index cae36f38..7f6249e1 100644
--- a/themes/Hexo/LayoutTag.js
+++ b/themes/Hexo/LayoutTag.js
@@ -1,5 +1,19 @@
-export const LayoutTag = ({ tags, posts, tag, categories, postCount, latestPosts }) => {
- return
- Tag - {tag}
-
+import BLOG from '@/blog.config'
+import { useGlobal } from '@/lib/global'
+import BlogPostListScroll from './components/BlogPostListScroll'
+import LayoutBase from './LayoutBase'
+
+export const LayoutTag = (props) => {
+ const { tags, posts, tag } = props
+ const { locale } = useGlobal()
+
+ const meta = {
+ title: `${tag} | ${locale.COMMON.TAGS} | ${BLOG.TITLE}`,
+ description: BLOG.DESCRIPTION,
+ type: 'website'
+ }
+
+ return
+
+
}
diff --git a/themes/Hexo/LayoutTagIndex.js b/themes/Hexo/LayoutTagIndex.js
index deb76f8e..879fe696 100644
--- a/themes/Hexo/LayoutTagIndex.js
+++ b/themes/Hexo/LayoutTagIndex.js
@@ -1,5 +1,36 @@
-export const LayoutTagIndex = ({ tags, categories, postCount, latestPosts }) => {
- return
- TagIndex
-
+import BLOG from '@/blog.config'
+import { useGlobal } from '@/lib/global'
+import { faTag } from '@fortawesome/free-solid-svg-icons'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import Card from './components/Card'
+import TagItemMini from './components/TagItemMini'
+import LayoutBase from './LayoutBase'
+
+export const LayoutTagIndex = props => {
+ const { tags } = props
+ const { locale } = useGlobal()
+ const meta = {
+ title: `${locale.COMMON.TAGS} | ${BLOG.TITLE}`,
+ description: BLOG.DESCRIPTION,
+ type: 'website'
+ }
+ return (
+
+
+
+
+ {locale.COMMON.TAGS}:
+
+
+
+
+ )
}
diff --git a/themes/Hexo/components/BlogPostArchive.js b/themes/Hexo/components/BlogPostArchive.js
new file mode 100644
index 00000000..5c3bc169
--- /dev/null
+++ b/themes/Hexo/components/BlogPostArchive.js
@@ -0,0 +1,32 @@
+import React from 'react'
+import Link from 'next/link'
+import BLOG from '@/blog.config'
+/**
+ * 博客归档列表
+ * @param posts 所有文章
+ * @param archiveTitle 归档标题
+ * @returns {JSX.Element}
+ * @constructor
+ */
+const BlogPostArchive = ({ posts = [], archiveTitle }) => {
+ if (!posts || posts.length === 0) {
+ return <>>
+ } else {
+ return
+
{archiveTitle}
+
+ {posts.map(post => (
+ -
+
{post.date.start_date}
+
+
{post.title}
+
+
+
+ ))}
+
+
+ }
+}
+
+export default BlogPostArchive
diff --git a/themes/Hexo/components/BlogPostListScroll.js b/themes/Hexo/components/BlogPostListScroll.js
new file mode 100644
index 00000000..53a1d93f
--- /dev/null
+++ b/themes/Hexo/components/BlogPostListScroll.js
@@ -0,0 +1,88 @@
+import BLOG from '@/blog.config'
+import BlogPostCard from './BlogPostCard'
+import BlogPostListEmpty from './BlogPostListEmpty'
+import { useGlobal } from '@/lib/global'
+import throttle from 'lodash.throttle'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import CONFIG_HEXO from '../config_hexo'
+
+/**
+ * 博客列表滚动分页
+ * @param posts 所有文章
+ * @param tags 所有标签
+ * @returns {JSX.Element}
+ * @constructor
+ */
+const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = CONFIG_HEXO.POST_LIST_SUMMARY }) => {
+ const postsPerPage = BLOG.POSTS_PER_PAGE
+ const [page, updatePage] = useState(1)
+ const postsToShow = getPostByPage(page, posts, postsPerPage)
+
+ let hasMore = false
+ if (posts) {
+ const totalCount = posts.length
+ hasMore = page * postsPerPage < totalCount
+ }
+
+ const handleGetMore = () => {
+ if (!hasMore) return
+ updatePage(page + 1)
+ }
+
+ // 监听滚动自动分页加载
+ const scrollTrigger = useCallback(throttle(() => {
+ const scrollS = window.scrollY + window.outerHeight
+ const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0
+ if (scrollS > clientHeight + 100) {
+ handleGetMore()
+ }
+ }, 500))
+
+ // 监听滚动
+ useEffect(() => {
+ window.addEventListener('scroll', scrollTrigger)
+ return () => {
+ window.removeEventListener('scroll', scrollTrigger)
+ }
+ })
+
+ const targetRef = useRef(null)
+ const { locale } = useGlobal()
+
+ if (!postsToShow || postsToShow.length === 0) {
+ return
+ } else {
+ return
+
+ {/* 文章列表 */}
+
+ {postsToShow.map(post => (
+
+ ))}
+
+
+
+
{
+ handleGetMore()
+ }}
+ className='w-full my-4 py-4 text-center cursor-pointer glassmorphism shadow-xl rounded-xl dark:text-gray-200'
+ > {hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}
+
+
+ }
+}
+
+/**
+ * 获取从第1页到指定页码的文章
+ * @param page 第几页
+ * @param totalPosts 所有文章
+ * @param postsPerPage 每页文章数量
+ * @returns {*}
+ */
+const getPostByPage = function (page, totalPosts, postsPerPage) {
+ return totalPosts.slice(
+ 0,
+ postsPerPage * page
+ )
+}
+export default BlogPostListScroll
diff --git a/themes/Hexo/components/CategoryGroup.js b/themes/Hexo/components/CategoryGroup.js
index bc07e00a..e89159c4 100644
--- a/themes/Hexo/components/CategoryGroup.js
+++ b/themes/Hexo/components/CategoryGroup.js
@@ -4,6 +4,9 @@ import Link from 'next/link'
import React from 'react'
const CategoryGroup = ({ currentCategory, categories }) => {
+ if (!categories) {
+ return <>>
+ }
return <>
{Object.keys(categories).map(category => {
diff --git a/themes/Hexo/components/PaginationNumber.js b/themes/Hexo/components/PaginationNumber.js
index bec6f399..f37d8704 100644
--- a/themes/Hexo/components/PaginationNumber.js
+++ b/themes/Hexo/components/PaginationNumber.js
@@ -27,7 +27,7 @@ const PaginationNumber = ({ page, totalPage }) => {
} } passHref >
@@ -39,7 +39,7 @@ const PaginationNumber = ({ page, totalPage }) => {
@@ -50,8 +50,8 @@ const PaginationNumber = ({ page, totalPage }) => {
function getPageElement (page, currentPage) {
return
-
+
{page}
diff --git a/themes/Hexo/config_hexo.js b/themes/Hexo/config_hexo.js
index 4581a256..b0b6edf7 100644
--- a/themes/Hexo/config_hexo.js
+++ b/themes/Hexo/config_hexo.js
@@ -10,6 +10,7 @@ const CONFIG_HEXO = {
MENU_ARCHIVE: true, // 显示归档
MENU_SEARCH: true, // 显示搜索
- POST_LIST_COVER: true // 文章封面
+ POST_LIST_COVER: true, // 文章封面
+ POST_LIST_SUMMARY: true // 文章摘要
}
export default CONFIG_HEXO