diff --git a/lib/notion/getNotionData.js b/lib/notion/getNotionData.js index 11913b2d..80444cdb 100644 --- a/lib/notion/getNotionData.js +++ b/lib/notion/getNotionData.js @@ -212,17 +212,16 @@ async function getPageRecordMapByNotionAPI({ pageId, from }) { collectionData.push(properties) } } - // 读取映射 配置 - let postCount = 0 // 获取page作为自定义菜单 const customNav = getCustomNav({ allPages: collectionData.filter(post => post.type === 'Page' && post.status === 'Published') }) + // 文章计数 + let postCount = 0 const allPages = collectionData.filter(post => { if (post.type === 'Post' && post.status === 'Published') { postCount++ } - return post && post.type && (post.type === 'Post' || post.type === 'Page') && diff --git a/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js index f4ee3282..ef93f84b 100644 --- a/lib/notion/getPageProperties.js +++ b/lib/notion/getPageProperties.js @@ -3,6 +3,7 @@ import { NotionAPI } from 'notion-client' import BLOG from '@/blog.config' import formatDate from '../formatDate' import { defaultMapImageUrl } from 'react-notion-x' +import md5 from 'js-md5' export default async function getPageProperties(id, block, schema, authToken, tagOptions, siteInfo) { const rawProperties = Object.entries(block?.[id]?.value?.properties || []) @@ -89,6 +90,7 @@ export default async function getPageProperties(id, block, schema, authToken, ta properties.pageIcon = getImageUrl(block[id].value?.format?.page_icon, block[id].value) ?? '' properties.page_cover = getImageUrl(block[id].value?.format?.page_cover, block[id].value) ?? siteInfo?.pageCover properties.content = value.content ?? [] + properties.password = properties.password ? md5(properties.slug + properties.password) : '' properties.tagItems = properties?.tags?.map(tag => { return { name: tag, color: tagOptions?.find(t => t.value === tag)?.color || 'gray' } }) || [] diff --git a/lib/notion/getPageTableOfContents.js b/lib/notion/getPageTableOfContents.js new file mode 100644 index 00000000..a23be7cb --- /dev/null +++ b/lib/notion/getPageTableOfContents.js @@ -0,0 +1,90 @@ +import { getTextContent } from 'notion-utils' + +const indentLevels = { + header: 0, + sub_header: 1, + sub_sub_header: 2 +} + +/** + * @see https://github.com/NotionX/react-notion-x/blob/master/packages/notion-utils/src/get-page-table-of-contents.ts + * Gets the metadata for a table of contents block by parsing the page's + * H1, H2, and H3 elements. + */ +export const getPageTableOfContents = (page, recordMap) => { + const contents = (page.content ?? []) + const toc = getBlockHeader(contents, recordMap) + const indentLevelStack = [ + { + actual: -1, + effective: -1 + } + ] + + // Adjust indent levels to always change smoothly. + // This is a little tricky, but the key is that when increasing indent levels, + // they should never jump more than one at a time. + for (const tocItem of toc) { + const { indentLevel } = tocItem + const actual = indentLevel + + do { + const prevIndent = indentLevelStack[indentLevelStack.length - 1] + const { actual: prevActual, effective: prevEffective } = prevIndent + + if (actual > prevActual) { + tocItem.indentLevel = prevEffective + 1 + indentLevelStack.push({ + actual, + effective: tocItem.indentLevel + }) + } else if (actual === prevActual) { + tocItem.indentLevel = prevEffective + break + } else { + indentLevelStack.pop() + } + + // eslint-disable-next-line no-constant-condition + } while (true) + } + + return toc +} + +/** + * 重写获取目录方法 + */ +function getBlockHeader(contents, recordMap, toc) { + if (!toc) { + toc = [] + } + if (!contents) { + return toc + } + + for (const blockId of contents) { + const block = recordMap.block[blockId]?.value + if (!block) { + continue + } + const { type } = block + if (type.indexOf('header') >= 0) { + const existed = toc.find(e => e.id === blockId) + if (!existed) { + toc.push({ + id: blockId, + type, + text: getTextContent(block.properties?.title), + indentLevel: indentLevels[type] + }) + } + } + + if (block.content?.length > 0) { + getBlockHeader(block.content, recordMap, toc) + } + } + + return toc +} diff --git a/package.json b/package.json index c9e3b948..f022f9d0 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "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", diff --git a/pages/[...slug].js b/pages/[...slug].js index c790f211..6ca98c93 100644 --- a/pages/[...slug].js +++ b/pages/[...slug].js @@ -8,6 +8,8 @@ import { idToUuid } from 'notion-utils' import Router from 'next/router' import { isBrowser } from '@/lib/utils' import { getNotion } from '@/lib/notion/getNotion' +import md5 from 'js-md5' +import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents' /** * 根据notion的slug访问页面 @@ -28,6 +30,11 @@ const Slug = props => { if (post?.password && post?.password !== '') { setLock(true) } else { + if (!lock && post?.blockMap?.block) { + post.content = Object.keys(post.blockMap.block) + post.toc = getPageTableOfContents(post, post.blockMap) + } + setLock(false) } }, [post]) @@ -51,10 +58,12 @@ const Slug = props => { * 验证文章密码 * @param {*} result */ - const validPassword = result => { - if (result) { + const validPassword = passInput => { + if (passInput && md5(post.slug + passInput) === post.password) { setLock(false) + return true } + return false } props = { ...props, lock, setLock, validPassword } diff --git a/styles/notion.css b/styles/notion.css index 92acdb96..d55d8456 100644 --- a/styles/notion.css +++ b/styles/notion.css @@ -392,7 +392,7 @@ .notion-h { position: relative; - display: block; + /* display: block; */ font-weight: 600; line-height: 1.3; padding: 3px 2px; @@ -427,7 +427,7 @@ margin-top: 2px; } */ .notion-h2 { - font-size: 1.5em; + font-size: 1.4em; margin-top: 1.1em; } .notion-h3 { diff --git a/themes/example/LayoutSlug.js b/themes/example/LayoutSlug.js index 1f7fd409..b16892b7 100644 --- a/themes/example/LayoutSlug.js +++ b/themes/example/LayoutSlug.js @@ -1,4 +1,3 @@ -import { getPageTableOfContents } from 'notion-utils' import LayoutBase from './LayoutBase' import { ArticleLock } from './components/ArticleLock' import NotionPage from '@/components/NotionPage' @@ -12,15 +11,10 @@ export const LayoutSlug = props => { return } - if (!lock && post?.blockMap?.block) { - post.content = Object.keys(post.blockMap.block) - post.toc = getPageTableOfContents(post, post.blockMap) - } - return ( - {lock && } + {lock && } {!lock &&
diff --git a/themes/example/components/ArticleLock.js b/themes/example/components/ArticleLock.js index a9f5f59d..43b6647e 100644 --- a/themes/example/components/ArticleLock.js +++ b/themes/example/components/ArticleLock.js @@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global' * @returns */ export const ArticleLock = props => { - const { password, validPassword } = props + const { validPassword } = props const { locale } = useGlobal() const submitPassword = () => { const p = document.getElementById('password') - if (p && p.value && p.value === password) { - validPassword(true) - } else { + if (!validPassword(p?.value)) { const tips = document.getElementById('tips') if (tips) { tips.innerHTML = '' diff --git a/themes/fukasawa/LayoutSlug.js b/themes/fukasawa/LayoutSlug.js index 30265a6c..fb78690c 100644 --- a/themes/fukasawa/LayoutSlug.js +++ b/themes/fukasawa/LayoutSlug.js @@ -1,19 +1,13 @@ -import { getPageTableOfContents } from 'notion-utils' import ArticleDetail from './components/ArticleDetail' import LayoutBase from './LayoutBase' import { ArticleLock } from './components/ArticleLock' export const LayoutSlug = (props) => { - const { post, lock, validPassword } = props - if (!lock && post?.blockMap?.block) { - post.content = Object.keys(post.blockMap.block) - post.toc = getPageTableOfContents(post, post.blockMap) - } - + const { lock, validPassword } = props return ( {!lock && } - {lock && } + {lock && } ) } diff --git a/themes/fukasawa/components/ArticleLock.js b/themes/fukasawa/components/ArticleLock.js index 23112eeb..8ae18a4e 100644 --- a/themes/fukasawa/components/ArticleLock.js +++ b/themes/fukasawa/components/ArticleLock.js @@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global' * @returns */ export const ArticleLock = props => { - const { password, validPassword } = props + const { validPassword } = props const { locale } = useGlobal() const submitPassword = () => { const p = document.getElementById('password') - if (p && p.value && p.value === password) { - validPassword(true) - } else { + if (!validPassword(p?.value)) { const tips = document.getElementById('tips') if (tips) { tips.innerHTML = '' diff --git a/themes/hexo/LayoutSlug.js b/themes/hexo/LayoutSlug.js index 7875c990..327497ac 100644 --- a/themes/hexo/LayoutSlug.js +++ b/themes/hexo/LayoutSlug.js @@ -1,4 +1,3 @@ -import { getPageTableOfContents } from 'notion-utils' import { useRef } from 'react' import { ArticleLock } from './components/ArticleLock' import HeaderArticle from './components/HeaderArticle' @@ -15,6 +14,7 @@ import { isBrowser } from '@/lib/utils' export const LayoutSlug = props => { const { post, lock, validPassword } = props + const drawerRight = useRef(null) if (!post) { return { > } - if (!lock && post?.blockMap?.block) { - post.content = Object.keys(post.blockMap.block) - post.toc = getPageTableOfContents(post, post.blockMap) - } - - const drawerRight = useRef(null) const targetRef = isBrowser() ? document.getElementById('container') : null const floatSlot = <> @@ -53,7 +47,7 @@ export const LayoutSlug = props => { floatSlot={floatSlot} >
- {lock && } + {lock && } {!lock &&
diff --git a/themes/hexo/components/ArticleLock.js b/themes/hexo/components/ArticleLock.js index 84ef905f..1a1bd193 100644 --- a/themes/hexo/components/ArticleLock.js +++ b/themes/hexo/components/ArticleLock.js @@ -8,13 +8,11 @@ import { useGlobal } from '@/lib/global' * @returns */ export const ArticleLock = props => { - const { password, validPassword } = props + const { validPassword } = props const { locale } = useGlobal() const submitPassword = () => { const p = document.getElementById('password') - if (p && p.value && p.value === password) { - validPassword(true) - } else { + if (!validPassword(p?.value)) { const tips = document.getElementById('tips') if (tips) { tips.innerHTML = '' diff --git a/themes/hexo/components/HeaderArticle.js b/themes/hexo/components/HeaderArticle.js index 918c75c7..8ebfe2bd 100644 --- a/themes/hexo/components/HeaderArticle.js +++ b/themes/hexo/components/HeaderArticle.js @@ -4,12 +4,13 @@ import formatDate from '@/lib/formatDate' import BLOG from '@/blog.config' export default function HeaderArticle({ post, siteInfo }) { + const { locale } = useGlobal() + if (!post) { return <> } const headerImage = post?.page_cover ? `url("${post.page_cover}")` : `url("${siteInfo?.pageCover}")` - const { locale } = useGlobal() const date = formatDate( post?.date?.start_date || post?.createdTime, locale.LOCALE diff --git a/themes/medium/LayoutCategory.js b/themes/medium/LayoutCategory.js index a3018144..7522e264 100644 --- a/themes/medium/LayoutCategory.js +++ b/themes/medium/LayoutCategory.js @@ -5,7 +5,7 @@ import BLOG from '@/blog.config' export const LayoutCategory = props => { const { category } = props - const slotTop =
分类:
{category}
+ const slotTop =
分类:
{category}
return {BLOG.POST_LIST_STYLE === 'page' ? : } diff --git a/themes/medium/LayoutSlug.js b/themes/medium/LayoutSlug.js index f7fdc4d0..bdeec1a5 100644 --- a/themes/medium/LayoutSlug.js +++ b/themes/medium/LayoutSlug.js @@ -1,5 +1,3 @@ -import { getPageTableOfContents } from 'notion-utils' - import LayoutBase from './LayoutBase' import { useGlobal } from '@/lib/global' import React from 'react' @@ -16,11 +14,6 @@ export const LayoutSlug = props => { /> } - if (!lock && post?.blockMap?.block) { - post.content = Object.keys(post.blockMap.block) - post.toc = getPageTableOfContents(post, post.blockMap) - } - const slotRight = post?.toc && post?.toc?.length > 3 && (
@@ -29,7 +22,7 @@ export const LayoutSlug = props => { return ( - {!lock ? : } + {!lock ? : } ) } diff --git a/themes/medium/LayoutTag.js b/themes/medium/LayoutTag.js index 6f072aa9..41164ce3 100644 --- a/themes/medium/LayoutTag.js +++ b/themes/medium/LayoutTag.js @@ -5,7 +5,7 @@ import BlogPostListPage from './components/BlogPostListPage' export const LayoutTag = (props) => { const { tag } = props - const slotTop =
标签:
{tag}
+ const slotTop =
标签:
{tag}
return {BLOG.POST_LIST_STYLE === 'page' ? : } diff --git a/themes/medium/components/ArticleLock.js b/themes/medium/components/ArticleLock.js index 4b969835..1e1bb228 100644 --- a/themes/medium/components/ArticleLock.js +++ b/themes/medium/components/ArticleLock.js @@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global' * @returns */ export const ArticleLock = props => { - const { password, validPassword } = props + const { validPassword } = props const { locale } = useGlobal() const submitPassword = () => { const p = document.getElementById('password') - if (p && p.value && p.value === password) { - validPassword(true) - } else { + if (!validPassword(p?.value)) { const tips = document.getElementById('tips') if (tips) { tips.innerHTML = '' diff --git a/themes/next/LayoutSlug.js b/themes/next/LayoutSlug.js index aa1cc4d2..fa1915a1 100644 --- a/themes/next/LayoutSlug.js +++ b/themes/next/LayoutSlug.js @@ -1,4 +1,3 @@ -import { getPageTableOfContents } from 'notion-utils' import TocDrawerButton from './components/TocDrawerButton' import LayoutBase from './LayoutBase' import Card from './components/Card' @@ -12,11 +11,6 @@ import { isBrowser } from '@/lib/utils' export const LayoutSlug = (props) => { const { post, latestPosts, lock, validPassword } = props - if (!lock && post?.blockMap?.block) { - post.content = Object.keys(post.blockMap.block) - post.toc = getPageTableOfContents(post, post.blockMap) - } - const drawerRight = useRef(null) const targetRef = isBrowser() ? document.getElementById('container') : null const floatSlot = post?.toc?.length > 1 @@ -45,7 +39,7 @@ export const LayoutSlug = (props) => { {!lock && } - {lock && } + {lock && } {/* 悬浮目录按钮 */}
diff --git a/themes/next/components/ArticleLock.js b/themes/next/components/ArticleLock.js index 4bb2ef65..3e4a2019 100644 --- a/themes/next/components/ArticleLock.js +++ b/themes/next/components/ArticleLock.js @@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global' * @returns */ export const ArticleLock = props => { - const { password, validPassword } = props + const { validPassword } = props const { locale } = useGlobal() const submitPassword = () => { const p = document.getElementById('password') - if (p && p.value && p.value === password) { - validPassword(true) - } else { + if (!validPassword(p?.value)) { const tips = document.getElementById('tips') if (tips) { tips.innerHTML = ''