diff --git a/blog.config.js b/blog.config.js
index 39e8336b..94b978ab 100644
--- a/blog.config.js
+++ b/blog.config.js
@@ -405,6 +405,7 @@ const BLOG = {
DEBUG: process.env.NEXT_PUBLIC_DEBUG || false, // 是否显示调试按钮
ENABLE_CACHE: process.env.ENABLE_CACHE || process.env.npm_lifecycle_event === 'build', // 缓存在开发调试和打包过程中选择性开启,正式部署开启此功能意义不大。
isProd: process.env.VERCEL_ENV === 'production', // distinguish between development and production environment (ref: https://vercel.com/docs/environment-variables#system-environment-variables) isProd: process.env.VERCEL_ENV === 'production' // distinguish between development and production environment (ref: https://vercel.com/docs/environment-variables#system-environment-variables)
+ BUNDLE_ANALYZER: process.env.ANALYZE === 'true' || true, // 编译时是否展示内容
VERSION: process.env.NEXT_PUBLIC_VERSION // 版本号
}
diff --git a/components/AOSAnimation.js b/components/AOSAnimation.js
new file mode 100644
index 00000000..c5dd4d92
--- /dev/null
+++ b/components/AOSAnimation.js
@@ -0,0 +1,12 @@
+import AOS from 'aos'
+import { isBrowser } from 'react-notion-x'
+
+/**
+ * 加载滚动动画
+ * https://michalsnik.github.io/aos/
+ */
+export default function AOSAnimation() {
+ if (isBrowser) {
+ AOS.init()
+ }
+}
diff --git a/components/Equation.js b/components/Equation.js
index 4872ad87..86685d62 100644
--- a/components/Equation.js
+++ b/components/Equation.js
@@ -8,8 +8,12 @@ const katexSettings = {
strict: false
}
+/**
+ * 数学公式
+ * @param {} param0
+ * @returns
+ */
export const Equation = ({ block, math, inline = false, className, ...rest }) => {
-// const { recordMap } = useNotionContext()
math = math || getBlockTitle(block, null)
if (!math) return null
diff --git a/components/ExternalPlugins.js b/components/ExternalPlugins.js
index 813025c0..5dd00db3 100644
--- a/components/ExternalPlugins.js
+++ b/components/ExternalPlugins.js
@@ -22,6 +22,8 @@ const VConsole = dynamic(() => import('@/components/VConsole'), { ssr: false })
const CustomContextMenu = dynamic(() => import('@/components/CustomContextMenu'), { ssr: false })
const DisableCopy = dynamic(() => import('@/components/DisableCopy'), { ssr: false })
const AdBlockDetect = dynamic(() => import('@/components/AdBlockDetect'), { ssr: false })
+const LoadingProgress = dynamic(() => import('@/components/LoadingProgress'), { ssr: false })
+const AosAnimation = dynamic(() => import('@/components/AosAnimation'), { ssr: false })
/**
* 各种插件脚本
@@ -91,6 +93,8 @@ const ExternalPlugin = (props) => {
{WEB_WHIZ_ENABLED && }
{AD_WWADS_BLOCK_DETECT && }
+
+
{CHATBASE_ID && (<>
diff --git a/components/KatexReact.js b/components/KatexReact.js
index 5a585e13..9adc8870 100644
--- a/components/KatexReact.js
+++ b/components/KatexReact.js
@@ -1,6 +1,11 @@
import KaTeX from 'katex'
-import React from 'react'
+import { memo, useEffect, useState } from 'react'
+/**
+ * 数学公式
+ * @param {*} param0
+ * @returns
+ */
const TeX = ({
children,
math,
@@ -13,9 +18,9 @@ const TeX = ({
}) => {
const Component = asComponent || (block ? 'div' : 'span')
const content = (children ?? math)
- const [state, setState] = React.useState({ innerHtml: '' })
+ const [state, setState] = useState({ innerHtml: '' })
- React.useEffect(() => {
+ useEffect(() => {
try {
const innerHtml = KaTeX.renderToString(content, {
displayMode: true,
@@ -50,4 +55,4 @@ const TeX = ({
)
}
-export default React.memo(TeX)
+export default memo(TeX)
diff --git a/components/Live2D.js b/components/Live2D.js
index c232ddbb..4dbbe31a 100644
--- a/components/Live2D.js
+++ b/components/Live2D.js
@@ -4,6 +4,10 @@ import { useGlobal } from '@/lib/global'
import { loadExternalResource } from '@/lib/utils'
import { useEffect } from 'react'
+/**
+ * 网页动画
+ * @returns
+ */
export default function Live2D() {
const { theme, switchTheme } = useGlobal()
const showPet = JSON.parse(siteConfig('WIDGET_PET'))
diff --git a/components/LoadingProgress.js b/components/LoadingProgress.js
new file mode 100644
index 00000000..d7f7b5f7
--- /dev/null
+++ b/components/LoadingProgress.js
@@ -0,0 +1,29 @@
+import { useRouter } from 'next/router'
+import NProgress from 'nprogress'
+import { useEffect } from 'react'
+
+/**
+ * 出现页面加载进度条
+ */
+export default function LoadingProgress() {
+ const router = useRouter()
+ // 加载进度条
+ useEffect(() => {
+ const handleStart = (url) => {
+ NProgress.start()
+ }
+
+ const handleStop = () => {
+ NProgress.done()
+ }
+
+ router.events.on('routeChangeStart', handleStart)
+ router.events.on('routeChangeError', handleStop)
+ router.events.on('routeChangeComplete', handleStop)
+ return () => {
+ router.events.off('routeChangeStart', handleStart)
+ router.events.off('routeChangeComplete', handleStop)
+ router.events.off('routeChangeError', handleStop)
+ }
+ }, [router])
+}
diff --git a/components/NotionPage.js b/components/NotionPage.js
index e6e82046..a2586295 100644
--- a/components/NotionPage.js
+++ b/components/NotionPage.js
@@ -1,20 +1,25 @@
-import { NotionRenderer } from 'react-notion-x'
import dynamic from 'next/dynamic'
import mediumZoom from '@fisch0920/medium-zoom'
-import React, { useEffect, useRef } from 'react'
-// import { Code } from 'react-notion-x/build/third-party/code'
-import TweetEmbed from 'react-tweet-embed'
+import { useEffect, useRef } from 'react'
import 'katex/dist/katex.min.css'
import { mapImgUrl } from '@/lib/notion/mapImage'
import { isBrowser } from '@/lib/utils'
import { siteConfig } from '@/lib/config'
+// Notion渲染
+const NotionRenderer = dynamic(() => import('react-notion-x').then(async (m) => {
+ return m.NotionRenderer
+}), {
+ ssr: false
+})
+
const Code = dynamic(() =>
import('react-notion-x/build/third-party/code').then(async (m) => {
return m.Code
}), { ssr: false }
)
+// 公式
const Equation = dynamic(() =>
import('@/components/Equation').then(async (m) => {
// 化学方程式
@@ -36,6 +41,13 @@ const PrismMac = dynamic(() => import('@/components/PrismMac'), {
ssr: false
})
+/**
+ * tweet嵌入
+ */
+const TweetEmbed = dynamic(() => import('react-tweet-embed'), {
+ ssr: false
+})
+
const Collection = dynamic(() =>
import('react-notion-x/build/third-party/collection').then((m) => m.Collection), { ssr: true }
)
diff --git a/components/ShareBar.js b/components/ShareBar.js
index c228bb8b..334a5f12 100644
--- a/components/ShareBar.js
+++ b/components/ShareBar.js
@@ -1,29 +1,21 @@
import { siteConfig } from '@/lib/config'
-import { useRouter } from 'next/router'
-import React from 'react'
-import ShareButtons from './ShareButtons'
+import dynamic from 'next/dynamic'
+const ShareButtons = dynamic(() => import('@/components/ShareButtons'), { ssr: false })
+
+/**
+ * 分享栏
+ * @param {} param0
+ * @returns
+ */
const ShareBar = ({ post }) => {
- const router = useRouter()
- const title = siteConfig('TITLE')
-
if (!JSON.parse(siteConfig('POST_SHARE_BAR_ENABLE')) || !post || post?.type !== 'Post') {
return <>>
}
- const shareUrl = siteConfig('LINK') + router.asPath
-
return
}
diff --git a/components/ShareButtons.js b/components/ShareButtons.js
index e016bd6b..e3714b79 100644
--- a/components/ShareButtons.js
+++ b/components/ShareButtons.js
@@ -2,6 +2,7 @@ import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import copy from 'copy-to-clipboard'
import dynamic from 'next/dynamic'
+import { useRouter } from 'next/router'
import { useState } from 'react'
import {
@@ -56,7 +57,13 @@ const QrCode = dynamic(() => import('@/components/QrCode'), { ssr: false })
* @param {*} param0
* @returns
*/
-const ShareButtons = ({ shareUrl, title, body, image }) => {
+const ShareButtons = ({ post }) => {
+ const router = useRouter()
+ const shareUrl = siteConfig('LINK') + router.asPath
+ const title = post.title || siteConfig('TITLE')
+ const image = post.pageCover
+ const body = post?.title + ' | ' + title + ' ' + shareUrl + ' ' + post?.summary
+
const services = siteConfig('POSTS_SHARE_SERVICES').split(',')
const titleWithSiteInfo = title + ' | ' + siteConfig('TITLE')
const { locale } = useGlobal()
diff --git a/lib/global.js b/lib/global.js
index df119ac3..28b79be3 100644
--- a/lib/global.js
+++ b/lib/global.js
@@ -2,10 +2,7 @@ import { generateLocaleDict, initLocale } from './lang'
import { createContext, useContext, useEffect, useState } from 'react'
import { useRouter } from 'next/router'
import { THEMES, initDarkMode, saveDarkModeToCookies } from '@/themes/theme'
-
-import BLOG from '@/blog.config'
-import NProgress from 'nprogress'
-
+import { APPEARANCE, LANG, THEME } from 'blog.config'
const GlobalContext = createContext()
/**
@@ -17,10 +14,10 @@ const GlobalContext = createContext()
export function GlobalContextProvider(props) {
const { children, siteInfo, categoryOptions, tagOptions, NOTION_CONFIG } = props
const router = useRouter()
- const [lang, updateLang] = useState(NOTION_CONFIG?.LANG || BLOG.LANG) // 默认语言
- const [locale, updateLocale] = useState(generateLocaleDict(NOTION_CONFIG?.LANG || BLOG.LANG)) // 默认语言
- const [theme, setTheme] = useState(NOTION_CONFIG?.THEME || BLOG.THEME) // 默认博客主题
- const [isDarkMode, updateDarkMode] = useState(NOTION_CONFIG?.APPEARANCE || BLOG.APPEARANCE === 'dark') // 默认深色模式
+ const [lang, updateLang] = useState(NOTION_CONFIG?.LANG || LANG) // 默认语言
+ const [locale, updateLocale] = useState(generateLocaleDict(NOTION_CONFIG?.LANG || LANG)) // 默认语言
+ const [theme, setTheme] = useState(NOTION_CONFIG?.THEME || THEME) // 默认博客主题
+ const [isDarkMode, updateDarkMode] = useState(NOTION_CONFIG?.APPEARANCE || APPEARANCE === 'dark') // 默认深色模式
const [onLoading, setOnLoading] = useState(false) // 抓取文章数据
// 切换主题
@@ -62,7 +59,6 @@ export function GlobalContextProvider(props) {
// 加载进度条
useEffect(() => {
const handleStart = (url) => {
- NProgress.start()
const { theme } = router.query
if (theme && !url.includes(`theme=${theme}`)) {
const newUrl = `${url}${url.includes('?') ? '&' : '?'}theme=${theme}`
@@ -71,7 +67,6 @@ export function GlobalContextProvider(props) {
setOnLoading(true)
}
const handleStop = () => {
- NProgress.done()
setOnLoading(false)
}
diff --git a/next.config.js b/next.config.js
index aff79920..6266fb48 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,10 +1,11 @@
-const withBundleAnalyzer = require('@next/bundle-analyzer')({
- enabled: process.env.ANALYZE === 'true'
-})
-
const { THEME } = require('./blog.config')
const fs = require('fs')
const path = require('path')
+const BLOG = require('./blog.config')
+
+const withBundleAnalyzer = require('@next/bundle-analyzer')({
+ enabled: BLOG.BUNDLE_ANALYZER
+})
/**
* 扫描指定目录下的文件夹名,用于获取当前有几个主题
diff --git a/pages/_app.js b/pages/_app.js
index a19933cb..711f10f6 100644
--- a/pages/_app.js
+++ b/pages/_app.js
@@ -6,41 +6,38 @@ import '@/styles/utility-patterns.css'
// core styles shared by all of react-notion-x (required)
import 'react-notion-x/src/styles.css'
import '@/styles/notion.css' // 重写部分样式
+import 'aos/dist/aos.css' // You can also use for styles
import { GlobalContextProvider } from '@/lib/global'
-
-import AOS from 'aos'
-import 'aos/dist/aos.css' // You can also use for styles
import { isBrowser, loadExternalResource } from '@/lib/utils'
-import BLOG from '@/blog.config'
-// 各种扩展插件 动画等
+
+// 各种扩展插件 这个要阻塞引入
import ExternalPlugins from '@/components/ExternalPlugins'
-// const ExternalPlugins = dynamic(() => import('@/components/ExternalPlugins'))
+import { CUSTOM_EXTERNAL_CSS, CUSTOM_EXTERNAL_JS, IMG_SHADOW } from '@/blog.config'
const MyApp = ({ Component, pageProps }) => {
// 自定义样式css和js引入
if (isBrowser) {
// 初始化AOS动画
- AOS.init()
// 静态导入本地自定义样式
loadExternalResource('/css/custom.css', 'css')
loadExternalResource('/js/custom.js', 'js')
// 自动添加图片阴影
- if (BLOG.IMG_SHADOW) {
+ if (IMG_SHADOW) {
loadExternalResource('/css/img-shadow.css', 'css')
}
// 导入外部自定义脚本
- if (BLOG.CUSTOM_EXTERNAL_JS && BLOG.CUSTOM_EXTERNAL_JS.length > 0) {
- for (const url of BLOG.CUSTOM_EXTERNAL_JS) {
+ if (CUSTOM_EXTERNAL_JS && CUSTOM_EXTERNAL_JS.length > 0) {
+ for (const url of CUSTOM_EXTERNAL_JS) {
loadExternalResource(url, 'js')
}
}
// 导入外部自定义样式
- if (BLOG.CUSTOM_EXTERNAL_CSS && BLOG.CUSTOM_EXTERNAL_CSS.length > 0) {
- for (const url of BLOG.CUSTOM_EXTERNAL_CSS) {
+ if (CUSTOM_EXTERNAL_CSS && CUSTOM_EXTERNAL_CSS.length > 0) {
+ for (const url of CUSTOM_EXTERNAL_CSS) {
loadExternalResource(url, 'css')
}
}
diff --git a/themes/simple/components/ArticleInfo.js b/themes/simple/components/ArticleInfo.js
index f4f1b63a..f4d3f7fc 100644
--- a/themes/simple/components/ArticleInfo.js
+++ b/themes/simple/components/ArticleInfo.js
@@ -4,7 +4,12 @@ import CONFIG from '../config'
import { siteConfig } from '@/lib/config'
import { formatDateFmt } from '@/lib/formatDate'
-export const ArticleInfo = (props) => {
+/**
+ * 文章描述
+ * @param {*} props
+ * @returns
+ */
+export default function ArticleInfo (props) {
const { post } = props
const { locale } = useGlobal()
diff --git a/themes/simple/components/ArticleLock.js b/themes/simple/components/ArticleLock.js
index 4957946d..eb1d10ef 100644
--- a/themes/simple/components/ArticleLock.js
+++ b/themes/simple/components/ArticleLock.js
@@ -8,7 +8,7 @@ import { useEffect, useRef } from 'react'
* @param validPassword(bool) 回调函数,校验正确回调入参为true
* @returns
*/
-export const ArticleLock = props => {
+export default function ArticleLock (props) {
const { validPassword } = props
const { locale } = useGlobal()
diff --git a/themes/simple/components/BlogListPage.js b/themes/simple/components/BlogListPage.js
index 877d0473..b0e6720c 100644
--- a/themes/simple/components/BlogListPage.js
+++ b/themes/simple/components/BlogListPage.js
@@ -6,7 +6,12 @@ import { AdSlot } from '@/components/GoogleAdsense'
import { siteConfig } from '@/lib/config'
import CONFIG from '../config'
-export const BlogListPage = props => {
+/**
+ * 博客列表
+ * @param {*} props
+ * @returns
+ */
+export default function BlogListPage(props) {
const { page = 1, posts, postCount } = props
const router = useRouter()
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
diff --git a/themes/simple/components/BlogListScroll.js b/themes/simple/components/BlogListScroll.js
index 8ae37cc8..d68745f3 100644
--- a/themes/simple/components/BlogListScroll.js
+++ b/themes/simple/components/BlogListScroll.js
@@ -4,7 +4,12 @@ import throttle from 'lodash.throttle'
import { BlogItem } from './BlogItem'
import { siteConfig } from '@/lib/config'
-export const BlogListScroll = props => {
+/**
+ * 滚动博客列表
+ * @param {*} props
+ * @returns
+ */
+export default function BlogListScroll (props) {
const { posts } = props
const { locale } = useGlobal()
diff --git a/themes/simple/components/Footer.js b/themes/simple/components/Footer.js
index d902f341..4e3c8c45 100644
--- a/themes/simple/components/Footer.js
+++ b/themes/simple/components/Footer.js
@@ -1,7 +1,12 @@
import DarkModeButton from '@/components/DarkModeButton'
import { siteConfig } from '@/lib/config'
-export const Footer = (props) => {
+/**
+ * 页脚
+ * @param {*} props
+ * @returns
+ */
+export default function Footer (props) {
const d = new Date()
const currentYear = d.getFullYear()
const since = siteConfig('SINCE')
diff --git a/themes/simple/components/Header.js b/themes/simple/components/Header.js
index 59715c19..a33f001b 100644
--- a/themes/simple/components/Header.js
+++ b/themes/simple/components/Header.js
@@ -9,7 +9,7 @@ import { compressImage } from '@/lib/notion/mapImage'
* 网站顶部
* @returns
*/
-export const Header = (props) => {
+export default function Header (props) {
const { siteInfo } = props
const avatar = compressImage(siteInfo?.icon || siteConfig('AVATAR'), 200)
diff --git a/themes/simple/components/NavBar.js b/themes/simple/components/NavBar.js
index 08506396..db3033ca 100644
--- a/themes/simple/components/NavBar.js
+++ b/themes/simple/components/NavBar.js
@@ -7,7 +7,7 @@ import { MenuList } from './MenuList'
* @param {*} props
* @returns
*/
-export const NavBar = (props) => {
+export default function NavBar (props) {
const [showSearchInput, changeShowSearchInput] = useState(false)
const router = useRouter()
diff --git a/themes/simple/components/SideBar.js b/themes/simple/components/SideBar.js
index 44c4bd0b..6ff2075c 100644
--- a/themes/simple/components/SideBar.js
+++ b/themes/simple/components/SideBar.js
@@ -3,7 +3,12 @@ import Live2D from '@/components/Live2D'
import Announcement from './Announcement'
import Catalog from './Catalog'
-export const SideBar = (props) => {
+/**
+ * 侧边栏
+ * @param {*} props
+ * @returns
+ */
+export default function SideBar (props) {
const { notice } = props
return (<>
diff --git a/themes/simple/components/TopBar.js b/themes/simple/components/TopBar.js
index 843eaeda..e9224de8 100644
--- a/themes/simple/components/TopBar.js
+++ b/themes/simple/components/TopBar.js
@@ -5,7 +5,7 @@ import { siteConfig } from '@/lib/config'
* 网站顶部 提示栏
* @returns
*/
-export const TopBar = (props) => {
+export default function TopBar (props) {
const content = siteConfig('SIMPLE_TOP_BAR_CONTENT', null, CONFIG)
if (content) {
diff --git a/themes/simple/index.js b/themes/simple/index.js
index 0324992a..46c3174a 100644
--- a/themes/simple/index.js
+++ b/themes/simple/index.js
@@ -1,31 +1,34 @@
import CONFIG from './config'
-import { BlogListPage } from './components/BlogListPage'
-import { BlogListScroll } from './components/BlogListScroll'
import { useEffect } from 'react'
import { isBrowser } 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 { TopBar } from './components/TopBar'
-import { Header } from './components/Header'
-import { NavBar } from './components/NavBar'
-import { siteConfig } from '@/lib/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'
+import { AdSlot } from '@/components/GoogleAdsense'
+import { siteConfig } from '@/lib/config'
import { Transition } from '@headlessui/react'
+import Link from 'next/link'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
-import CommonHead from '@/components/CommonHead'
-import WWAds from '@/components/WWAds'
+import dynamic from 'next/dynamic'
+
+// 主题组件
+const BlogListScroll = dynamic(() => import('./components/BlogListScroll'), { ssr: false });
+const BlogArchiveItem = dynamic(() => import('./components/BlogArchiveItem'), { ssr: false });
+const ArticleLock = dynamic(() => import('./components/ArticleLock'), { ssr: false });
+const NotionPage = dynamic(() => import('@/components/NotionPage'), { ssr: false });
+const ArticleInfo = dynamic(() => import('./components/ArticleInfo'), { ssr: false });
+const Comment = dynamic(() => import('@/components/Comment'), { ssr: false });
+const ArticleAround = dynamic(() => import('./components/ArticleAround'), { ssr: false });
+const ShareBar = dynamic(() => import('@/components/ShareBar'), { ssr: false });
+const TopBar = dynamic(() => import('./components/TopBar'), { ssr: false });
+const Header = dynamic(() => import('./components/Header'), { ssr: false });
+const NavBar = dynamic(() => import('./components/NavBar'), { ssr: false });
+const SideBar = dynamic(() => import('./components/SideBar'), { ssr: false });
+const JumpToTopButton = dynamic(() => import('./components/JumpToTopButton'), { ssr: false });
+const Footer = dynamic(() => import('./components/Footer'), { ssr: false });
+const SearchInput = dynamic(() => import('./components/SearchInput'), { ssr: false });
+const CommonHead = dynamic(() => import('@/components/CommonHead'), { ssr: false });
+const WWAds = dynamic(() => import('@/components/WWAds'), { ssr: false });
+const BlogListPage = dynamic(() => import('./components/BlogListPage'), { ssr: false })
/**
* 基础布局