diff --git a/public/bg_image.jpg b/public/bg_image.jpg
old mode 100755
new mode 100644
index cfbe96f5..d602ff36
Binary files a/public/bg_image.jpg and b/public/bg_image.jpg differ
diff --git a/styles/globals.css b/styles/globals.css
index 70eec009..cd9aab7b 100644
--- a/styles/globals.css
+++ b/styles/globals.css
@@ -188,4 +188,8 @@ nav {
width: 100%;
background-image: linear-gradient(-180deg,rgba(255,255,255,0) 0%,#fff 70%);
padding-bottom: 34px;
+}
+
+.shadow-text{
+ text-shadow: 0.1em 0.1em 0.2em black;
}
\ No newline at end of file
diff --git a/themes/Empty/LayoutSlug.js b/themes/Empty/LayoutSlug.js
index cb5844df..4def0283 100644
--- a/themes/Empty/LayoutSlug.js
+++ b/themes/Empty/LayoutSlug.js
@@ -1,3 +1,4 @@
+import BLOG from '@/blog.config'
import 'prismjs'
import 'prismjs/components/prism-bash'
import 'prismjs/components/prism-javascript'
@@ -5,6 +6,7 @@ import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-python'
import 'prismjs/components/prism-typescript'
import { Code, Collection, CollectionRow, Equation, NotionRenderer } from 'react-notion-x'
+import LayoutBase from './LayoutBase'
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
@@ -12,7 +14,14 @@ const mapPageUrl = id => {
export const LayoutSlug = (props) => {
const { post } = props
- return
{
diff --git a/themes/Hexo/components/LatestPostsGroup.js b/themes/Hexo/components/LatestPostsGroup.js
new file mode 100644
index 00000000..78782e69
--- /dev/null
+++ b/themes/Hexo/components/LatestPostsGroup.js
@@ -0,0 +1,42 @@
+import BLOG from '@/blog.config'
+import { useGlobal } from '@/lib/global'
+import { faArchive, faFileAlt } from '@fortawesome/free-solid-svg-icons'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import Link from 'next/link'
+import { useRouter } from 'next/router'
+
+/**
+ * 最新文章列表
+ * @param posts 所有文章数据
+ * @param sliceCount 截取展示的数量 默认6
+ * @constructor
+ */
+const LatestPostsGroup = ({ posts }) => {
+ if (!posts) {
+ return <>>
+ }
+ // 获取当前路径
+ const currentPath = useRouter().asPath
+ const { locale } = useGlobal()
+
+ return <>
+
+
{locale.COMMON.LATEST_POSTS}
+
+ {posts.map(post => {
+ const selected = currentPath === `${BLOG.PATH}/article/${post.slug}`
+ return (
+
+
+
+
+
+ )
+ })}
+ >
+}
+export default LatestPostsGroup
diff --git a/themes/Hexo/components/MenuButtonGroup.js b/themes/Hexo/components/MenuButtonGroup.js
new file mode 100644
index 00000000..53528653
--- /dev/null
+++ b/themes/Hexo/components/MenuButtonGroup.js
@@ -0,0 +1,41 @@
+import React from 'react'
+import Link from 'next/link'
+import { useRouter } from 'next/router'
+import { useGlobal } from '@/lib/global'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faArchive, faHome, faTag, faTh, faUser } from '@fortawesome/free-solid-svg-icons'
+import CONFIG_HEXO from '../config_hexo'
+
+const MenuButtonGroup = ({ postCount }) => {
+ const { locale } = useGlobal()
+ const router = useRouter()
+ const archiveSlot =
{postCount}
+
+ const links = [
+ { id: 0, icon: faHome, name: locale.NAV.INDEX, to: '/' || '/', show: true },
+ { id: 1, icon: faTh, name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_HEXO.MENU_CATEGORY },
+ { id: 2, icon: faTag, name: locale.COMMON.TAGS, to: '/tag', show: CONFIG_HEXO.MENU_TAG },
+ { id: 3, icon: faArchive, name: locale.NAV.ARCHIVE, to: '/archive', slot: archiveSlot, show: CONFIG_HEXO.MENU_ARCHIVE },
+ { id: 4, icon: faUser, name: locale.NAV.ABOUT, to: '/about', show: CONFIG_HEXO.MENU_ABOUT }
+ ]
+ return
+}
+export default MenuButtonGroup
diff --git a/themes/Hexo/components/PaginationNumber.js b/themes/Hexo/components/PaginationNumber.js
new file mode 100644
index 00000000..bec6f399
--- /dev/null
+++ b/themes/Hexo/components/PaginationNumber.js
@@ -0,0 +1,94 @@
+import BLOG from '@/blog.config'
+import Link from 'next/link'
+import { useRouter } from 'next/router'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons'
+
+/**
+ * 数字翻页插件
+ * @param page 当前页码
+ * @param showNext 是否有下一页
+ * @returns {JSX.Element}
+ * @constructor
+ */
+const PaginationNumber = ({ page, totalPage }) => {
+ const router = useRouter()
+ const currentPage = +page
+ const showNext = page !== totalPage
+ const pages = generatePages(page, currentPage, totalPage)
+
+ return (
+
+
+ {/* 上一页 */}
+
+
+
+
+
+
+ {pages}
+
+ {/* 下一页 */}
+
+
+
+
+
+
+ )
+}
+
+function getPageElement (page, currentPage) {
+ return
+
+ {page}
+
+
+}
+function generatePages (page, currentPage, totalPage) {
+ const pages = []
+ const groupCount = 7 // 最多显示页签数
+ if (totalPage <= groupCount) {
+ for (let i = 1; i <= totalPage; i++) {
+ pages.push(getPageElement(i, page))
+ }
+ } else {
+ pages.push(getPageElement(1, page))
+ const dynamicGroupCount = groupCount - 2
+ let startPage = currentPage - 2
+ if (startPage <= 1) {
+ startPage = 2
+ }
+ if (startPage + dynamicGroupCount > totalPage) {
+ startPage = totalPage - dynamicGroupCount
+ }
+ if (startPage > 2) {
+ pages.push(
...
)
+ }
+
+ for (let i = 0; i < dynamicGroupCount; i++) {
+ if (startPage + i < totalPage) {
+ pages.push(getPageElement(startPage + i, page))
+ }
+ }
+
+ if (startPage + dynamicGroupCount < totalPage) {
+ pages.push(
...
)
+ }
+
+ pages.push(getPageElement(totalPage, page))
+ }
+ return pages
+}
+export default PaginationNumber
diff --git a/themes/Hexo/components/SearchInput.js b/themes/Hexo/components/SearchInput.js
new file mode 100644
index 00000000..57e16633
--- /dev/null
+++ b/themes/Hexo/components/SearchInput.js
@@ -0,0 +1,68 @@
+import { useRouter } from 'next/router'
+import { useImperativeHandle, useRef, useState } from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faSearch, faSpinner, faTimes } from '@fortawesome/free-solid-svg-icons'
+
+const SearchInput = ({ currentTag, currentSearch, cRef }) => {
+ const [searchKey, setSearchKey] = useState(currentSearch || '')
+ const [onLoading, setLoadingState] = useState(false)
+ const router = useRouter()
+ const searchInputRef = useRef()
+ useImperativeHandle(cRef, () => {
+ return {
+ focus: () => {
+ searchInputRef?.current?.focus()
+ }
+ }
+ })
+ const handleSearch = (key) => {
+ if (key && key !== '') {
+ setLoadingState(true)
+ router.push({ pathname: '/search', query: { s: key } }).then(r => {
+ setLoadingState(false)
+ })
+ } 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 = ''
+ setSearchKey('')
+ }
+
+ const updateSearchKey = (val) => {
+ setSearchKey(val)
+ }
+
+ return
+
updateSearchKey(e.target.value)}
+ defaultValue={searchKey}
+ />
+
+
{ handleSearch(searchKey) }}>
+
+
+
+ {(searchKey && searchKey.length &&
+
+
+
+ )}
+
+}
+
+export default SearchInput
diff --git a/themes/Hexo/components/SideRight.js b/themes/Hexo/components/SideRight.js
new file mode 100644
index 00000000..adac7e09
--- /dev/null
+++ b/themes/Hexo/components/SideRight.js
@@ -0,0 +1,64 @@
+import Router from 'next/router'
+import Image from 'next/image'
+import BLOG from '@/blog.config'
+import Card from './Card'
+import MenuButtonGroup from './MenuButtonGroup'
+import SearchInput from './SearchInput'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faChartArea, faTh } from '@fortawesome/free-solid-svg-icons'
+import CategoryGroup from './CategoryGroup'
+import LatestPostsGroup from './LatestPostsGroup'
+import TagGroups from './TagGroups'
+import SocialButton from './SocialButton'
+
+export default function SideRight (props) {
+ const { postCount, currentCategory, categories, latestPosts, tags, currentTag } = props
+ return
+
+ { Router.push('/') }}>
+
+
+ {BLOG.TITLE}
+
+
+
+
+
+
+
+
+ 统计
+
+
+
+
+
+ 分类
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/themes/Hexo/components/SocialButton.js b/themes/Hexo/components/SocialButton.js
new file mode 100644
index 00000000..4a4c6a2e
--- /dev/null
+++ b/themes/Hexo/components/SocialButton.js
@@ -0,0 +1,36 @@
+import BLOG from '@/blog.config'
+import { faGithub, faTelegram, faTwitter, faWeibo } from '@fortawesome/free-brands-svg-icons'
+import { faEnvelope, faRss } from '@fortawesome/free-solid-svg-icons'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import React from 'react'
+
+/**
+ * 社交联系方式按钮组
+ * @returns {JSX.Element}
+ * @constructor
+ */
+const SocialButton = () => {
+ return
+
+ {BLOG.CONTACT_GITHUB &&
+
+ }
+ {BLOG.CONTACT_TWITTER &&
+
+ }
+ {BLOG.CONTACT_TELEGRAM &&
+
+ }
+ {BLOG.CONTACT_WEIBO &&
+
+ }
+ {BLOG.CONTACT_EMAIL &&
+
+ }
+
+
+
+
+
+}
+export default SocialButton
diff --git a/themes/Hexo/components/TagGroups.js b/themes/Hexo/components/TagGroups.js
new file mode 100644
index 00000000..9f87776f
--- /dev/null
+++ b/themes/Hexo/components/TagGroups.js
@@ -0,0 +1,29 @@
+import { faTag } from '@fortawesome/free-solid-svg-icons'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import TagItemMini from './TagItemMini'
+
+/**
+ * 标签组
+ * @param tags
+ * @param currentTag
+ * @returns {JSX.Element}
+ * @constructor
+ */
+const TagGroups = ({ tags, currentTag }) => {
+ if (!tags) return <>>
+ return (
+
+ )
+}
+
+export default TagGroups
diff --git a/themes/Hexo/components/TagItemMini.js b/themes/Hexo/components/TagItemMini.js
new file mode 100644
index 00000000..e687413f
--- /dev/null
+++ b/themes/Hexo/components/TagItemMini.js
@@ -0,0 +1,17 @@
+import { faTag } from '@fortawesome/free-solid-svg-icons'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import Link from 'next/link'
+
+const TagItemMini = ({ tag, selected = false }) => {
+ return
+
+ {selected && } {tag.name + (tag.count ? `(${tag.count})` : '')}
+
+
+}
+
+export default TagItemMini
diff --git a/themes/Hexo/config_hexo.js b/themes/Hexo/config_hexo.js
index 6da54488..4581a256 100644
--- a/themes/Hexo/config_hexo.js
+++ b/themes/Hexo/config_hexo.js
@@ -1,6 +1,15 @@
const CONFIG_HEXO = {
HOME_BANNER_ENABLE: true,
HOME_BANNER_GREETINGS: ['Hi,我是一个程序员', 'Hi,我是一个打工人', 'Hi,我是一个干饭人', '欢迎来到我的博客🎉'], // 首页大图标语文字
- HOME_BANNER_IMAGE: './bg_image.jpg' // see /public/bg_image.jpg
+ HOME_BANNER_IMAGE: './bg_image.jpg', // see /public/bg_image.jpg
+
+ // 菜单
+ MENU_ABOUT: false, // 显示关于
+ MENU_CATEGORY: true, // 显示分类
+ MENU_TAG: true, // 显示标签
+ MENU_ARCHIVE: true, // 显示归档
+ MENU_SEARCH: true, // 显示搜索
+
+ POST_LIST_COVER: true // 文章封面
}
export default CONFIG_HEXO
diff --git a/themes/index.js b/themes/index.js
index a519f091..4f34ef8d 100644
--- a/themes/index.js
+++ b/themes/index.js
@@ -2,7 +2,7 @@
* 修改 from 后面的路径,实现主题切换
*/
-// export * from './NEXT' // 切换主题
+// export * from './Empty' // 空主题
+// export * from './NEXT'
// export * from './Fukasawa'
-// export * from './Empty'
-export * from './Hexo'
+export * from './Hexo' //