import BLOG from '@/blog.config' import useNotification from '@/components/Notification' import OpenWrite from '@/components/OpenWrite' import { siteConfig } from '@/lib/config' import { getGlobalData, getPost, getPostBlocks } from '@/lib/db/getSiteData' import { useGlobal } from '@/lib/global' import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents' import { getPasswordQuery } from '@/lib/password' import { uploadDataToAlgolia } from '@/lib/plugins/algolia' import { checkSlugHasNoSlash, getRecommendPost } from '@/lib/utils/post' import { DynamicLayout } from '@/themes/theme' import md5 from 'js-md5' import { useRouter } from 'next/router' import { idToUuid } from 'notion-utils' import { useEffect, useState } from 'react' /** * 根据notion的slug访问页面 * 只解析一级目录例如 /about * @param {*} props * @returns */ const Slug = props => { const { post } = props const router = useRouter() const { locale } = useGlobal() // 文章锁🔐 const [lock, setLock] = useState(post?.password && post?.password !== '') const { showNotification, Notification } = useNotification() /** * 验证文章密码 * @param {*} passInput */ const validPassword = passInput => { if (!post) { return false } const encrypt = md5(post?.slug + passInput) if (passInput && encrypt === post?.password) { setLock(false) // 输入密码存入localStorage,下次自动提交 localStorage.setItem('password_' + router.asPath, passInput) showNotification(locale.COMMON.ARTICLE_UNLOCK_TIPS) // 设置解锁成功提示显示 return true } return false } // 文章加载 useEffect(() => { // 文章加密 if (post?.password && post?.password !== '') { setLock(true) } else { setLock(false) } // 读取上次记录 自动提交密码 const passInputs = getPasswordQuery(router.asPath) if (passInputs.length > 0) { for (const passInput of passInputs) { if (validPassword(passInput)) { break // 密码验证成功,停止尝试 } } } }, [post]) // 文章加载 useEffect(() => { if (lock) { return } // 文章解锁后生成目录与内容 if (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) } }, [router, lock]) props = { ...props, lock, validPassword } const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG) return ( <> {/* 文章布局 */} {/* 解锁密码提示框 */} {post?.password && post?.password !== '' && !lock && } {/* 导流工具 */} ) } export async function getStaticPaths() { if (!BLOG.isProd) { return { paths: [], fallback: true } } const from = 'slug-paths' const { allPages } = await getGlobalData({ from }) const paths = allPages ?.filter(row => checkSlugHasNoSlash(row)) .map(row => ({ params: { prefix: row.slug } })) return { paths: paths, fallback: true } } export async function getStaticProps({ params: { prefix }, locale }) { let fullSlug = prefix const from = `slug-props-${fullSlug}` const props = await getGlobalData({ from, locale }) if (siteConfig('PSEUDO_STATIC', false, props.NOTION_CONFIG)) { if (!fullSlug.endsWith('.html')) { fullSlug += '.html' } } // 在列表内查找文章 props.post = props?.allPages?.find(p => { return ( p.type.indexOf('Menu') < 0 && (p.slug === prefix || p.id === idToUuid(prefix)) ) }) // 处理非列表内文章的内信息 if (!props?.post) { const pageId = prefix if (pageId.length >= 32) { const post = await getPost(pageId) props.post = post } } // 无法获取文章 if (!props?.post) { props.post = null return { props, revalidate: process.env.EXPORT ? undefined : siteConfig( 'NEXT_REVALIDATE_SECOND', BLOG.NEXT_REVALIDATE_SECOND, props.NOTION_CONFIG ) } } // 文章内容加载 if (!props?.post?.blockMap) { props.post.blockMap = await getPostBlocks(props.post.id, from) } // 目录默认加载 if (props.post?.blockMap?.block) { props.post.content = Object.keys(props.post.blockMap.block).filter( key => props.post.blockMap.block[key]?.value?.parent_id === props.post.id ) props.post.toc = getPageTableOfContents(props.post, props.post.blockMap) } // 生成全文索引 && process.env.npm_lifecycle_event === 'build' && JSON.parse(BLOG.ALGOLIA_RECREATE_DATA) if (BLOG.ALGOLIA_APP_ID) { uploadDataToAlgolia(props?.post) } // 推荐关联文章处理 const allPosts = props.allPages?.filter( page => page.type === 'Post' && page.status === 'Published' ) if (allPosts && allPosts.length > 0) { const index = allPosts.indexOf(props.post) props.prev = allPosts.slice(index - 1, index)[0] ?? allPosts.slice(-1)[0] props.next = allPosts.slice(index + 1, index + 2)[0] ?? allPosts[0] props.recommendPosts = getRecommendPost( props.post, allPosts, siteConfig('POST_RECOMMEND_COUNT') ) } else { props.prev = null props.next = null props.recommendPosts = [] } delete props.allPages return { props, revalidate: process.env.EXPORT ? undefined : siteConfig( 'NEXT_REVALIDATE_SECOND', BLOG.NEXT_REVALIDATE_SECOND, props.NOTION_CONFIG ) } } export default Slug