diff --git a/.env.local b/.env.local index 90456af7..11f8351f 100644 --- a/.env.local +++ b/.env.local @@ -1,2 +1,2 @@ # 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables -NEXT_PUBLIC_VERSION=3.14.0 \ No newline at end of file +NEXT_PUBLIC_VERSION=3.15.0 \ No newline at end of file diff --git a/blog.config.js b/blog.config.js index 2178eaa2..300f3ff6 100644 --- a/blog.config.js +++ b/blog.config.js @@ -12,6 +12,9 @@ const BLOG = { APPEARANCE: process.env.NEXT_PUBLIC_APPEARANCE || 'light', // ['light', 'dark', 'auto'], // light 日间模式 , dark夜间模式, auto根据时间和主题自动夜间模式 APPEARANCE_DARK_TIME: process.env.NEXT_PUBLIC_APPEARANCE_DARK_TIME || [18, 6], // 夜间模式起至时间,false时关闭根据时间自动切换夜间模式 + // 3.14.1版本后,欢迎语在此配置,英文逗号隔开 , 即可支持多个欢迎语打字效果。 + GREETING_WORDS: process.env.NEXT_PUBLIC_GREETING_WORDS || 'Hi,我是一个程序员, Hi,我是一个打工人,Hi,我是一个干饭人,欢迎来到我的博客🎉', + CUSTOM_MENU: process.env.NEXT_PUBLIC_CUSTOM_MENU || false, // 支持Menu 类型,从3.12.0版本起,各主题将逐步支持灵活的二级菜单配置,替代了原来的Page类型,此配置是试验功能、默认关闭。 AUTHOR: process.env.NEXT_PUBLIC_AUTHOR || 'NotionNext', // 您的昵称 例如 tangly1024 @@ -95,6 +98,9 @@ const BLOG = { CODE_MAC_BAR: true, // 代码左上角显示mac的红黄绿图标 CODE_LINE_NUMBERS: process.env.NEXT_PUBLIC_CODE_LINE_NUMBERS || 'false', // 是否显示行号 + // Mermaid 图表CDN + MERMAID_CDN: process.env.NEXT_PUBLIC_MERMAID_CDN || 'https://cdn.jsdelivr.net/npm/mermaid@10.2.2/dist/mermaid.min.js', // CDN + BACKGROUND_LIGHT: '#eeeeee', // use hex value, don't forget '#' e.g #fffefc BACKGROUND_DARK: '#000000', // use hex value, don't forget '#' SUB_PATH: '', // leave this empty unless you want to deploy in a folder @@ -231,11 +237,14 @@ const BLOG = { COMMENT_GITALK_CLIENT_SECRET: process.env.NEXT_PUBLIC_COMMENT_GITALK_CLIENT_SECRET || '', // e.g 40位ID, 在gitalk后台获取 COMMENT_GITALK_DISTRACTION_FREE_MODE: false, // 类似facebook的无干扰模式 + COMMENT_GITALK_JS_CDN_URL: process.env.NEXT_PUBLIC_COMMENT_GITALK_JS_CDN_URL || 'https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js', // gitalk客户端 js cdn + COMMENT_GITALK_CSS_CDN_URL: process.env.NEXT_PUBLIC_COMMENT_GITALK_CSS_CDN_URL || 'https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css', // gitalk客户端 css cdn COMMENT_GITTER_ROOM: process.env.NEXT_PUBLIC_COMMENT_GITTER_ROOM || '', // gitter聊天室 see https://gitter.im/ 不需要则留空 COMMENT_DAO_VOICE_ID: process.env.NEXT_PUBLIC_COMMENT_DAO_VOICE_ID || '', // DaoVoice http://dashboard.daovoice.io/get-started COMMENT_TIDIO_ID: process.env.NEXT_PUBLIC_COMMENT_TIDIO_ID || '', // [tidio_id] -> //code.tidio.co/[tidio_id].js + COMMENT_VALINE_CDN: process.env.NEXT_PUBLIC_VALINE_CDN || 'https://unpkg.com/valine@1.5.1/dist/Valine.min.js', COMMENT_VALINE_APP_ID: process.env.NEXT_PUBLIC_VALINE_ID || '', // Valine @see https://valine.js.org/quickstart.html 或 https://github.com/stonehank/react-valine#%E8%8E%B7%E5%8F%96app-id-%E5%92%8C-app-key COMMENT_VALINE_APP_KEY: process.env.NEXT_PUBLIC_VALINE_KEY || '', COMMENT_VALINE_SERVER_URLS: process.env.NEXT_PUBLIC_VALINE_SERVER_URLS || '', // 该配置适用于国内自定义域名用户, 海外版本会自动检测(无需手动填写) @see https://valine.js.org/configuration.html#serverURLs @@ -314,7 +323,7 @@ const BLOG = { // 作废配置 AVATAR: process.env.NEXT_PUBLIC_AVATAR || '/avatar.svg', // 作者头像,被notion中的ICON覆盖。若无ICON则取public目录下的avatar.png - TITLE: process.env.NEXT_PUBLIC_TITLE || 'NotionNext BLOG', // 站点标题 ,被notion中的页面标题覆盖 + TITLE: process.env.NEXT_PUBLIC_TITLE || 'NotionNext BLOG', // 站点标题 ,被notion中的页面标题覆盖;此处请勿留空白,否则服务器无法编译 HOME_BANNER_IMAGE: process.env.NEXT_PUBLIC_HOME_BANNER_IMAGE || './bg_image.jpg', // 首页背景大图, 会被notion中的封面图覆盖,若无封面图则会使用代码中的 /public/bg_image.jpg 文件 DESCRIPTION: diff --git a/components/DebugPanel.js b/components/DebugPanel.js index 55c4a465..7765e827 100644 --- a/components/DebugPanel.js +++ b/components/DebugPanel.js @@ -1,18 +1,18 @@ import BLOG from '@/blog.config' -import * as ThemeMap from '@/themes' import { useEffect, useState } from 'react' import Select from './Select' -import { ALL_THEME } from '@/themes' import { useGlobal } from '@/lib/global' +import { ALL_THEME } from '@/lib/theme' + /** * * @returns 调试面板 */ -export function DebugPanel() { +const DebugPanel = () => { const [show, setShow] = useState(false) - const { theme, changeTheme, switchTheme, locale } = useGlobal() + const { changeTheme, switchTheme, locale } = useGlobal() const [siteConfig, updateSiteConfig] = useState({}) - const [themeConfig, updateThemeConfig] = useState({}) + // const [themeConfig, updateThemeConfig] = useState({}) const [debugTheme, updateDebugTheme] = useState(BLOG.THEME) // 主题下拉框 @@ -21,7 +21,7 @@ export function DebugPanel() { useEffect(() => { changeTheme(BLOG.THEME) updateSiteConfig(Object.assign({}, BLOG)) - updateThemeConfig(Object.assign({}, ThemeMap[BLOG.THEME].THEME_CONFIG)) + // updateThemeConfig(Object.assign({}, ThemeMap[BLOG.THEME].THEME_CONFIG)) }, []) function toggleShow() { @@ -30,13 +30,13 @@ export function DebugPanel() { function handleChangeDebugTheme() { const newTheme = switchTheme() - updateThemeConfig(Object.assign({}, ThemeMap[newTheme].THEME_CONFIG)) + // updateThemeConfig(Object.assign({}, ThemeMap[newTheme].THEME_CONFIG)) updateDebugTheme(newTheme) } function handleUpdateDebugTheme(e) { changeTheme(e) - updateThemeConfig(Object.assign({}, ThemeMap[theme].THEME_CONFIG)) + // updateThemeConfig(Object.assign({}, ThemeMap[theme].THEME_CONFIG)) updateDebugTheme(e) } @@ -90,7 +90,7 @@ export function DebugPanel() {
-
+ {/*
主题配置{`config_${debugTheme}.js`}:
@@ -106,7 +106,7 @@ export function DebugPanel() {
))}
-
+ */}
站点配置[blog.config.js]
@@ -128,3 +128,4 @@ export function DebugPanel() { ) } +export default DebugPanel diff --git a/components/ExternalPlugins.js b/components/ExternalPlugins.js new file mode 100644 index 00000000..235472d8 --- /dev/null +++ b/components/ExternalPlugins.js @@ -0,0 +1,58 @@ +import BLOG from 'blog.config' +import dynamic from 'next/dynamic' + +// import TwikooCommentCounter from '@/components/TwikooCommentCounter' +// import { DebugPanel } from '@/components/DebugPanel' +// import { ThemeSwitch } from '@/components/ThemeSwitch' +// import { Fireworks } from '@/components/Fireworks' +// import { Nest } from '@/components/Nest' +// import { FlutteringRibbon } from '@/components/FlutteringRibbon' +// import { Ribbon } from '@/components/Ribbon' +// import { Sakura } from '@/components/Sakura' +// import { StarrySky } from '@/components/StarrySky' +// import { Analytics } from '@vercel/analytics/react' + +const TwikooCommentCounter = dynamic(() => import('@/components/TwikooCommentCounter'), { ssr: false }) +const DebugPanel = dynamic(() => import('@/components/DebugPanel'), { ssr: false }) +const ThemeSwitch = dynamic(() => import('@/components/ThemeSwitch'), { ssr: false }) +const Fireworks = dynamic(() => import('@/components/Fireworks'), { ssr: false }) +const Nest = dynamic(() => import('@/components/Nest'), { ssr: false }) +const FlutteringRibbon = dynamic(() => import('@/components/FlutteringRibbon'), { ssr: false }) +const Ribbon = dynamic(() => import('@/components/Ribbon'), { ssr: false }) +const Sakura = dynamic(() => import('@/components/Sakura'), { ssr: false }) +const StarrySky = dynamic(() => import('@/components/StarrySky'), { ssr: false }) +const Analytics = dynamic(() => import('@vercel/analytics/react').then(async (m) => { return m.Analytics }), { ssr: false }) +const MusicPlayer = dynamic(() => import('@/components/Player'), { ssr: false }) +const Ackee = dynamic(() => import('@/components/Ackee'), { ssr: false }) +const Gtag = dynamic(() => import('@/components/Gtag'), { ssr: false }) +const Busuanzi = dynamic(() => import('@/components/Busuanzi'), { ssr: false }) +const GoogleAdsense = dynamic(() => import('@/components/GoogleAdsense'), { ssr: false }) +const Messenger = dynamic(() => import('@/components/FacebookMessenger'), { ssr: false }) + +/** + * 各种第三方组件 + * @param {*} props + * @returns + */ +const ExternalPlugin = (props) => { + return <> + {JSON.parse(BLOG.THEME_SWITCH) && } + {JSON.parse(BLOG.DEBUG) && } + {BLOG.ANALYTICS_ACKEE_TRACKER && } + {BLOG.ANALYTICS_GOOGLE_ID && } + {BLOG.ANALYTICS_VERCEL && } + {JSON.parse(BLOG.ANALYTICS_BUSUANZI_ENABLE) && } + {BLOG.ADSENSE_GOOGLE_ID && } + {BLOG.FACEBOOK_APP_ID && BLOG.FACEBOOK_PAGE_ID && } + {JSON.parse(BLOG.FIREWORKS) && } + {JSON.parse(BLOG.SAKURA) && } + {JSON.parse(BLOG.STARRY_SKY) && } + {JSON.parse(BLOG.MUSIC_PLAYER) && } + {JSON.parse(BLOG.NEST) && } + {JSON.parse(BLOG.FLUTTERINGRIBBON) && } + {JSON.parse(BLOG.COMMENT_TWIKOO_COUNT_ENABLE) && } + {JSON.parse(BLOG.RIBBON) && } + +} + +export default ExternalPlugin diff --git a/components/Fireworks.js b/components/Fireworks.js index 8235baa7..d6b9a650 100644 --- a/components/Fireworks.js +++ b/components/Fireworks.js @@ -2,16 +2,17 @@ * https://codepen.io/juliangarnier/pen/gmOwJX * custom by hexo-theme-yun @YunYouJun */ -import React from 'react' +import { useEffect } from 'react' import anime from 'animejs' import BLOG from 'blog.config' -export const Fireworks = () => { - React.useEffect(() => { +const Fireworks = () => { + useEffect(() => { createFireworks({}) }, []) return } +export default Fireworks /** * 创建烟花 diff --git a/components/FlutteringRibbon.js b/components/FlutteringRibbon.js index 301fbd23..eb0f03e0 100644 --- a/components/FlutteringRibbon.js +++ b/components/FlutteringRibbon.js @@ -1,5 +1,5 @@ /* eslint-disable */ -import React from 'react' +import { useEffect } from 'react' const id = 'canvasFlutteringRibbon' export const FlutteringRibbon = () => { const destroyRibbon = ()=>{ @@ -9,15 +9,17 @@ export const FlutteringRibbon = () => { } } - React.useEffect(() => { + useEffect(() => { createFlutteringRibbon() return () => destroyRibbon() }, []) return <> - } +export default FlutteringRibbon + + /** * 创建连接点 * @param config diff --git a/components/Gitalk.js b/components/Gitalk.js index 66b30174..166eb8c7 100644 --- a/components/Gitalk.js +++ b/components/Gitalk.js @@ -1,18 +1,44 @@ -import 'gitalk/dist/gitalk.css' +// import 'gitalk/dist/gitalk.css' import BLOG from '@/blog.config' -import GitalkComponent from 'gitalk/dist/gitalk-component' +import { loadExternalResource } from '@/lib/utils' +import { useEffect } from 'react' +// import GitalkComponent from 'gitalk/dist/gitalk-component' const Gitalk = ({ frontMatter }) => { - return + // return + const loadGitalk = async() => { + const css = await loadExternalResource(BLOG.COMMENT_GITALK_CSS_CDN_URL, 'css') + const js = await loadExternalResource(BLOG.COMMENT_GITALK_JS_CDN_URL, 'js') + + console.log('gitalk 加载成功', css, js) + const Gitalk = window.Gitalk + + const gitalk = new Gitalk({ + clientID: BLOG.COMMENT_GITALK_CLIENT_ID, + clientSecret: BLOG.COMMENT_GITALK_CLIENT_SECRET, + repo: BLOG.COMMENT_GITALK_REPO, + owner: BLOG.COMMENT_GITALK_OWNER, + admin: BLOG.COMMENT_GITALK_ADMIN.split(','), + id: frontMatter.id, // Ensure uniqueness and length less than 50 + distractionFreeMode: JSON.parse(BLOG.COMMENT_GITALK_DISTRACTION_FREE_MODE) // Facebook-like distraction free mode + }) + + gitalk.render('gitalk-container') + } + useEffect(() => { + loadGitalk() + }, []) + + return
} export default Gitalk diff --git a/components/Live2D.js b/components/Live2D.js index ba4b9065..2fc6327f 100644 --- a/components/Live2D.js +++ b/components/Live2D.js @@ -6,17 +6,20 @@ import { useEffect } from 'react' export default function Live2D() { const { theme, switchTheme } = useGlobal() + const showPet = JSON.parse(BLOG.WIDGET_PET) useEffect(() => { - if (BLOG.WIDGET_PET) { - // setLive2DLoaded(true) - // console.log('加载宠物挂件') + if (showPet) { Promise.all([ loadExternalResource('https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/live2d.min.js', 'js') ]).then((e) => { - if (window?.loadlive2d) { + if (typeof window?.loadlive2d !== 'undefined') { // https://github.com/xiazeyu/live2d-widget-models - loadlive2d('live2d', BLOG.WIDGET_PET_LINK) + try { + loadlive2d('live2d', BLOG.WIDGET_PET_LINK) + } catch (error) { + console.error('读取PET模型', error) + } } }) } @@ -28,7 +31,7 @@ export default function Live2D() { } } - if (!BLOG.WIDGET_PET || !JSON.parse(BLOG.WIDGET_PET)) { + if (!showPet) { return <> } diff --git a/components/Loading.js b/components/Loading.js new file mode 100644 index 00000000..1cf295cd --- /dev/null +++ b/components/Loading.js @@ -0,0 +1,25 @@ + +/** + * 主题文件被加载出之前的占位符 + * @returns + */ +const Loading = (props) => { +// const { theme, setOnReading } = useGlobal() + // console.log('开启遮罩') + // setOnReading(true) + + // useEffect(() => { + // // 返回一个函数,在组件销毁时设置 onReading 为 false + // return () => { + // setTimeout(() => { + // console.log('关闭遮罩') + // setOnReading(false) + // }, 500) + // } + // }) + + return
+ +
+} +export default Loading diff --git a/components/LoadingCover.js b/components/LoadingCover.js new file mode 100644 index 00000000..c9ec6752 --- /dev/null +++ b/components/LoadingCover.js @@ -0,0 +1,13 @@ + +/** + * 加载文件时的全局遮罩 + * @returns + */ +const LoadingCover = (props) => { + const { onReading } = props + + return
+ +
+} +export default LoadingCover diff --git a/components/MusicPlayer.js b/components/MusicPlayer.js deleted file mode 100644 index 7e788639..00000000 --- a/components/MusicPlayer.js +++ /dev/null @@ -1,7 +0,0 @@ -import dynamic from 'next/dynamic' - -const MusicPlayer = dynamic( - () => import('@/components/Player'), - { ssr: false } -) -export default MusicPlayer diff --git a/components/Nest.js b/components/Nest.js index 74fa85e3..47453ad2 100644 --- a/components/Nest.js +++ b/components/Nest.js @@ -1,7 +1,7 @@ /* eslint-disable */ import { useEffect } from 'react' const id = 'canvasNestCreated' -export const Nest = () => { +const Nest = () => { const destroyNest = ()=>{ const nest = document.getElementById(id) if(nest && nest.parentNode){ @@ -16,6 +16,8 @@ export const Nest = () => { return <> } +export default Nest + /** * 创建连接点 * @param config diff --git a/components/NotionPage.js b/components/NotionPage.js index c2466e03..63d57861 100644 --- a/components/NotionPage.js +++ b/components/NotionPage.js @@ -13,7 +13,7 @@ const Equation = dynamic(() => // 化学方程式 await import('@/lib/mhchem') return m.Equation - }) + }), { ssr: false } ) const Pdf = dynamic( () => import('react-notion-x/build/third-party/pdf').then((m) => m.Pdf), diff --git a/components/PrismMac.js b/components/PrismMac.js index 0350fa60..c8a93c49 100644 --- a/components/PrismMac.js +++ b/components/PrismMac.js @@ -25,7 +25,7 @@ const PrismMac = () => { } loadExternalResource(BLOG.PRISM_THEME_PATH, 'css') loadExternalResource(BLOG.PRISM_JS_AUTO_LOADER, 'js').then((url) => { - console.log('渲染公式图表') + // console.log('渲染公式图表') if (window?.Prism?.plugins?.autoloader) { window.Prism.plugins.autoloader.languages_path = BLOG.PRISM_JS_PATH } @@ -64,8 +64,11 @@ const renderMermaid = async() => { } } if (needLoad) { - const asyncMermaid = await import('mermaid') - asyncMermaid.default.contentLoaded() + // const asyncMermaid = await import('mermaid') + const url = await loadExternalResource(BLOG.MERMAID_CDN, 'js') + const mermaid = window.mermaid + console.log('mermaid加载成功', url, mermaid) + mermaid.contentLoaded() } } } diff --git a/components/Ribbon.js b/components/Ribbon.js index 2c6855fc..468cf443 100644 --- a/components/Ribbon.js +++ b/components/Ribbon.js @@ -2,7 +2,7 @@ import { useEffect } from 'react' const id = 'canvasRibbon' -export const Ribbon = () => { +const Ribbon = () => { const destroyRibbon = ()=>{ const ribbon = document.getElementById(id) if(ribbon && ribbon.parentNode){ @@ -17,6 +17,8 @@ export const Ribbon = () => { return <> } +export default Ribbon + /** * 创建连接点 * @param config diff --git a/components/Sakura.js b/components/Sakura.js index 7898b3cc..aed87cc0 100644 --- a/components/Sakura.js +++ b/components/Sakura.js @@ -1,7 +1,7 @@ /* eslint-disable */ import { useEffect } from 'react' const id = 'canvas_sakura' -export const Sakura = () => { +const Sakura = () => { const destroySakura = ()=>{ const sakura = document.getElementById(id) if(sakura && sakura.parentNode){ @@ -16,6 +16,8 @@ export const Sakura = () => { return <> } +export default Sakura + /** * 创建樱花雨 * @param config diff --git a/components/SideBarDrawer.js b/components/SideBarDrawer.js index 0db865cb..422f24ff 100644 --- a/components/SideBarDrawer.js +++ b/components/SideBarDrawer.js @@ -29,11 +29,11 @@ const SideBarDrawer = ({ children, isOpen, onOpen, onClose, className }) => { const sideBarDrawerBackground = window.document.getElementById('sidebar-drawer-background') if (showStatus) { - sideBarDrawer.classList.replace('-ml-60', 'ml-0') - sideBarDrawerBackground.classList.replace('hidden', 'block') + sideBarDrawer?.classList.replace('-ml-60', 'ml-0') + sideBarDrawerBackground?.classList.replace('hidden', 'block') } else { - sideBarDrawer.classList.replace('ml-0', '-ml-60') - sideBarDrawerBackground.classList.replace('block', 'hidden') + sideBarDrawer?.classList.replace('ml-0', '-ml-60') + sideBarDrawerBackground?.classList.replace('block', 'hidden') } } diff --git a/components/StarrySky.js b/components/StarrySky.js index 4cb5c8a5..5479df93 100644 --- a/components/StarrySky.js +++ b/components/StarrySky.js @@ -1,7 +1,7 @@ /* eslint-disable */ import React from 'react' -export const StarrySky = () => { +const StarrySky = () => { React.useEffect(() => { dark() }, []) @@ -12,6 +12,7 @@ export const StarrySky = () => { ) } +export default StarrySky /** * 创建星空雨 * @param config diff --git a/components/ThemeSwitch.js b/components/ThemeSwitch.js index 6265e035..d7143dc7 100644 --- a/components/ThemeSwitch.js +++ b/components/ThemeSwitch.js @@ -1,12 +1,12 @@ import { useGlobal } from '@/lib/global' -import { ALL_THEME } from '@/themes' import React from 'react' import { Draggable } from './Draggable' +import { ALL_THEME } from '@/lib/theme' /** * * @returns 主题切换 */ -export function ThemeSwitch() { +const ThemeSwitch = () => { const { theme, changeTheme } = useGlobal() const onSelectChange = (e) => { @@ -30,3 +30,5 @@ export function ThemeSwitch() { ) } + +export default ThemeSwitch diff --git a/components/TwikooCommentCounter.js b/components/TwikooCommentCounter.js index c847a176..b3b54ca3 100644 --- a/components/TwikooCommentCounter.js +++ b/components/TwikooCommentCounter.js @@ -24,7 +24,7 @@ const TwikooCommentCounter = (props) => { twikoo.getCommentsCount({ envId: BLOG.COMMENT_TWIKOO_ENV_ID, // 环境 ID // region: 'ap-guangzhou', // 环境地域,默认为 ap-shanghai,如果您的环境地域不是上海,需传此参数 - urls: posts.map(post => post.slug), // 不包含协议、域名、参数的文章路径列表,必传参数 + urls: posts?.map(post => post.slug), // 不包含协议、域名、参数的文章路径列表,必传参数 includeReply: true // 评论数是否包括回复,默认:false }).then(function (res) { // console.log('查询', res) @@ -62,7 +62,7 @@ const TwikooCommentCounter = (props) => { const router = useRouter() useEffect(() => { - console.log('路由触发评论计数') + // console.log('路由触发评论计数') if (props?.posts && props?.posts?.length > 0) { fetchTwikooData(props.posts) } @@ -70,7 +70,7 @@ const TwikooCommentCounter = (props) => { // 监控主题变化时的的评论数 useEffect(() => { - console.log('主题触发评论计数', commentsData) + // console.log('主题触发评论计数', commentsData) updateCommentCount() }, [theme]) return null diff --git a/components/Valine.js b/components/Valine.js deleted file mode 100644 index c1e915db..00000000 --- a/components/Valine.js +++ /dev/null @@ -1,3 +0,0 @@ -import { Valine } from 'react-valine' - -export default Valine diff --git a/components/ValineComponent.js b/components/ValineComponent.js index 6df63e7c..359cff6d 100644 --- a/components/ValineComponent.js +++ b/components/ValineComponent.js @@ -1,49 +1,61 @@ import BLOG from '@/blog.config' -import { useRouter } from 'next/router' -import React from 'react' -import Valine from 'valine' +import { loadExternalResource } from '@/lib/utils' +import { useEffect } from 'react' -const ValineComponent = (props) => { - const router = useRouter() - const initValine = (url) => { - const valine = new Valine({ - el: '#v-comments', - appId: BLOG.COMMENT_VALINE_APP_ID, - appKey: BLOG.COMMENT_VALINE_APP_KEY, - avatar: '', - path: url || router.asPath, - recordIP: true, - placeholder: BLOG.COMMENT_VALINE_PLACEHOLDER, - serverURLs: BLOG.COMMENT_VALINE_SERVER_URLS, - visitor: true - }) - if (!valine) { - console.error('valine错误') +const ValineComponent = ({ path }) => { + const loadValine = async () => { + try { + const url = await loadExternalResource(BLOG.COMMENT_VALINE_CDN, 'js') + console.log('valine 加载成功', url) + const Valine = window.Valine + // eslint-disable-next-line no-unused-vars + const valine = new Valine({ + el: '#valine', // 容器元素 + lang: BLOG.LANG, // 用于手动设定评论区语言,支持的语言列表 https://github.com/imaegoo/twikoo/blob/main/src/client/utils/i18n/index.js + appId: BLOG.COMMENT_VALINE_APP_ID, + appKey: BLOG.COMMENT_VALINE_APP_KEY, + avatar: '', + path, + recordIP: true, + placeholder: BLOG.COMMENT_VALINE_PLACEHOLDER, + serverURLs: BLOG.COMMENT_VALINE_SERVER_URLS, + visitor: true + }) + console.log('初始化valine成功') + } catch (error) { + console.error('twikoo 加载失败', error) } } - const updateValine = url => { - // 移除旧的评论区,否则会重复渲染。 - const wrapper = document.getElementById('v-wrapper') - const comments = document.getElementById('v-comments') - wrapper.removeChild(comments) - const newComments = document.createElement('div') - newComments.id = 'v-comments' - newComments.name = new Date() - wrapper.appendChild(newComments) - initValine(url) - } - - React.useEffect(() => { - initValine() - router.events.on('routeChangeComplete', updateValine) - return () => { - router.events.off('routeChangeComplete', updateValine) - } + useEffect(() => { + loadValine() }, []) - return
-
-
+ + return
+ + // const updateValine = url => { + // // 移除旧的评论区,否则会重复渲染。 + // const wrapper = document.getElementById('v-wrapper') + // const comments = document.getElementById('v-comments') + // wrapper.removeChild(comments) + // const newComments = document.createElement('div') + // newComments.id = 'v-comments' + // newComments.name = new Date() + // wrapper.appendChild(newComments) + // initValine(url) + // } + + // useEffect(() => { + // initValine() + // router.events.on('routeChangeComplete', updateValine) + // return () => { + // router.events.off('routeChangeComplete', updateValine) + // } + // }, []) + +// return
+//
+//
} export default ValineComponent diff --git a/jsconfig.json b/jsconfig.json index f6f71d10..395f9ce0 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -4,6 +4,7 @@ "paths": { "@/*": ["./*"], "@/components/*": ["components/*"], + "@/theme/*": ["theme/*"], "@/data/*": ["data/*"], "@/lib/*": ["lib/*"], "@/styles/*": ["styles/*"] diff --git a/lib/global.js b/lib/global.js index 6b6d86ce..f96d326a 100644 --- a/lib/global.js +++ b/lib/global.js @@ -2,9 +2,10 @@ import { generateLocaleDict, initLocale } from './lang' import { createContext, useContext, useEffect, useState } from 'react' import Router, { useRouter } from 'next/router' import BLOG from '@/blog.config' -import { initDarkMode, initTheme, saveThemeToCookies } from '@/lib/theme' -import { ALL_THEME } from '@/themes' +import { ALL_THEME, initDarkMode, initTheme, saveThemeToCookies } from '@/lib/theme' import NProgress from 'nprogress' +import LoadingCover from '@/components/LoadingCover' +import { isBrowser } from './utils' const GlobalContext = createContext() @@ -15,27 +16,40 @@ const GlobalContext = createContext() * @constructor */ export function GlobalContextProvider({ children }) { - const [lang, updateLang] = useState(BLOG.LANG) - const [locale, updateLocale] = useState(generateLocaleDict(BLOG.LANG)) - const [theme, setTheme] = useState(BLOG.THEME) - const [isDarkMode, updateDarkMode] = useState(BLOG.APPEARANCE === 'dark') - const [onLoading, changeLoadingState] = useState(false) + const [lang, updateLang] = useState(BLOG.LANG) // 默认语言 + const [locale, updateLocale] = useState(generateLocaleDict(BLOG.LANG)) // 默认语言 + const [theme, setTheme] = useState(BLOG.THEME) // 默认博客主题 + const [isDarkMode, updateDarkMode] = useState(BLOG.APPEARANCE === 'dark') // 默认深色模式 + const [onLoading, setOnLoading] = useState(false) // 抓取文章数据 + const [onReading, setOnReading] = useState(true) // 网页资源加载 const router = useRouter() useEffect(() => { initLocale(lang, locale, updateLang, updateLocale) initDarkMode(isDarkMode, updateDarkMode) initTheme(theme, changeTheme) + if (isBrowser()) { + // 监听用户刷新页面 + const handleBeforeUnload = (event) => { + setOnReading(true) + } + // 监听页面元素加载完 + setOnReading(false) + window.addEventListener('beforeunload', handleBeforeUnload) + return () => { + window.removeEventListener('beforeunload', handleBeforeUnload) + } + } }, []) useEffect(() => { const handleStart = (url) => { NProgress.start() - changeLoadingState(true) + setOnLoading(true) } const handleStop = () => { NProgress.done() - changeLoadingState(false) + setOnLoading(false) } router.events.on('routeChangeStart', handleStart) @@ -67,20 +81,20 @@ export function GlobalContextProvider({ children }) { } return ( - + + {children} ) diff --git a/lib/memorize.js b/lib/memorize.js new file mode 100644 index 00000000..e69de29b diff --git a/lib/notion/getAllCategories.js b/lib/notion/getAllCategories.js index b7700bc1..7cfd4588 100644 --- a/lib/notion/getAllCategories.js +++ b/lib/notion/getAllCategories.js @@ -19,7 +19,7 @@ export function getAllCategories({ allPages, categoryOptions, sliceCount = 0 }) return [] } // 计数 - let categories = allPosts.map(p => p.category) + let categories = allPosts?.map(p => p.category) categories = [...categories.flat()] const categoryObj = {} categories.forEach(category => { diff --git a/lib/notion/getAllTags.js b/lib/notion/getAllTags.js index b9144be8..968b8ca3 100644 --- a/lib/notion/getAllTags.js +++ b/lib/notion/getAllTags.js @@ -14,7 +14,7 @@ export function getAllTags({ allPages, sliceCount = 0, tagOptions }) { return [] } // 计数 - let tags = allPosts.map(p => p.tags) + let tags = allPosts?.map(p => p.tags) tags = [...tags.flat()] const tagObj = {} tags.forEach(tag => { diff --git a/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js index 185bc008..1d4554df 100644 --- a/lib/notion/getPageProperties.js +++ b/lib/notion/getPageProperties.js @@ -172,5 +172,9 @@ function generateCustomizeUrl(postProperties) { fullSlug += '/' } }) + if (fullSlug.startsWith('/')) { + fullSlug = fullSlug.substring(1) // 去掉头部的"/" + } + return `${fullSlug}/${(postProperties.slug ?? postProperties.id)}` } diff --git a/lib/theme.js b/lib/theme.js index 0a4f7a12..4d34fc8a 100644 --- a/lib/theme.js +++ b/lib/theme.js @@ -1,8 +1,21 @@ import cookie from 'react-cookies' import BLOG from '@/blog.config' -import { ALL_THEME } from '@/themes' import { isBrowser, getQueryVariable } from './utils' +/** + * 所有主题枚举 + */ +export const ALL_THEME = [ + 'hexo', + 'matery', + 'next', + 'medium', + 'fukasawa', + 'nobelium', + 'example', + 'simple' +] + /** * 初始化主题 , 优先级 query > cookies > systemPrefer * @param isDarkMode diff --git a/lib/utils.js b/lib/utils.js index 6677e7df..df39fe64 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,5 +1,15 @@ // 封装异步加载资源的方法 +import { memo } from 'react' +/** + * 组件持久化 + */ +export const memorize = (Component) => { + const MemoizedComponent = (props) => { + return + } + return memo(MemoizedComponent) +} /** * 加载外部资源 * @param url 地址 例如 https://xx.com/xx.js diff --git a/package.json b/package.json index 50363485..67dbcd6c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "notion-next", - "version": "3.14.0", + "version": "3.15.0", "homepage": "https://github.com/tangly1024/NotionNext.git", "license": "MIT", "repository": { @@ -30,13 +30,11 @@ "copy-to-clipboard": "^3.3.1", "eslint-plugin-react-hooks": "^4.6.0", "feed": "^4.2.2", - "gitalk": "^1.7.2", "js-md5": "^0.7.3", "localStorage": "^1.0.4", "lodash.throttle": "^4.1.1", "mark.js": "^8.11.1", "memory-cache": "^0.2.0", - "mermaid": "9.2.2", "mongodb": "^4.6.0", "next": "13.3.1", "notion-client": "6.15.6", @@ -56,8 +54,7 @@ "react-tweet-embed": "~2.0.0", "smoothscroll-polyfill": "^0.4.4", "typed.js": "^2.0.12", - "use-ackee": "^3.0.0", - "valine": "^1.4.18" + "use-ackee": "^3.0.0" }, "devDependencies": { "@waline/client": "^2.5.1", diff --git a/pages/404.js b/pages/404.js index d63b1e5e..f23edcec 100644 --- a/pages/404.js +++ b/pages/404.js @@ -1,6 +1,6 @@ import { getGlobalNotionData } from '@/lib/notion/getNotionData' -import * as ThemeMap from '@/themes' import { useGlobal } from '@/lib/global' +import dynamic from 'next/dynamic' /** * 404 @@ -9,9 +9,9 @@ import { useGlobal } from '@/lib/global' */ const NoFound = props => { const { theme, siteInfo } = useGlobal() - const ThemeComponents = ThemeMap[theme] const meta = { title: `${props?.siteInfo?.title} | 页面找不到啦`, image: siteInfo?.pageCover } - return + const Layout404 = dynamic(() => import(`@/themes/${theme}/Layout404`)) + return } export async function getStaticProps () { diff --git a/pages/[...slug].js b/pages/[...slug].js index 43e3d17a..d62a110a 100644 --- a/pages/[...slug].js +++ b/pages/[...slug].js @@ -2,14 +2,20 @@ import BLOG from '@/blog.config' import { getPostBlocks } from '@/lib/notion' import { getGlobalNotionData } from '@/lib/notion/getNotionData' import { useGlobal } from '@/lib/global' -import * as ThemeMap from '@/themes' -import { useEffect, useState } from 'react' +import { Suspense, useEffect, useState } from 'react' import { idToUuid } from 'notion-utils' -import Router, { useRouter } from 'next/router' +import { useRouter } from 'next/router' +import { isBrowser } from '@/lib/utils' import { getNotion } from '@/lib/notion/getNotion' import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents' import md5 from 'js-md5' -import { isBrowser } from '@/lib/utils' +import dynamic from 'next/dynamic' +import Loading from '@/components/Loading' + +/** + * 懒加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutSlug`), { ssr: true }) /** * 根据notion的slug访问页面 @@ -17,54 +23,28 @@ import { isBrowser } from '@/lib/utils' * @returns */ const Slug = props => { - const { theme, changeLoadingState } = useGlobal() - const ThemeComponents = ThemeMap[theme] + const { theme, setOnLoading } = useGlobal() const { post, siteInfo } = props const router = useRouter() + const [Layout, setLayout] = useState(DefaultLayout) + + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutSlug`))) + } + loadLayout() + }, [theme]) // 文章锁🔐 const [lock, setLock] = useState(post?.password && post?.password !== '') - useEffect(() => { - if (post) { - changeLoadingState(false) - } else { - changeLoadingState(true) - } - if (post?.password && post?.password !== '') { - setLock(true) - } else { - if (!lock && post?.blockMap?.block) { - post.content = Object.keys(post.blockMap.block).filter(key => post.blockMap.block[key]?.value?.parent_id === post.id) - post.toc = getPageTableOfContents(post, post.blockMap) - } - - setLock(false) - } - }, [post]) - - if (!post) { - setTimeout(() => { - if (isBrowser()) { - const article = document.getElementById('notion-article') - if (!article) { - router.push('/404').then(() => { - console.warn('找不到页面', router.asPath) - }) - } - } - }, 8 * 1000) // 404时长 8秒 - const meta = { title: `${props?.siteInfo?.title || BLOG.TITLE} | loading`, image: siteInfo?.pageCover || BLOG.HOME_BANNER_IMAGE } - return - } - /** - * 验证文章密码 - * @param {*} result - */ + * 验证文章密码 + * @param {*} result + */ const validPassword = passInput => { const encrypt = md5(post.slug + passInput) - if (passInput && encrypt === post.password) { setLock(false) return true @@ -72,25 +52,52 @@ const Slug = props => { return false } - props = { ...props, lock, setLock, validPassword } + // 文章加载 + useEffect(() => { + setOnLoading(false) + // 404 + if (!post) { + setTimeout(() => { + if (isBrowser()) { + const article = document.getElementById('notion-article') + if (!article) { + router.push('/404').then(() => { + console.warn('找不到页面', router.asPath) + }) + } + } + }, 8 * 1000) // 404时长 8秒 + } + + // 文章加密 + if (post?.password && post?.password !== '') { + setLock(true) + } else { + if (!lock && post?.blockMap?.block) { + post.content = Object.keys(post.blockMap.block).filter(key => post.blockMap.block[key]?.value?.parent_id === post.id) + post.toc = getPageTableOfContents(post, post.blockMap) + } + setLock(false) + } + router.events.on('routeChangeComplete', () => { + window.scrollTo({ top: 0, behavior: 'smooth' }) + }) + }, [post]) const meta = { - title: `${post?.title} | ${siteInfo?.title}`, + title: post ? `${post?.title} | ${siteInfo?.title}` : `${props?.siteInfo?.title || BLOG.TITLE} | loading`, description: post?.summary, type: post?.type, slug: post?.slug, - image: post?.page_cover, + image: post?.page_cover || (siteInfo?.pageCover || BLOG.HOME_BANNER_IMAGE), category: post?.category?.[0], tags: post?.tags } + props = { ...props, lock, meta, setLock, validPassword } - Router.events.on('routeChangeComplete', () => { - window.scrollTo({ top: 0, behavior: 'smooth' }) - }) - - return ( - - ) + return }> + + } export async function getStaticPaths() { @@ -119,7 +126,7 @@ export async function getStaticProps({ params: { slug } }) { const from = `slug-props-${fullSlug}` const props = await getGlobalNotionData({ from }) // 在列表内查找文章 - props.post = props.allPages.find((p) => { + props.post = props?.allPages?.find((p) => { return p.slug === fullSlug || p.id === idToUuid(fullSlug) }) diff --git a/pages/_app.js b/pages/_app.js index 9f83f261..41fc3de3 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -1,6 +1,4 @@ -import BLOG from 'blog.config' -import React, { useEffect } from 'react' -import dynamic from 'next/dynamic' +import { useEffect } from 'react' import 'animate.css' import '@/styles/globals.css' @@ -11,56 +9,21 @@ import 'react-notion-x/src/styles.css' import '@/styles/notion.css' // 重写部分样式 import { GlobalContextProvider } from '@/lib/global' -import { DebugPanel } from '@/components/DebugPanel' -import { ThemeSwitch } from '@/components/ThemeSwitch' -import { Fireworks } from '@/components/Fireworks' -import { Nest } from '@/components/Nest' -import { FlutteringRibbon } from '@/components/FlutteringRibbon' -import { Ribbon } from '@/components/Ribbon' -import { Sakura } from '@/components/Sakura' -import { StarrySky } from '@/components/StarrySky' -import MusicPlayer from '@/components/MusicPlayer' -import ExternalScript from '@/components/ExternalScript' -import smoothscroll from 'smoothscroll-polyfill' -import { Analytics } from '@vercel/analytics/react' +import { isMobile } from '@/lib/utils' import AOS from 'aos' import 'aos/dist/aos.css' // You can also use for styles -import { isMobile } from '@/lib/utils' -import TwikooCommentCounter from '@/components/TwikooCommentCounter' -const Ackee = dynamic(() => import('@/components/Ackee'), { ssr: false }) -const Gtag = dynamic(() => import('@/components/Gtag'), { ssr: false }) -const Busuanzi = dynamic(() => import('@/components/Busuanzi'), { ssr: false }) -const GoogleAdsense = dynamic(() => import('@/components/GoogleAdsense'), { - ssr: false -}) -const Messenger = dynamic(() => import('@/components/FacebookMessenger'), { - ssr: false -}) +import smoothscroll from 'smoothscroll-polyfill' +import dynamic from 'next/dynamic' + +// 自定义样式css和js引入 +import ExternalScript from '@/components/ExternalScript' + +// 各种扩展插件 动画等 +const ExternalPlugins = dynamic(() => import('@/components/ExternalPlugins')) const MyApp = ({ Component, pageProps }) => { - // 外部插件 - const externalPlugins = <> - {JSON.parse(BLOG.THEME_SWITCH) && } - {JSON.parse(BLOG.DEBUG) && } - {BLOG.ANALYTICS_ACKEE_TRACKER && } - {BLOG.ANALYTICS_GOOGLE_ID && } - {BLOG.ANALYTICS_VERCEL && } - {JSON.parse(BLOG.ANALYTICS_BUSUANZI_ENABLE) && } - {BLOG.ADSENSE_GOOGLE_ID && } - {BLOG.FACEBOOK_APP_ID && BLOG.FACEBOOK_PAGE_ID && } - {JSON.parse(BLOG.FIREWORKS) && } - {JSON.parse(BLOG.SAKURA) && } - {JSON.parse(BLOG.STARRY_SKY) && } - {JSON.parse(BLOG.MUSIC_PLAYER) && } - {JSON.parse(BLOG.NEST) && } - {JSON.parse(BLOG.FLUTTERINGRIBBON) && } - {JSON.parse(BLOG.COMMENT_TWIKOO_COUNT_ENABLE) && } - {JSON.parse(BLOG.RIBBON) && } - - - useEffect(() => { AOS.init() if (isMobile()) { @@ -71,7 +34,8 @@ const MyApp = ({ Component, pageProps }) => { return ( - {externalPlugins} + + ) } diff --git a/pages/archive/index.js b/pages/archive/index.js index 679d0800..bb095411 100644 --- a/pages/archive/index.js +++ b/pages/archive/index.js @@ -1,13 +1,28 @@ import { getGlobalNotionData } from '@/lib/notion/getNotionData' -import React from 'react' +import React, { Suspense, useEffect, useState } from 'react' import { useGlobal } from '@/lib/global' -import * as ThemeMap from '@/themes' +import dynamic from 'next/dynamic' import BLOG from '@/blog.config' +import Loading from '@/components/Loading' + +/** + * 加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutArchive`), { ssr: true }) + const ArchiveIndex = props => { - const { theme, locale } = useGlobal() - const ThemeComponents = ThemeMap[theme] const { siteInfo } = props + const { theme, locale } = useGlobal() + const [Layout, setLayout] = useState(DefaultLayout) + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutArchive`))) + } + loadLayout() + }, [theme]) + const meta = { title: `${locale.NAV.ARCHIVE} | ${siteInfo?.title}`, description: siteInfo?.description, @@ -16,7 +31,11 @@ const ArchiveIndex = props => { type: 'website' } - return + props = { ...props, meta } + + return }> + + } export async function getStaticProps() { diff --git a/pages/category/[category]/index.js b/pages/category/[category]/index.js index 583a69ab..1db1e85c 100644 --- a/pages/category/[category]/index.js +++ b/pages/category/[category]/index.js @@ -1,22 +1,33 @@ import { getGlobalNotionData } from '@/lib/notion/getNotionData' -import React from 'react' +import React, { Suspense, useEffect, useState } from 'react' import { useGlobal } from '@/lib/global' -import * as ThemeMap from '@/themes' +import dynamic from 'next/dynamic' import BLOG from '@/blog.config' +import Loading from '@/components/Loading' + +/** + * 加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutCategory`), { ssr: true }) + /** * 分类页 * @param {*} props * @returns */ export default function Category(props) { - const { theme } = useGlobal() - const ThemeComponents = ThemeMap[theme] - const { siteInfo, posts } = props - const { locale } = useGlobal() - if (!posts) { - return - } + const { siteInfo } = props + const { locale, theme } = useGlobal() + const [Layout, setLayout] = useState(DefaultLayout) + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutCategory`))) + } + loadLayout() + }, [theme]) + const meta = { title: `${props.category} | ${locale.COMMON.CATEGORY} | ${ siteInfo?.title || '' @@ -26,7 +37,12 @@ export default function Category(props) { image: siteInfo?.pageCover, type: 'website' } - return + + props = { ...props, meta } + + return }> + + } export async function getStaticProps({ params: { category } }) { diff --git a/pages/category/[category]/page/[page].js b/pages/category/[category]/page/[page].js index f01ae27a..7ed2d109 100644 --- a/pages/category/[category]/page/[page].js +++ b/pages/category/[category]/page/[page].js @@ -1,9 +1,16 @@ import { getGlobalNotionData } from '@/lib/notion/getNotionData' -import React from 'react' +import React, { Suspense, useEffect, useState } from 'react' import { useGlobal } from '@/lib/global' -import * as ThemeMap from '@/themes' +import dynamic from 'next/dynamic' import BLOG from '@/blog.config' +import Loading from '@/components/Loading' + +/** + * 加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutCategory`), { ssr: true }) + /** * 分类页 * @param {*} props @@ -11,12 +18,18 @@ import BLOG from '@/blog.config' */ export default function Category(props) { const { theme } = useGlobal() - const ThemeComponents = ThemeMap[theme] - const { siteInfo, posts } = props + const { siteInfo } = props const { locale } = useGlobal() - if (!posts) { - return - } + + const [Layout, setLayout] = useState(DefaultLayout) + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutCategory`))) + } + loadLayout() + }, [theme]) + const meta = { title: `${props.category} | ${locale.COMMON.CATEGORY} | ${ siteInfo?.title || '' @@ -26,7 +39,12 @@ export default function Category(props) { image: siteInfo?.pageCover, type: 'website' } - return + + props = { ...props, meta } + + return }> + + } export async function getStaticProps({ params: { category, page } }) { diff --git a/pages/category/index.js b/pages/category/index.js index b310c188..d4c6ab00 100644 --- a/pages/category/index.js +++ b/pages/category/index.js @@ -1,9 +1,16 @@ import { getGlobalNotionData } from '@/lib/notion/getNotionData' -import React from 'react' +import React, { Suspense, useEffect, useState } from 'react' import { useGlobal } from '@/lib/global' -import * as ThemeMap from '@/themes' +import dynamic from 'next/dynamic' import BLOG from '@/blog.config' +import Loading from '@/components/Loading' + +/** + * 加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutCategoryIndex`), { ssr: true }) + /** * 分类首页 * @param {*} props @@ -11,9 +18,18 @@ import BLOG from '@/blog.config' */ export default function Category(props) { const { theme } = useGlobal() - const ThemeComponents = ThemeMap[theme] const { locale } = useGlobal() const { siteInfo } = props + const [Layout, setLayout] = useState(DefaultLayout) + + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutCategoryIndex`))) + } + loadLayout() + }, [theme]) + const meta = { title: `${locale.COMMON.CATEGORY} | ${siteInfo?.title}`, description: siteInfo?.description, @@ -21,7 +37,11 @@ export default function Category(props) { slug: 'category', type: 'website' } - return + props = { ...props, meta } + + return }> + + } export async function getStaticProps() { diff --git a/pages/index.js b/pages/index.js index 7fac472b..8de156c9 100644 --- a/pages/index.js +++ b/pages/index.js @@ -1,10 +1,17 @@ import BLOG from '@/blog.config' import { getPostBlocks } from '@/lib/notion' import { getGlobalNotionData } from '@/lib/notion/getNotionData' -import * as ThemeMap from '@/themes' import { useGlobal } from '@/lib/global' import { generateRss } from '@/lib/rss' import { generateRobotsTxt } from '@/lib/robots.txt' +import dynamic from 'next/dynamic' +import { Suspense, useEffect, useState } from 'react' +import Loading from '@/components/Loading' + +/** + * 懒加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutIndex`), { ssr: true }) /** * 首页布局 @@ -12,9 +19,20 @@ import { generateRobotsTxt } from '@/lib/robots.txt' * @returns */ const Index = props => { + // 动态切换主题 const { theme } = useGlobal() - const ThemeComponents = ThemeMap[theme] - return + const [Layout, setLayoutIndex] = useState(DefaultLayout) + useEffect(() => { + const loadLayout = async () => { + setLayoutIndex(dynamic(() => import(`@/themes/${theme}/LayoutIndex`))) + } + console.log(loadLayout) + // loadLayout() + }, [theme]) + + return }> + + } /** diff --git a/pages/page/[page].js b/pages/page/[page].js index 63ebc615..e3b03ddd 100644 --- a/pages/page/[page].js +++ b/pages/page/[page].js @@ -2,23 +2,44 @@ import BLOG from '@/blog.config' import { getPostBlocks } from '@/lib/notion' import { getGlobalNotionData } from '@/lib/notion/getNotionData' import { useGlobal } from '@/lib/global' -import * as ThemeMap from '@/themes' +import dynamic from 'next/dynamic' +import { Suspense, useEffect, useState } from 'react' +import Loading from '@/components/Loading' +/** + * 加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutPage`), { ssr: true }) +/** + * 文章列表分页 + * @param {*} props + * @returns + */ const Page = props => { const { theme } = useGlobal() const { siteInfo } = props - const ThemeComponents = ThemeMap[theme] - if (!siteInfo) { - return <> - } + const [Layout, setLayout] = useState(DefaultLayout) + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutPage`))) + } + loadLayout() + }, [theme]) + const meta = { - title: `${props.page} | Page | ${siteInfo?.title}`, + title: `${props?.page} | Page | ${siteInfo?.title}`, description: siteInfo?.description, image: siteInfo?.pageCover, slug: 'page/' + props.page, type: 'website' } - return + + props = { ...props, meta } + + return }> + + } export async function getStaticPaths() { diff --git a/pages/search/[keyword]/index.js b/pages/search/[keyword]/index.js index b1ea5bc4..92b18fb3 100644 --- a/pages/search/[keyword]/index.js +++ b/pages/search/[keyword]/index.js @@ -1,12 +1,28 @@ import { getGlobalNotionData } from '@/lib/notion/getNotionData' import { useGlobal } from '@/lib/global' import { getDataFromCache } from '@/lib/cache/cache_manager' -import * as ThemeMap from '@/themes' import BLOG from '@/blog.config' +import dynamic from 'next/dynamic' +import { Suspense, useEffect, useState } from 'react' +import Loading from '@/components/Loading' + +/** + * 加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutSearch`), { ssr: true }) const Index = props => { const { keyword, siteInfo } = props - const { locale } = useGlobal() + const { locale, theme } = useGlobal() + const [Layout, setLayout] = useState(DefaultLayout) + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutSearch`))) + } + loadLayout() + }, [theme]) + const meta = { title: `${keyword || ''}${keyword ? ' | ' : ''}${locale.NAV.SEARCH} | ${siteInfo?.title}`, description: siteInfo?.title, @@ -14,15 +30,12 @@ const Index = props => { slug: 'search/' + (keyword || ''), type: 'website' } - const { theme } = useGlobal() - const ThemeComponents = ThemeMap[theme] - return ( - - ) + + props = { ...props, meta } + + return }> + + } /** diff --git a/pages/search/[keyword]/page/[page].js b/pages/search/[keyword]/page/[page].js index 1255f3c3..a279f332 100644 --- a/pages/search/[keyword]/page/[page].js +++ b/pages/search/[keyword]/page/[page].js @@ -1,12 +1,27 @@ import { getGlobalNotionData } from '@/lib/notion/getNotionData' import { useGlobal } from '@/lib/global' import { getDataFromCache } from '@/lib/cache/cache_manager' -import * as ThemeMap from '@/themes' +import dynamic from 'next/dynamic' import BLOG from '@/blog.config' +import { Suspense, useEffect, useState } from 'react' +import Loading from '@/components/Loading' + +/** + * 加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutSearch`), { ssr: true }) const Index = props => { const { keyword, siteInfo } = props - const { locale } = useGlobal() + const { locale, theme } = useGlobal() + const [Layout, setLayout] = useState(DefaultLayout) + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutSearch`))) + } + loadLayout() + }, [theme]) const meta = { title: `${keyword || ''}${keyword ? ' | ' : ''}${locale.NAV.SEARCH} | ${siteInfo?.title}`, description: siteInfo?.title, @@ -14,15 +29,12 @@ const Index = props => { slug: 'search/' + (keyword || ''), type: 'website' } - const { theme } = useGlobal() - const ThemeComponents = ThemeMap[theme] - return ( - - ) + + props = { ...props, meta, currentSearch: keyword } + + return }> + + } /** diff --git a/pages/search/index.js b/pages/search/index.js index fc20c5fd..06fd3984 100644 --- a/pages/search/index.js +++ b/pages/search/index.js @@ -1,22 +1,39 @@ import { getGlobalNotionData } from '@/lib/notion/getNotionData' import { useGlobal } from '@/lib/global' import { useRouter } from 'next/router' -import * as ThemeMap from '@/themes' import BLOG from '@/blog.config' +import dynamic from 'next/dynamic' +import { Suspense, useEffect, useState } from 'react' +import Loading from '@/components/Loading' +/** + * 加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutSearch`), { ssr: true }) const Search = props => { const { posts, siteInfo } = props + const { theme } = useGlobal() + const [Layout, setLayout] = useState(DefaultLayout) + + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutSearch`))) + } + loadLayout() + }, [theme]) + const router = useRouter() let filteredPosts - const searchKey = getSearchKey(router) + const keyword = getSearchKey(router) // 静态过滤 - if (searchKey) { + if (keyword) { filteredPosts = posts.filter(post => { const tagContent = post.tags ? post.tags.join(' ') : '' const categoryContent = post.category ? post.category.join(' ') : '' const searchContent = - post.title + post.summary + tagContent + categoryContent - return searchContent.toLowerCase().includes(searchKey.toLowerCase()) + post.title + post.summary + tagContent + categoryContent + return searchContent.toLowerCase().includes(keyword.toLowerCase()) }) } else { filteredPosts = [] @@ -24,26 +41,18 @@ const Search = props => { const { locale } = useGlobal() const meta = { - title: `${searchKey || ''}${searchKey ? ' | ' : ''}${locale.NAV.SEARCH} | ${ - siteInfo?.title - }`, + title: `${keyword || ''}${keyword ? ' | ' : ''}${locale.NAV.SEARCH} | ${siteInfo?.title}`, description: siteInfo?.description, image: siteInfo?.pageCover, slug: 'search', type: 'website' } - const { theme } = useGlobal() - const ThemeComponents = ThemeMap[theme] + props = { ...props, meta, posts: { filteredPosts } } - return ( - - ) + return }> + + } /** diff --git a/pages/tag/[tag]/index.js b/pages/tag/[tag]/index.js index f633c94f..8b5729f3 100644 --- a/pages/tag/[tag]/index.js +++ b/pages/tag/[tag]/index.js @@ -1,17 +1,28 @@ import { useGlobal } from '@/lib/global' import { getGlobalNotionData } from '@/lib/notion/getNotionData' -import * as ThemeMap from '@/themes' import BLOG from '@/blog.config' +import dynamic from 'next/dynamic' +import { Suspense, useEffect, useState } from 'react' +import Loading from '@/components/Loading' + +/** + * 加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutTag`), { ssr: true }) const Tag = props => { const { theme } = useGlobal() - const ThemeComponents = ThemeMap[theme] const { locale } = useGlobal() - const { tag, siteInfo, posts } = props + const { tag, siteInfo } = props + const [Layout, setLayout] = useState(DefaultLayout) - if (!posts) { - return - } + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutTag`))) + } + loadLayout() + }, [theme]) const meta = { title: `${tag} | ${locale.COMMON.TAGS} | ${siteInfo?.title}`, @@ -20,7 +31,11 @@ const Tag = props => { slug: 'tag/' + tag, type: 'website' } - return + props = { ...props, meta } + + return }> + + } export async function getStaticProps({ params: { tag } }) { diff --git a/pages/tag/[tag]/page/[page].js b/pages/tag/[tag]/page/[page].js index 788473b9..2adb6c2c 100644 --- a/pages/tag/[tag]/page/[page].js +++ b/pages/tag/[tag]/page/[page].js @@ -1,17 +1,27 @@ import { useGlobal } from '@/lib/global' import { getGlobalNotionData } from '@/lib/notion/getNotionData' -import * as ThemeMap from '@/themes' import BLOG from '@/blog.config' +import dynamic from 'next/dynamic' +import { Suspense, useEffect, useState } from 'react' +import Loading from '@/components/Loading' + +/** + * 加载默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutTag`), { ssr: true }) const Tag = props => { const { theme } = useGlobal() - const ThemeComponents = ThemeMap[theme] const { locale } = useGlobal() - const { tag, siteInfo, posts } = props - - if (!posts) { - return - } + const { tag, siteInfo } = props + const [Layout, setLayout] = useState(DefaultLayout) + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutTag`))) + } + loadLayout() + }, [theme]) const meta = { title: `${tag} | ${locale.COMMON.TAGS} | ${siteInfo?.title}`, @@ -20,7 +30,11 @@ const Tag = props => { slug: 'tag/' + tag, type: 'website' } - return + props = { ...props, meta } + + return }> + + } export async function getStaticProps({ params: { tag, page } }) { diff --git a/pages/tag/index.js b/pages/tag/index.js index e9263668..8b8bc1c7 100644 --- a/pages/tag/index.js +++ b/pages/tag/index.js @@ -1,8 +1,13 @@ import { getGlobalNotionData } from '@/lib/notion/getNotionData' -import React from 'react' +import { Suspense, useEffect, useState } from 'react' import { useGlobal } from '@/lib/global' -import * as ThemeMap from '@/themes' import BLOG from '@/blog.config' +import dynamic from 'next/dynamic' +import Loading from '@/components/Loading' +/** + * 默认主题 + */ +const DefaultLayout = dynamic(() => import(`@/themes/${BLOG.THEME}/LayoutTagIndex`), { ssr: true }) /** * 标签首页 @@ -10,10 +15,18 @@ import BLOG from '@/blog.config' * @returns */ const TagIndex = props => { - const { theme } = useGlobal() - const ThemeComponents = ThemeMap[theme] const { locale } = useGlobal() const { siteInfo } = props + const { theme } = useGlobal() + const [Layout, setLayout] = useState(DefaultLayout) + // 切换主题 + useEffect(() => { + const loadLayout = async () => { + setLayout(dynamic(() => import(`@/themes/${theme}/LayoutTagIndex`))) + } + loadLayout() + }, [theme]) + const meta = { title: `${locale.COMMON.TAGS} | ${siteInfo?.title}`, description: siteInfo?.description, @@ -21,7 +34,11 @@ const TagIndex = props => { slug: 'tag', type: 'website' } - return + props = { ...props, meta } + + return }> + + } export async function getStaticProps() { diff --git a/themes/example/Layout404.js b/themes/example/Layout404.js index 5f92f0cc..c0992ad3 100644 --- a/themes/example/Layout404.js +++ b/themes/example/Layout404.js @@ -5,3 +5,5 @@ export const Layout404 = (props) => { 404 Not found. } + +export default Layout404 diff --git a/themes/example/LayoutArchive.js b/themes/example/LayoutArchive.js index 4ba92d8a..81ec0781 100644 --- a/themes/example/LayoutArchive.js +++ b/themes/example/LayoutArchive.js @@ -43,3 +43,5 @@ export const LayoutArchive = props => { ) } + +export default LayoutArchive diff --git a/themes/example/LayoutCategory.js b/themes/example/LayoutCategory.js index 6d819185..517a5e82 100644 --- a/themes/example/LayoutCategory.js +++ b/themes/example/LayoutCategory.js @@ -8,3 +8,5 @@ export const LayoutCategory = props => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutCategory diff --git a/themes/example/LayoutCategoryIndex.js b/themes/example/LayoutCategoryIndex.js index a4c19033..d969516b 100644 --- a/themes/example/LayoutCategoryIndex.js +++ b/themes/example/LayoutCategoryIndex.js @@ -24,3 +24,5 @@ export const LayoutCategoryIndex = props => { ) } + +export default LayoutCategoryIndex diff --git a/themes/example/LayoutIndex.js b/themes/example/LayoutIndex.js index 94eaac2f..18024d9c 100644 --- a/themes/example/LayoutIndex.js +++ b/themes/example/LayoutIndex.js @@ -11,3 +11,5 @@ export const LayoutIndex = props => { ) } + +export default LayoutIndex diff --git a/themes/example/LayoutPage.js b/themes/example/LayoutPage.js index 15355018..184251a8 100644 --- a/themes/example/LayoutPage.js +++ b/themes/example/LayoutPage.js @@ -8,3 +8,5 @@ export const LayoutPage = props => { ) } + +export default LayoutPage diff --git a/themes/example/LayoutSlug.js b/themes/example/LayoutSlug.js index b19f51ff..2ab9c557 100644 --- a/themes/example/LayoutSlug.js +++ b/themes/example/LayoutSlug.js @@ -29,3 +29,5 @@ export const LayoutSlug = props => { ) } + +export default LayoutSlug diff --git a/themes/example/LayoutTag.js b/themes/example/LayoutTag.js index 06a6d778..f12ae546 100644 --- a/themes/example/LayoutTag.js +++ b/themes/example/LayoutTag.js @@ -8,3 +8,5 @@ export const LayoutTag = props => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutTag diff --git a/themes/example/LayoutTagIndex.js b/themes/example/LayoutTagIndex.js index 0705c2d6..63ffa7ca 100644 --- a/themes/example/LayoutTagIndex.js +++ b/themes/example/LayoutTagIndex.js @@ -27,3 +27,5 @@ export const LayoutTagIndex = (props) => { ) } + +export default LayoutTagIndex diff --git a/themes/example/index.js b/themes/example/index.js deleted file mode 100644 index dd762bd4..00000000 --- a/themes/example/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import CONFIG_EXAMPLE from './config_example' -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' - -export { - CONFIG_EXAMPLE as THEME_CONFIG, - LayoutIndex, - LayoutSearch, - LayoutArchive, - LayoutSlug, - Layout404, - LayoutCategory, - LayoutCategoryIndex, - LayoutPage, - LayoutTag, - LayoutTagIndex -} diff --git a/themes/fukasawa/Layout404.js b/themes/fukasawa/Layout404.js index 183001c9..98ae689a 100644 --- a/themes/fukasawa/Layout404.js +++ b/themes/fukasawa/Layout404.js @@ -3,3 +3,5 @@ import LayoutBase from './LayoutBase' export const Layout404 = props => { return 404 } + +export default Layout404 diff --git a/themes/fukasawa/LayoutArchive.js b/themes/fukasawa/LayoutArchive.js index 495ed6a4..f82f3e35 100644 --- a/themes/fukasawa/LayoutArchive.js +++ b/themes/fukasawa/LayoutArchive.js @@ -28,3 +28,5 @@ export const LayoutArchive = (props) => { } + +export default LayoutArchive diff --git a/themes/fukasawa/LayoutCategory.js b/themes/fukasawa/LayoutCategory.js index fa6c8c0d..c633a439 100644 --- a/themes/fukasawa/LayoutCategory.js +++ b/themes/fukasawa/LayoutCategory.js @@ -8,3 +8,5 @@ export const LayoutCategory = props => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutCategory diff --git a/themes/fukasawa/LayoutCategoryIndex.js b/themes/fukasawa/LayoutCategoryIndex.js index 9e9cdd9c..469ab973 100644 --- a/themes/fukasawa/LayoutCategoryIndex.js +++ b/themes/fukasawa/LayoutCategoryIndex.js @@ -31,3 +31,5 @@ export const LayoutCategoryIndex = (props) => { ) } + +export default LayoutCategoryIndex diff --git a/themes/fukasawa/LayoutIndex.js b/themes/fukasawa/LayoutIndex.js index 47ae1bce..d4e7451b 100644 --- a/themes/fukasawa/LayoutIndex.js +++ b/themes/fukasawa/LayoutIndex.js @@ -8,3 +8,5 @@ export const LayoutIndex = (props) => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutIndex diff --git a/themes/fukasawa/LayoutPage.js b/themes/fukasawa/LayoutPage.js index a3c39788..c3a85397 100644 --- a/themes/fukasawa/LayoutPage.js +++ b/themes/fukasawa/LayoutPage.js @@ -8,3 +8,5 @@ export const LayoutPage = (props) => { } + +export default LayoutPage diff --git a/themes/fukasawa/LayoutSearch.js b/themes/fukasawa/LayoutSearch.js index fcfa35b2..58aeaf88 100644 --- a/themes/fukasawa/LayoutSearch.js +++ b/themes/fukasawa/LayoutSearch.js @@ -28,3 +28,5 @@ export const LayoutSearch = (props) => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutSearch diff --git a/themes/fukasawa/LayoutSlug.js b/themes/fukasawa/LayoutSlug.js index fb78690c..73e22a00 100644 --- a/themes/fukasawa/LayoutSlug.js +++ b/themes/fukasawa/LayoutSlug.js @@ -11,3 +11,5 @@ export const LayoutSlug = (props) => { ) } + +export default LayoutSlug diff --git a/themes/fukasawa/LayoutTag.js b/themes/fukasawa/LayoutTag.js index 46e9e0fd..104b6884 100644 --- a/themes/fukasawa/LayoutTag.js +++ b/themes/fukasawa/LayoutTag.js @@ -1,7 +1,6 @@ import BLOG from '@/blog.config' import BlogListPage from './components/BlogListPage' import BlogListScroll from './components/BlogListScroll' -import TagItemMini from './components/TagItemMini' import LayoutBase from './LayoutBase' export const LayoutTag = (props) => { @@ -9,3 +8,5 @@ export const LayoutTag = (props) => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutTag diff --git a/themes/fukasawa/LayoutTagIndex.js b/themes/fukasawa/LayoutTagIndex.js index df43fdeb..30f602a6 100644 --- a/themes/fukasawa/LayoutTagIndex.js +++ b/themes/fukasawa/LayoutTagIndex.js @@ -1,5 +1,4 @@ import { useGlobal } from '@/lib/global' -import TagItem from './components/TagItem' import TagItemMini from './components/TagItemMini' import LayoutBase from './LayoutBase' @@ -21,3 +20,5 @@ export const LayoutTagIndex = (props) => { } + +export default LayoutTagIndex diff --git a/themes/fukasawa/components/BlogPostArchive.js b/themes/fukasawa/components/BlogPostArchive.js index c594d7d1..a86210db 100644 --- a/themes/fukasawa/components/BlogPostArchive.js +++ b/themes/fukasawa/components/BlogPostArchive.js @@ -21,7 +21,7 @@ const BlogArchiveItem = ({ posts = [], archiveTitle }) => { {archiveTitle}
    - {posts.map(post => ( + {posts?.map(post => (
  • { ) } +export default Layout404 diff --git a/themes/hexo/LayoutArchive.js b/themes/hexo/LayoutArchive.js index 94dc9267..44f81c08 100644 --- a/themes/hexo/LayoutArchive.js +++ b/themes/hexo/LayoutArchive.js @@ -32,3 +32,5 @@ export const LayoutArchive = (props) => { } + +export default LayoutArchive diff --git a/themes/hexo/LayoutCategory.js b/themes/hexo/LayoutCategory.js index 7df32650..3aedefef 100644 --- a/themes/hexo/LayoutCategory.js +++ b/themes/hexo/LayoutCategory.js @@ -13,3 +13,5 @@ export const LayoutCategory = props => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutCategory diff --git a/themes/hexo/LayoutCategoryIndex.js b/themes/hexo/LayoutCategoryIndex.js index 0d0a24d0..bd4e278e 100644 --- a/themes/hexo/LayoutCategoryIndex.js +++ b/themes/hexo/LayoutCategoryIndex.js @@ -37,3 +37,5 @@ export const LayoutCategoryIndex = props => { ) } + +export default LayoutCategoryIndex diff --git a/themes/hexo/LayoutIndex.js b/themes/hexo/LayoutIndex.js index 48cc29e4..388e69bf 100644 --- a/themes/hexo/LayoutIndex.js +++ b/themes/hexo/LayoutIndex.js @@ -12,3 +12,5 @@ export const LayoutIndex = (props) => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutIndex diff --git a/themes/hexo/LayoutPage.js b/themes/hexo/LayoutPage.js index ac32c985..58d35c0a 100644 --- a/themes/hexo/LayoutPage.js +++ b/themes/hexo/LayoutPage.js @@ -6,3 +6,5 @@ export const LayoutPage = (props) => { } + +export default LayoutPage diff --git a/themes/hexo/LayoutSearch.js b/themes/hexo/LayoutSearch.js index bf9c6daa..1098e483 100644 --- a/themes/hexo/LayoutSearch.js +++ b/themes/hexo/LayoutSearch.js @@ -97,3 +97,5 @@ export const LayoutSearch = props => { ) } + +export default LayoutSearch diff --git a/themes/hexo/LayoutSlug.js b/themes/hexo/LayoutSlug.js index 120d4243..9c8ff361 100644 --- a/themes/hexo/LayoutSlug.js +++ b/themes/hexo/LayoutSlug.js @@ -93,3 +93,5 @@ export const LayoutSlug = props => { ) } + +export default LayoutSlug diff --git a/themes/hexo/LayoutTag.js b/themes/hexo/LayoutTag.js index 36a9ce7d..cd72a015 100644 --- a/themes/hexo/LayoutTag.js +++ b/themes/hexo/LayoutTag.js @@ -6,7 +6,7 @@ import React from 'react' import Link from 'next/link' export const LayoutTag = (props) => { - const tag = props.tagOptions.find((t) => { + const tag = props?.tagOptions?.find((t) => { return t.name === props.tag }) @@ -30,3 +30,5 @@ export const LayoutTag = (props) => { ) } + +export default LayoutTag diff --git a/themes/hexo/LayoutTagIndex.js b/themes/hexo/LayoutTagIndex.js index 5e83966a..40e7e234 100644 --- a/themes/hexo/LayoutTagIndex.js +++ b/themes/hexo/LayoutTagIndex.js @@ -26,3 +26,5 @@ export const LayoutTagIndex = props => { ) } + +export default LayoutTagIndex diff --git a/themes/hexo/components/BlogPostArchive.js b/themes/hexo/components/BlogPostArchive.js index 20887d45..f90f4c03 100644 --- a/themes/hexo/components/BlogPostArchive.js +++ b/themes/hexo/components/BlogPostArchive.js @@ -21,7 +21,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => { {archiveTitle}
      - {posts.map(post => ( + {posts?.map(post => (
    • { ))}
    - ); + ) } } diff --git a/themes/hexo/components/BlogPostCard.js b/themes/hexo/components/BlogPostCard.js index 5882f265..af2192b0 100644 --- a/themes/hexo/components/BlogPostCard.js +++ b/themes/hexo/components/BlogPostCard.js @@ -2,6 +2,7 @@ import Link from 'next/link' import React from 'react' import CONFIG_HEXO from '../config_hexo' import { BlogPostCardInfo } from './BlogPostCardInfo' +import BLOG from '@/blog.config' // import Image from 'next/image' const BlogPostCard = ({ index, post, showSummary, siteInfo }) => { @@ -34,7 +35,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => { {/* 图片封面 */} {showPageCover && (
    - +
    diff --git a/themes/hexo/components/BlogPostCardInfo.js b/themes/hexo/components/BlogPostCardInfo.js index d89c126b..508114f4 100644 --- a/themes/hexo/components/BlogPostCardInfo.js +++ b/themes/hexo/components/BlogPostCardInfo.js @@ -2,6 +2,7 @@ import NotionPage from '@/components/NotionPage' import Link from 'next/link' import TagItemMini from './TagItemMini' import TwikooCommentCount from '@/components/TwikooCommentCount' +import BLOG from '@/blog.config' /** * 博客列表的文字内容 @@ -13,7 +14,7 @@ export const BlogPostCardInfo = ({ post, showPreview, showPageCover, showSummary
    {/* 标题 */} diff --git a/themes/hexo/components/BlogPostListPage.js b/themes/hexo/components/BlogPostListPage.js index 9a2c68f7..92008f83 100644 --- a/themes/hexo/components/BlogPostListPage.js +++ b/themes/hexo/components/BlogPostListPage.js @@ -21,7 +21,7 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
    {/* 文章列表 */}
    - {posts.map(post => ( + {posts?.map(post => ( ))}
    diff --git a/themes/hexo/components/Header.js b/themes/hexo/components/Header.js index c3374413..e72a931a 100644 --- a/themes/hexo/components/Header.js +++ b/themes/hexo/components/Header.js @@ -5,6 +5,7 @@ import CONFIG_HEXO from '../config_hexo' import NavButtonGroup from './NavButtonGroup' import throttle from 'lodash.throttle' import { useGlobal } from '@/lib/global' +import BLOG from '@/blog.config' let wrapperTop = 0 let windowTop = 0 @@ -25,7 +26,7 @@ const Header = props => { if (!typed && window && document.getElementById('typed')) { changeType( new Typed('#typed', { - strings: CONFIG_HEXO.HOME_BANNER_GREETINGS, + strings: BLOG.GREETING_WORDS.split(','), typeSpeed: 200, backSpeed: 100, backDelay: 400, diff --git a/themes/hexo/components/HeaderArticle.js b/themes/hexo/components/HeaderArticle.js index 7e19985a..95997fa3 100644 --- a/themes/hexo/components/HeaderArticle.js +++ b/themes/hexo/components/HeaderArticle.js @@ -21,7 +21,11 @@ export default function HeaderArticle({ post, siteInfo }) { return (
      - {posts.map(post => ( + {posts?.map(post => (
    • {
      {/* 文章列表 */}
      - {posts.map(post => ( + {posts?.map(post => (
      ))}
      diff --git a/themes/matery/components/HeaderArticle.js b/themes/matery/components/HeaderArticle.js index 004d76d1..2a526c8a 100644 --- a/themes/matery/components/HeaderArticle.js +++ b/themes/matery/components/HeaderArticle.js @@ -7,9 +7,9 @@ export default function HeaderArticle({ post, siteInfo }) { } } + +export default LayoutSearch diff --git a/themes/medium/LayoutSlug.js b/themes/medium/LayoutSlug.js index 401c4a03..dab24ed0 100644 --- a/themes/medium/LayoutSlug.js +++ b/themes/medium/LayoutSlug.js @@ -106,3 +106,5 @@ export const LayoutSlug = props => { ) } + +export default LayoutSlug diff --git a/themes/medium/LayoutTag.js b/themes/medium/LayoutTag.js index 51a7ca59..bedb51ef 100644 --- a/themes/medium/LayoutTag.js +++ b/themes/medium/LayoutTag.js @@ -11,3 +11,5 @@ export const LayoutTag = (props) => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutTag diff --git a/themes/medium/LayoutTagIndex.js b/themes/medium/LayoutTagIndex.js index 1f173bd2..cc9f8c94 100644 --- a/themes/medium/LayoutTagIndex.js +++ b/themes/medium/LayoutTagIndex.js @@ -25,3 +25,5 @@ export const LayoutTagIndex = props => { ) } + +export default LayoutTagIndex diff --git a/themes/medium/components/BlogPostListPage.js b/themes/medium/components/BlogPostListPage.js index bd7499dc..db74b74e 100644 --- a/themes/medium/components/BlogPostListPage.js +++ b/themes/medium/components/BlogPostListPage.js @@ -22,7 +22,7 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
      {/* 文章列表 */} - {posts.map(post => ( + {posts?.map(post => ( ))}
      diff --git a/themes/medium/index.js b/themes/medium/index.js deleted file mode 100644 index 81961c58..00000000 --- a/themes/medium/index.js +++ /dev/null @@ -1,25 +0,0 @@ -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' - -export { - CONFIG_MEDIUM as THEME_CONFIG, - LayoutIndex, - LayoutSearch, - LayoutArchive, - LayoutSlug, - Layout404, - LayoutCategory, - LayoutCategoryIndex, - LayoutPage, - LayoutTag, - LayoutTagIndex -} diff --git a/themes/next/Layout404.js b/themes/next/Layout404.js index 8c1bc421..61c48d37 100644 --- a/themes/next/Layout404.js +++ b/themes/next/Layout404.js @@ -29,3 +29,4 @@ export const Layout404 = props => {
      } +export default Layout404 diff --git a/themes/next/LayoutArchive.js b/themes/next/LayoutArchive.js index ebd94ed3..29f6683c 100644 --- a/themes/next/LayoutArchive.js +++ b/themes/next/LayoutArchive.js @@ -31,3 +31,5 @@ export const LayoutArchive = (props) => { ) } + +export default LayoutArchive diff --git a/themes/next/LayoutCategory.js b/themes/next/LayoutCategory.js index ec71cb95..aaf07970 100644 --- a/themes/next/LayoutCategory.js +++ b/themes/next/LayoutCategory.js @@ -19,3 +19,5 @@ export const LayoutCategory = (props) => {
    } + +export default LayoutCategory diff --git a/themes/next/LayoutCategoryIndex.js b/themes/next/LayoutCategoryIndex.js index 0dd99e0f..ca7d992a 100644 --- a/themes/next/LayoutCategoryIndex.js +++ b/themes/next/LayoutCategoryIndex.js @@ -31,3 +31,5 @@ export const LayoutCategoryIndex = (props) => { ) } + +export default LayoutCategoryIndex diff --git a/themes/next/LayoutIndex.js b/themes/next/LayoutIndex.js index c43dc3d3..31cfee1c 100644 --- a/themes/next/LayoutIndex.js +++ b/themes/next/LayoutIndex.js @@ -18,7 +18,10 @@ export const LayoutIndex = (props) => { > {BLOG.POST_LIST_STYLE !== 'page' ? - : + : } } + +export default LayoutIndex diff --git a/themes/next/LayoutPage.js b/themes/next/LayoutPage.js index 7cd06dab..710392fd 100644 --- a/themes/next/LayoutPage.js +++ b/themes/next/LayoutPage.js @@ -15,3 +15,5 @@ export const LayoutPage = (props) => { ) } + +export default LayoutPage diff --git a/themes/next/LayoutSearch.js b/themes/next/LayoutSearch.js index 78664343..31e102fd 100644 --- a/themes/next/LayoutSearch.js +++ b/themes/next/LayoutSearch.js @@ -37,3 +37,5 @@ export const LayoutSearch = (props) => { ) } + +export default LayoutSearch diff --git a/themes/next/LayoutSlug.js b/themes/next/LayoutSlug.js index 0087bf93..9870d457 100644 --- a/themes/next/LayoutSlug.js +++ b/themes/next/LayoutSlug.js @@ -40,3 +40,5 @@ export const LayoutSlug = (props) => { ) } + +export default LayoutSlug diff --git a/themes/next/LayoutTag.js b/themes/next/LayoutTag.js index c70307e8..9bf9b0c4 100644 --- a/themes/next/LayoutTag.js +++ b/themes/next/LayoutTag.js @@ -20,3 +20,5 @@ export const LayoutTag = (props) => {
    } + +export default LayoutTag diff --git a/themes/next/LayoutTagIndex.js b/themes/next/LayoutTagIndex.js index 5278dd8f..a8e96067 100644 --- a/themes/next/LayoutTagIndex.js +++ b/themes/next/LayoutTagIndex.js @@ -16,3 +16,5 @@ export const LayoutTagIndex = (props) => {
    } + +export default LayoutTagIndex diff --git a/themes/next/components/ArticleDetail.js b/themes/next/components/ArticleDetail.js index c0c2efac..da882db9 100644 --- a/themes/next/components/ArticleDetail.js +++ b/themes/next/components/ArticleDetail.js @@ -20,9 +20,10 @@ import NotionIcon from '@/components/NotionIcon' * @returns */ export default function ArticleDetail(props) { - const { post, recommendPosts, prev, next, showArticleInfo } = props + const { post, recommendPosts, prev, next } = props const url = BLOG.LINK + useRouter().asPath const { locale } = useGlobal() + const showArticleInfo = CONFIG_NEXT.ARTICLE_INFO const date = formatDate(post?.date?.start_date || post?.createdTime, locale.LOCALE) return ( diff --git a/themes/next/components/BlogPostArchive.js b/themes/next/components/BlogPostArchive.js index 91f5527a..a5a1ac6f 100644 --- a/themes/next/components/BlogPostArchive.js +++ b/themes/next/components/BlogPostArchive.js @@ -21,7 +21,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => { {archiveTitle}
      - {posts.map(post => ( + {posts?.map(post => (
    • { ))}
    - ); + ) } } diff --git a/themes/next/components/BlogPostListPage.js b/themes/next/components/BlogPostListPage.js index 6d10433b..773b59a4 100644 --- a/themes/next/components/BlogPostListPage.js +++ b/themes/next/components/BlogPostListPage.js @@ -21,7 +21,7 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
    {/* 文章列表 */}
    - {posts.map(post => ( + {posts?.map(post => ( ))}
    diff --git a/themes/next/components/RecommendPosts.js b/themes/next/components/RecommendPosts.js index 7e680da5..26d9010d 100644 --- a/themes/next/components/RecommendPosts.js +++ b/themes/next/components/RecommendPosts.js @@ -27,6 +27,6 @@ const RecommendPosts = ({ recommendPosts }) => { ))}
- ); + ) } export default RecommendPosts diff --git a/themes/next/config_next.js b/themes/next/config_next.js index d341cee0..b1f311a3 100644 --- a/themes/next/config_next.js +++ b/themes/next/config_next.js @@ -31,7 +31,8 @@ const CONFIG_NEXT = { WIDGET_TOC: true, // 移动端显示悬浮目录 ARTICLE_RELATE_POSTS: true, // 相关文章推荐 - ARTICLE_COPYRIGHT: true // 文章版权声明 + ARTICLE_COPYRIGHT: true, // 文章版权声明 + ARTICLE_INFO: true // 显示文章信息 } diff --git a/themes/next/index.js b/themes/next/index.js deleted file mode 100644 index 45286719..00000000 --- a/themes/next/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import CONFIG_NEXT from './config_next' -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' - -export { - CONFIG_NEXT as THEME_CONFIG, - LayoutIndex, - LayoutSearch, - LayoutArchive, - LayoutSlug, - Layout404, - LayoutCategory, - LayoutCategoryIndex, - LayoutPage, - LayoutTag, - LayoutTagIndex -} diff --git a/themes/nobelium/Layout404.js b/themes/nobelium/Layout404.js index 5f92f0cc..c0992ad3 100644 --- a/themes/nobelium/Layout404.js +++ b/themes/nobelium/Layout404.js @@ -5,3 +5,5 @@ export const Layout404 = (props) => { 404 Not found. } + +export default Layout404 diff --git a/themes/nobelium/LayoutArchive.js b/themes/nobelium/LayoutArchive.js index 4ba92d8a..81ec0781 100644 --- a/themes/nobelium/LayoutArchive.js +++ b/themes/nobelium/LayoutArchive.js @@ -43,3 +43,5 @@ export const LayoutArchive = props => { ) } + +export default LayoutArchive diff --git a/themes/nobelium/LayoutCategory.js b/themes/nobelium/LayoutCategory.js index 6d819185..517a5e82 100644 --- a/themes/nobelium/LayoutCategory.js +++ b/themes/nobelium/LayoutCategory.js @@ -8,3 +8,5 @@ export const LayoutCategory = props => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutCategory diff --git a/themes/nobelium/LayoutCategoryIndex.js b/themes/nobelium/LayoutCategoryIndex.js index 3cf9c10d..6a4f255d 100644 --- a/themes/nobelium/LayoutCategoryIndex.js +++ b/themes/nobelium/LayoutCategoryIndex.js @@ -25,3 +25,5 @@ export const LayoutCategoryIndex = (props) => { ) } + +export default LayoutCategoryIndex diff --git a/themes/nobelium/LayoutIndex.js b/themes/nobelium/LayoutIndex.js index 8bf7541a..d1e74923 100644 --- a/themes/nobelium/LayoutIndex.js +++ b/themes/nobelium/LayoutIndex.js @@ -13,3 +13,5 @@ export const LayoutIndex = props => { ) } + +export default LayoutIndex diff --git a/themes/nobelium/LayoutPage.js b/themes/nobelium/LayoutPage.js index 15355018..184251a8 100644 --- a/themes/nobelium/LayoutPage.js +++ b/themes/nobelium/LayoutPage.js @@ -8,3 +8,5 @@ export const LayoutPage = props => { ) } + +export default LayoutPage diff --git a/themes/nobelium/LayoutSearch.js b/themes/nobelium/LayoutSearch.js index 2da4772c..b1995820 100644 --- a/themes/nobelium/LayoutSearch.js +++ b/themes/nobelium/LayoutSearch.js @@ -54,3 +54,5 @@ export const LayoutSearch = props => { } + +export default LayoutSearch diff --git a/themes/nobelium/LayoutSlug.js b/themes/nobelium/LayoutSlug.js index d27628af..ea2cfb3a 100644 --- a/themes/nobelium/LayoutSlug.js +++ b/themes/nobelium/LayoutSlug.js @@ -31,3 +31,5 @@ export const LayoutSlug = props => { ) } + +export default LayoutSlug diff --git a/themes/nobelium/LayoutTag.js b/themes/nobelium/LayoutTag.js index 2d85004b..55607f00 100644 --- a/themes/nobelium/LayoutTag.js +++ b/themes/nobelium/LayoutTag.js @@ -55,3 +55,5 @@ export const LayoutTag = props => { } + +export default LayoutTag diff --git a/themes/nobelium/LayoutTagIndex.js b/themes/nobelium/LayoutTagIndex.js index 0705c2d6..63ffa7ca 100644 --- a/themes/nobelium/LayoutTagIndex.js +++ b/themes/nobelium/LayoutTagIndex.js @@ -27,3 +27,5 @@ export const LayoutTagIndex = (props) => { ) } + +export default LayoutTagIndex diff --git a/themes/nobelium/index.js b/themes/nobelium/index.js deleted file mode 100644 index dda0f1a2..00000000 --- a/themes/nobelium/index.js +++ /dev/null @@ -1,25 +0,0 @@ -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' - -export { - CONFIG_NOBELIUM as THEME_CONFIG, - LayoutIndex, - LayoutSearch, - LayoutArchive, - LayoutSlug, - Layout404, - LayoutCategory, - LayoutCategoryIndex, - LayoutPage, - LayoutTag, - LayoutTagIndex -} diff --git a/themes/simple/Layout404.js b/themes/simple/Layout404.js index 5f92f0cc..c0992ad3 100644 --- a/themes/simple/Layout404.js +++ b/themes/simple/Layout404.js @@ -5,3 +5,5 @@ export const Layout404 = (props) => { 404 Not found. } + +export default Layout404 diff --git a/themes/simple/LayoutArchive.js b/themes/simple/LayoutArchive.js index 4ba92d8a..81ec0781 100644 --- a/themes/simple/LayoutArchive.js +++ b/themes/simple/LayoutArchive.js @@ -43,3 +43,5 @@ export const LayoutArchive = props => { ) } + +export default LayoutArchive diff --git a/themes/simple/LayoutCategory.js b/themes/simple/LayoutCategory.js index 6d819185..517a5e82 100644 --- a/themes/simple/LayoutCategory.js +++ b/themes/simple/LayoutCategory.js @@ -8,3 +8,5 @@ export const LayoutCategory = props => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutCategory diff --git a/themes/simple/LayoutCategoryIndex.js b/themes/simple/LayoutCategoryIndex.js index a4c19033..d969516b 100644 --- a/themes/simple/LayoutCategoryIndex.js +++ b/themes/simple/LayoutCategoryIndex.js @@ -24,3 +24,5 @@ export const LayoutCategoryIndex = props => { ) } + +export default LayoutCategoryIndex diff --git a/themes/simple/LayoutIndex.js b/themes/simple/LayoutIndex.js index 94eaac2f..18024d9c 100644 --- a/themes/simple/LayoutIndex.js +++ b/themes/simple/LayoutIndex.js @@ -11,3 +11,5 @@ export const LayoutIndex = props => { ) } + +export default LayoutIndex diff --git a/themes/simple/LayoutPage.js b/themes/simple/LayoutPage.js index 15355018..184251a8 100644 --- a/themes/simple/LayoutPage.js +++ b/themes/simple/LayoutPage.js @@ -8,3 +8,5 @@ export const LayoutPage = props => { ) } + +export default LayoutPage diff --git a/themes/simple/LayoutSearch.js b/themes/simple/LayoutSearch.js index 1ba8fef7..597e7c25 100644 --- a/themes/simple/LayoutSearch.js +++ b/themes/simple/LayoutSearch.js @@ -48,3 +48,5 @@ export const LayoutSearch = props => { } + +export default LayoutSearch diff --git a/themes/simple/LayoutSlug.js b/themes/simple/LayoutSlug.js index 96f42c3e..4f6fc66f 100644 --- a/themes/simple/LayoutSlug.js +++ b/themes/simple/LayoutSlug.js @@ -33,3 +33,5 @@ export const LayoutSlug = props => { ) } + +export default LayoutSlug diff --git a/themes/simple/LayoutTag.js b/themes/simple/LayoutTag.js index 06a6d778..f12ae546 100644 --- a/themes/simple/LayoutTag.js +++ b/themes/simple/LayoutTag.js @@ -8,3 +8,5 @@ export const LayoutTag = props => { {BLOG.POST_LIST_STYLE === 'page' ? : } } + +export default LayoutTag diff --git a/themes/simple/LayoutTagIndex.js b/themes/simple/LayoutTagIndex.js index 0705c2d6..63ffa7ca 100644 --- a/themes/simple/LayoutTagIndex.js +++ b/themes/simple/LayoutTagIndex.js @@ -27,3 +27,5 @@ export const LayoutTagIndex = (props) => { ) } + +export default LayoutTagIndex diff --git a/themes/simple/index.js b/themes/simple/index.js deleted file mode 100644 index 7e560470..00000000 --- a/themes/simple/index.js +++ /dev/null @@ -1,25 +0,0 @@ -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' - -export { - CONFIG_SIMPLE as THEME_CONFIG, - LayoutIndex, - LayoutSearch, - LayoutArchive, - LayoutSlug, - Layout404, - LayoutCategory, - LayoutCategoryIndex, - LayoutPage, - LayoutTag, - LayoutTagIndex -}