mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-16 07:26:47 +00:00
Merge pull request #1109 from tangly1024/fix/website-performance
Fix/website performance
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
|
||||
NEXT_PUBLIC_VERSION=3.14.0
|
||||
NEXT_PUBLIC_VERSION=3.15.0
|
||||
@@ -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:
|
||||
|
||||
@@ -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() {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
{/* <div>
|
||||
<div className="font-bold w-18 border-b my-2">
|
||||
主题配置{`config_${debugTheme}.js`}:
|
||||
</div>
|
||||
@@ -106,7 +106,7 @@ export function DebugPanel() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="font-bold w-18 border-b my-2">
|
||||
站点配置[blog.config.js]
|
||||
</div>
|
||||
@@ -128,3 +128,4 @@ export function DebugPanel() {
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default DebugPanel
|
||||
|
||||
58
components/ExternalPlugins.js
Normal file
58
components/ExternalPlugins.js
Normal file
@@ -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) && <ThemeSwitch />}
|
||||
{JSON.parse(BLOG.DEBUG) && <DebugPanel />}
|
||||
{BLOG.ANALYTICS_ACKEE_TRACKER && <Ackee />}
|
||||
{BLOG.ANALYTICS_GOOGLE_ID && <Gtag />}
|
||||
{BLOG.ANALYTICS_VERCEL && <Analytics />}
|
||||
{JSON.parse(BLOG.ANALYTICS_BUSUANZI_ENABLE) && <Busuanzi />}
|
||||
{BLOG.ADSENSE_GOOGLE_ID && <GoogleAdsense />}
|
||||
{BLOG.FACEBOOK_APP_ID && BLOG.FACEBOOK_PAGE_ID && <Messenger />}
|
||||
{JSON.parse(BLOG.FIREWORKS) && <Fireworks />}
|
||||
{JSON.parse(BLOG.SAKURA) && <Sakura />}
|
||||
{JSON.parse(BLOG.STARRY_SKY) && <StarrySky />}
|
||||
{JSON.parse(BLOG.MUSIC_PLAYER) && <MusicPlayer />}
|
||||
{JSON.parse(BLOG.NEST) && <Nest />}
|
||||
{JSON.parse(BLOG.FLUTTERINGRIBBON) && <FlutteringRibbon />}
|
||||
{JSON.parse(BLOG.COMMENT_TWIKOO_COUNT_ENABLE) && <TwikooCommentCounter {...props}/>}
|
||||
{JSON.parse(BLOG.RIBBON) && <Ribbon />}
|
||||
</>
|
||||
}
|
||||
|
||||
export default ExternalPlugin
|
||||
@@ -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 <canvas id='fireworks' className='fireworks'></canvas>
|
||||
}
|
||||
export default Fireworks
|
||||
|
||||
/**
|
||||
* 创建烟花
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <GitalkComponent options={{
|
||||
id: frontMatter.id,
|
||||
title: frontMatter.title,
|
||||
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(','),
|
||||
distractionFreeMode: JSON.parse(BLOG.COMMENT_GITALK_DISTRACTION_FREE_MODE)
|
||||
}} />
|
||||
// return <GitalkComponent options={{
|
||||
// id: frontMatter.id,
|
||||
// title: frontMatter.title,
|
||||
// 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(','),
|
||||
// distractionFreeMode: JSON.parse(BLOG.COMMENT_GITALK_DISTRACTION_FREE_MODE)
|
||||
// }} />
|
||||
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 <div id="gitalk-container"></div>
|
||||
}
|
||||
|
||||
export default Gitalk
|
||||
|
||||
@@ -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 <></>
|
||||
}
|
||||
|
||||
|
||||
25
components/Loading.js
Normal file
25
components/Loading.js
Normal file
@@ -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 <div className="w-screen h-screen flex justify-center items-center bg-black">
|
||||
<i className='mr-5 fas fa-spinner animate-spin text-2xl' />
|
||||
</div>
|
||||
}
|
||||
export default Loading
|
||||
13
components/LoadingCover.js
Normal file
13
components/LoadingCover.js
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
/**
|
||||
* 加载文件时的全局遮罩
|
||||
* @returns
|
||||
*/
|
||||
const LoadingCover = (props) => {
|
||||
const { onReading } = props
|
||||
|
||||
return <div className={`${onReading ? 'opacity-90' : 'opacity-0'} transition-all fixed top-0 left-0 pointer-events-none duration-1000 z-50 shadow-inner w-screen h-screen flex justify-center items-center bg-gray-400 dark:bg-black text-white shadow-text`}>
|
||||
<i className='text-2xl mr-5 fas fa-spinner animate-spin' />
|
||||
</div>
|
||||
}
|
||||
export default LoadingCover
|
||||
@@ -1,7 +0,0 @@
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
const MusicPlayer = dynamic(
|
||||
() => import('@/components/Player'),
|
||||
{ ssr: false }
|
||||
)
|
||||
export default MusicPlayer
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { Valine } from 'react-valine'
|
||||
|
||||
export default Valine
|
||||
@@ -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 <div id='v-wrapper'>
|
||||
<div id='v-comments'></div>
|
||||
</div>
|
||||
|
||||
return <div id="valine"></div>
|
||||
|
||||
// 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 <div id='v-wrapper'>
|
||||
// <div id='v-comments'></div>
|
||||
// </div>
|
||||
}
|
||||
|
||||
export default ValineComponent
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"paths": {
|
||||
"@/*": ["./*"],
|
||||
"@/components/*": ["components/*"],
|
||||
"@/theme/*": ["theme/*"],
|
||||
"@/data/*": ["data/*"],
|
||||
"@/lib/*": ["lib/*"],
|
||||
"@/styles/*": ["styles/*"]
|
||||
|
||||
@@ -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 (
|
||||
<GlobalContext.Provider value={
|
||||
{
|
||||
onLoading,
|
||||
changeLoadingState,
|
||||
locale,
|
||||
updateLocale,
|
||||
isDarkMode,
|
||||
updateDarkMode,
|
||||
theme,
|
||||
setTheme,
|
||||
switchTheme,
|
||||
changeTheme
|
||||
}
|
||||
}>
|
||||
<GlobalContext.Provider value={{
|
||||
onLoading,
|
||||
setOnLoading,
|
||||
locale,
|
||||
updateLocale,
|
||||
isDarkMode,
|
||||
updateDarkMode,
|
||||
theme,
|
||||
setTheme,
|
||||
switchTheme,
|
||||
changeTheme,
|
||||
setOnReading
|
||||
}}>
|
||||
<LoadingCover onReading={onReading} setOnReading={setOnReading}/>
|
||||
{children}
|
||||
</GlobalContext.Provider>
|
||||
)
|
||||
|
||||
0
lib/memorize.js
Normal file
0
lib/memorize.js
Normal file
@@ -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 => {
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -172,5 +172,9 @@ function generateCustomizeUrl(postProperties) {
|
||||
fullSlug += '/'
|
||||
}
|
||||
})
|
||||
if (fullSlug.startsWith('/')) {
|
||||
fullSlug = fullSlug.substring(1) // 去掉头部的"/"
|
||||
}
|
||||
|
||||
return `${fullSlug}/${(postProperties.slug ?? postProperties.id)}`
|
||||
}
|
||||
|
||||
15
lib/theme.js
15
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
|
||||
|
||||
10
lib/utils.js
10
lib/utils.js
@@ -1,5 +1,15 @@
|
||||
// 封装异步加载资源的方法
|
||||
import { memo } from 'react'
|
||||
|
||||
/**
|
||||
* 组件持久化
|
||||
*/
|
||||
export const memorize = (Component) => {
|
||||
const MemoizedComponent = (props) => {
|
||||
return <Component {...props} />
|
||||
}
|
||||
return memo(MemoizedComponent)
|
||||
}
|
||||
/**
|
||||
* 加载外部资源
|
||||
* @param url 地址 例如 https://xx.com/xx.js
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 <ThemeComponents.Layout404 {...props} meta={meta}/>
|
||||
const Layout404 = dynamic(() => import(`@/themes/${theme}/Layout404`))
|
||||
return <Layout404 {...props} meta={meta}/>
|
||||
}
|
||||
|
||||
export async function getStaticProps () {
|
||||
|
||||
@@ -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 <ThemeComponents.LayoutSlug {...props} showArticleInfo={true} meta={meta} />
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证文章密码
|
||||
* @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 (
|
||||
<ThemeComponents.LayoutSlug {...props} showArticleInfo={true} meta={meta} />
|
||||
)
|
||||
return <Suspense fallback={<Loading />}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
|
||||
@@ -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 <link> 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) && <ThemeSwitch />}
|
||||
{JSON.parse(BLOG.DEBUG) && <DebugPanel />}
|
||||
{BLOG.ANALYTICS_ACKEE_TRACKER && <Ackee />}
|
||||
{BLOG.ANALYTICS_GOOGLE_ID && <Gtag />}
|
||||
{BLOG.ANALYTICS_VERCEL && <Analytics />}
|
||||
{JSON.parse(BLOG.ANALYTICS_BUSUANZI_ENABLE) && <Busuanzi />}
|
||||
{BLOG.ADSENSE_GOOGLE_ID && <GoogleAdsense />}
|
||||
{BLOG.FACEBOOK_APP_ID && BLOG.FACEBOOK_PAGE_ID && <Messenger />}
|
||||
{JSON.parse(BLOG.FIREWORKS) && <Fireworks />}
|
||||
{JSON.parse(BLOG.SAKURA) && <Sakura />}
|
||||
{JSON.parse(BLOG.STARRY_SKY) && <StarrySky />}
|
||||
{JSON.parse(BLOG.MUSIC_PLAYER) && <MusicPlayer />}
|
||||
{JSON.parse(BLOG.NEST) && <Nest />}
|
||||
{JSON.parse(BLOG.FLUTTERINGRIBBON) && <FlutteringRibbon />}
|
||||
{JSON.parse(BLOG.COMMENT_TWIKOO_COUNT_ENABLE) && <TwikooCommentCounter {...pageProps}/>}
|
||||
{JSON.parse(BLOG.RIBBON) && <Ribbon />}
|
||||
<ExternalScript/>
|
||||
</>
|
||||
|
||||
useEffect(() => {
|
||||
AOS.init()
|
||||
if (isMobile()) {
|
||||
@@ -71,7 +34,8 @@ const MyApp = ({ Component, pageProps }) => {
|
||||
return (
|
||||
<GlobalContextProvider>
|
||||
<Component {...pageProps} />
|
||||
{externalPlugins}
|
||||
<ExternalPlugins {...pageProps}/>
|
||||
<ExternalScript/>
|
||||
</GlobalContextProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 <ThemeComponents.LayoutArchive {...props} meta={meta} />
|
||||
props = { ...props, meta }
|
||||
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -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 <ThemeComponents.Layout404 {...props} />
|
||||
}
|
||||
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 <ThemeComponents.LayoutCategory {...props} meta={meta} />
|
||||
|
||||
props = { ...props, meta }
|
||||
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
export async function getStaticProps({ params: { category } }) {
|
||||
|
||||
@@ -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 <ThemeComponents.Layout404 {...props} />
|
||||
}
|
||||
|
||||
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 <ThemeComponents.LayoutCategory {...props} meta={meta} />
|
||||
|
||||
props = { ...props, meta }
|
||||
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
export async function getStaticProps({ params: { category, page } }) {
|
||||
|
||||
@@ -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 <ThemeComponents.LayoutCategoryIndex {...props} meta={meta} />
|
||||
props = { ...props, meta }
|
||||
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -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 <ThemeComponents.LayoutIndex {...props} />
|
||||
const [Layout, setLayoutIndex] = useState(DefaultLayout)
|
||||
useEffect(() => {
|
||||
const loadLayout = async () => {
|
||||
setLayoutIndex(dynamic(() => import(`@/themes/${theme}/LayoutIndex`)))
|
||||
}
|
||||
console.log(loadLayout)
|
||||
// loadLayout()
|
||||
}, [theme])
|
||||
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 <ThemeComponents.LayoutPage {...props} meta={meta} />
|
||||
|
||||
props = { ...props, meta }
|
||||
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
|
||||
@@ -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 (
|
||||
<ThemeComponents.LayoutSearch
|
||||
{...props}
|
||||
meta={meta}
|
||||
currentSearch={keyword}
|
||||
/>
|
||||
)
|
||||
|
||||
props = { ...props, meta }
|
||||
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 (
|
||||
<ThemeComponents.LayoutSearch
|
||||
{...props}
|
||||
meta={meta}
|
||||
currentSearch={keyword}
|
||||
/>
|
||||
)
|
||||
|
||||
props = { ...props, meta, currentSearch: keyword }
|
||||
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 (
|
||||
<ThemeComponents.LayoutSearch
|
||||
{...props}
|
||||
posts={filteredPosts}
|
||||
currentSearch={searchKey}
|
||||
meta={meta}
|
||||
/>
|
||||
)
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 <ThemeComponents.Layout404 {...props} />
|
||||
}
|
||||
// 切换主题
|
||||
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 <ThemeComponents.LayoutTag {...props} meta={meta} />
|
||||
props = { ...props, meta }
|
||||
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
export async function getStaticProps({ params: { tag } }) {
|
||||
|
||||
@@ -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 <ThemeComponents.Layout404 {...props} />
|
||||
}
|
||||
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 <ThemeComponents.LayoutTag {...props} meta={meta} />
|
||||
props = { ...props, meta }
|
||||
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
export async function getStaticProps({ params: { tag, page } }) {
|
||||
|
||||
@@ -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 <ThemeComponents.LayoutTagIndex {...props} meta={meta} />
|
||||
props = { ...props, meta }
|
||||
|
||||
return <Suspense fallback={<Loading/>}>
|
||||
<Layout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -5,3 +5,5 @@ export const Layout404 = (props) => {
|
||||
404 Not found.
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default Layout404
|
||||
|
||||
@@ -43,3 +43,5 @@ export const LayoutArchive = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutArchive
|
||||
|
||||
@@ -8,3 +8,5 @@ export const LayoutCategory = props => {
|
||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />}
|
||||
</LayoutBase >
|
||||
}
|
||||
|
||||
export default LayoutCategory
|
||||
|
||||
@@ -24,3 +24,5 @@ export const LayoutCategoryIndex = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutCategoryIndex
|
||||
|
||||
@@ -11,3 +11,5 @@ export const LayoutIndex = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutIndex
|
||||
|
||||
@@ -8,3 +8,5 @@ export const LayoutPage = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutPage
|
||||
|
||||
@@ -29,3 +29,5 @@ export const LayoutSlug = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutSlug
|
||||
|
||||
@@ -8,3 +8,5 @@ export const LayoutTag = props => {
|
||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />}
|
||||
</LayoutBase >
|
||||
}
|
||||
|
||||
export default LayoutTag
|
||||
|
||||
@@ -27,3 +27,5 @@ export const LayoutTagIndex = (props) => {
|
||||
</div> </LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutTagIndex
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -3,3 +3,5 @@ import LayoutBase from './LayoutBase'
|
||||
export const Layout404 = props => {
|
||||
return <LayoutBase {...props}>404</LayoutBase>
|
||||
}
|
||||
|
||||
export default Layout404
|
||||
|
||||
@@ -28,3 +28,5 @@ export const LayoutArchive = (props) => {
|
||||
</div>
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutArchive
|
||||
|
||||
@@ -8,3 +8,5 @@ export const LayoutCategory = props => {
|
||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props}/>}
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutCategory
|
||||
|
||||
@@ -31,3 +31,5 @@ export const LayoutCategoryIndex = (props) => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutCategoryIndex
|
||||
|
||||
@@ -8,3 +8,5 @@ export const LayoutIndex = (props) => {
|
||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props}/>}
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutIndex
|
||||
|
||||
@@ -8,3 +8,5 @@ export const LayoutPage = (props) => {
|
||||
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutPage
|
||||
|
||||
@@ -28,3 +28,5 @@ export const LayoutSearch = (props) => {
|
||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props}/>}
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutSearch
|
||||
|
||||
@@ -11,3 +11,5 @@ export const LayoutSlug = (props) => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutSlug
|
||||
|
||||
@@ -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' ? <BlogListPage {...props} /> : <BlogListScroll {...props}/>}
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutTag
|
||||
|
||||
@@ -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) => {
|
||||
</div>
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutTagIndex
|
||||
|
||||
@@ -21,7 +21,7 @@ const BlogArchiveItem = ({ posts = [], archiveTitle }) => {
|
||||
{archiveTitle}
|
||||
</div>
|
||||
<ul>
|
||||
{posts.map(post => (
|
||||
{posts?.map(post => (
|
||||
<li
|
||||
key={post.id}
|
||||
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-gray-500 dark:hover:border-gray-300 dark:border-gray-400 transform duration-500"
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import CONFIG_FUKA from './config_fuka'
|
||||
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_FUKA as THEME_CONFIG,
|
||||
LayoutIndex,
|
||||
LayoutSearch,
|
||||
LayoutArchive,
|
||||
LayoutSlug,
|
||||
Layout404,
|
||||
LayoutCategory,
|
||||
LayoutCategoryIndex,
|
||||
LayoutPage,
|
||||
LayoutTag,
|
||||
LayoutTagIndex
|
||||
}
|
||||
@@ -30,3 +30,4 @@ export const Layout404 = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
export default Layout404
|
||||
|
||||
@@ -32,3 +32,5 @@ export const LayoutArchive = (props) => {
|
||||
</Card>
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutArchive
|
||||
|
||||
@@ -13,3 +13,5 @@ export const LayoutCategory = props => {
|
||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutCategory
|
||||
|
||||
@@ -37,3 +37,5 @@ export const LayoutCategoryIndex = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutCategoryIndex
|
||||
|
||||
@@ -12,3 +12,5 @@ export const LayoutIndex = (props) => {
|
||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutIndex
|
||||
|
||||
@@ -6,3 +6,5 @@ export const LayoutPage = (props) => {
|
||||
<BlogPostListPage {...props}/>
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutPage
|
||||
|
||||
@@ -97,3 +97,5 @@ export const LayoutSearch = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutSearch
|
||||
|
||||
@@ -93,3 +93,5 @@ export const LayoutSlug = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutSlug
|
||||
|
||||
@@ -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) => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutTag
|
||||
|
||||
@@ -26,3 +26,5 @@ export const LayoutTagIndex = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutTagIndex
|
||||
|
||||
@@ -21,7 +21,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => {
|
||||
{archiveTitle}
|
||||
</div>
|
||||
<ul>
|
||||
{posts.map(post => (
|
||||
{posts?.map(post => (
|
||||
<li
|
||||
key={post.id}
|
||||
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-indigo-500 dark:hover:border-indigo-300 dark:border-indigo-400 transform duration-500"
|
||||
@@ -42,7 +42,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => {
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 && (
|
||||
<div className="md:w-5/12 overflow-hidden">
|
||||
<Link href={`/${post.slug}`} passHref legacyBehavior>
|
||||
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
|
||||
<div className='h-56 bg-center bg-cover hover:scale-110 duration-200' style={{ backgroundImage: `url('${post?.page_cover}')` }} />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -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
|
||||
<div>
|
||||
{/* 标题 */}
|
||||
<Link
|
||||
href={`/${post.slug}`}
|
||||
href={`${BLOG.SUB_PATH}/${post.slug}`}
|
||||
passHref
|
||||
className={`replace cursor-pointer hover:underline text-2xl ${showPreview ? 'text-center' : ''
|
||||
} leading-tight font-normal text-gray-600 dark:text-gray-100 hover:text-indigo-700 dark:hover:text-indigo-400`}>
|
||||
|
||||
@@ -21,7 +21,7 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
<div id="container" className='w-full'>
|
||||
{/* 文章列表 */}
|
||||
<div className="space-y-6 px-2">
|
||||
{posts.map(post => (
|
||||
{posts?.map(post => (
|
||||
<BlogPostCard index={posts.indexOf(post)} key={post.id} post={post} siteInfo={siteInfo}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -21,7 +21,11 @@ export default function HeaderArticle({ post, siteInfo }) {
|
||||
return (
|
||||
<div
|
||||
id="header"
|
||||
className="w-full h-96 relative md:flex-shrink-0 overflow-hidden bg-cover bg-center bg-no-repeat animate__animated animate__fadeIn z-10"
|
||||
data-aos="fade-down"
|
||||
data-aos-duration="300"
|
||||
data-aos-once="true"
|
||||
data-aos-anchor-placement="top-bottom"
|
||||
className="w-full h-96 relative md:flex-shrink-0 overflow-hidden bg-cover bg-center bg-no-repeat z-10"
|
||||
style={{ backgroundImage: headerImage }}
|
||||
>
|
||||
<header id='article-header-cover'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import React from 'react'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
/**
|
||||
* 侧边栏抽屉面板,可以从侧面拉出
|
||||
@@ -8,7 +8,7 @@ import React from 'react'
|
||||
*/
|
||||
const SideBarDrawer = ({ children, isOpen, onOpen, onClose, className }) => {
|
||||
const router = useRouter()
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
const sideBarDrawerRouteListener = () => {
|
||||
switchSideDrawerVisible(false)
|
||||
}
|
||||
@@ -29,11 +29,11 @@ const SideBarDrawer = ({ children, isOpen, onOpen, onClose, className }) => {
|
||||
const sideBarDrawerBackground = window.document.getElementById('sidebar-drawer-background')
|
||||
|
||||
if (showStatus) {
|
||||
sideBarDrawer.classList.replace('-mr-72', 'mr-0')
|
||||
sideBarDrawerBackground.classList.replace('hidden', 'block')
|
||||
sideBarDrawer?.classList.replace('-mr-72', 'mr-0')
|
||||
sideBarDrawerBackground?.classList.replace('hidden', 'block')
|
||||
} else {
|
||||
sideBarDrawer.classList.replace('mr-0', '-mr-72')
|
||||
sideBarDrawerBackground.classList.replace('block', 'hidden')
|
||||
sideBarDrawer?.classList.replace('mr-0', '-mr-72')
|
||||
sideBarDrawerBackground?.classList.replace('block', 'hidden')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const CONFIG_HEXO = {
|
||||
HOME_BANNER_ENABLE: true,
|
||||
// 3.14.1以后的版本中,欢迎语在blog.config.js中配置,用英文逗号','隔开多个。
|
||||
HOME_BANNER_GREETINGS: ['Hi,我是一个程序员', 'Hi,我是一个打工人', 'Hi,我是一个干饭人', '欢迎来到我的博客🎉'], // 首页大图标语文字
|
||||
|
||||
HOME_NAV_BUTTONS: true, // 首页是否显示分类大图标按钮
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import CONFIG_HEXO from './config_hexo'
|
||||
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_HEXO as THEME_CONFIG,
|
||||
LayoutIndex,
|
||||
LayoutSearch,
|
||||
LayoutArchive,
|
||||
LayoutSlug,
|
||||
Layout404,
|
||||
LayoutCategory,
|
||||
LayoutCategoryIndex,
|
||||
LayoutPage,
|
||||
LayoutTag,
|
||||
LayoutTagIndex
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* 切换主题请修改 blog.config.js 中的 THEME 字段
|
||||
*/
|
||||
import * as next from './next'
|
||||
import * as fukasawa from './fukasawa'
|
||||
import * as hexo from './hexo'
|
||||
import * as medium from './medium'
|
||||
import * as nobelium from './nobelium'
|
||||
import * as matery from './matery'
|
||||
import * as example from './example'
|
||||
import * as simple from './simple'
|
||||
|
||||
export const ALL_THEME = [
|
||||
'hexo',
|
||||
'matery',
|
||||
'next',
|
||||
'medium',
|
||||
'fukasawa',
|
||||
'nobelium',
|
||||
'example',
|
||||
'simple'
|
||||
]
|
||||
export {
|
||||
hexo,
|
||||
next,
|
||||
medium,
|
||||
fukasawa,
|
||||
nobelium,
|
||||
matery,
|
||||
example,
|
||||
simple
|
||||
}
|
||||
@@ -30,3 +30,5 @@ export const Layout404 = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default Layout404
|
||||
|
||||
@@ -32,3 +32,5 @@ export const LayoutArchive = (props) => {
|
||||
</Card>
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutArchive
|
||||
|
||||
@@ -36,3 +36,5 @@ export const LayoutCategory = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutCategory
|
||||
|
||||
@@ -30,3 +30,5 @@ export const LayoutCategoryIndex = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutCategoryIndex
|
||||
|
||||
@@ -12,3 +12,5 @@ export const LayoutIndex = (props) => {
|
||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutIndex
|
||||
|
||||
@@ -6,3 +6,5 @@ export const LayoutPage = (props) => {
|
||||
<BlogPostListPage {...props}/>
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutPage
|
||||
|
||||
@@ -97,3 +97,5 @@ export const LayoutSearch = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutSearch
|
||||
|
||||
@@ -128,3 +128,5 @@ export const LayoutSlug = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutSlug
|
||||
|
||||
@@ -6,7 +6,6 @@ import React from 'react'
|
||||
import HeaderArticle from './components/HeaderArticle'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import TagItemMiddle from './components/TagItemMiddle'
|
||||
import TagItemMini from './components/TagItemMini'
|
||||
|
||||
export const LayoutTag = (props) => {
|
||||
const { tagOptions, tag } = props
|
||||
@@ -41,3 +40,5 @@ export const LayoutTag = (props) => {
|
||||
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
export default LayoutTag
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import HeaderArticle from './components/HeaderArticle'
|
||||
import TagItemMiddle from './components/TagItemMiddle'
|
||||
import TagItemMini from './components/TagItemMini'
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutTagIndex = props => {
|
||||
@@ -31,3 +30,5 @@ export const LayoutTagIndex = props => {
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutTagIndex
|
||||
|
||||
@@ -21,7 +21,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => {
|
||||
{archiveTitle}
|
||||
</div>
|
||||
<ul>
|
||||
{posts.map(post => (
|
||||
{posts?.map(post => (
|
||||
<li
|
||||
key={post.id}
|
||||
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-indigo-500 dark:hover:border-indigo-300 dark:border-indigo-400 transform duration-500"
|
||||
|
||||
@@ -22,7 +22,7 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
<div className='pt-6'></div>
|
||||
{/* 文章列表 */}
|
||||
<div className="pt-4 flex flex-wrap pb-12" >
|
||||
{posts.map(post => (
|
||||
{posts?.map(post => (
|
||||
<div key={post.id} className='xl:w-1/3 md:w-1/2 w-full p-4'> <BlogPostCard index={posts.indexOf(post)} post={post} siteInfo={siteInfo} /></div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user