From 722aa2daface07931a47d897047ad543d447c31d Mon Sep 17 00:00:00 2001 From: anime Date: Tue, 8 Jul 2025 00:21:29 +0800 Subject: [PATCH 01/33] feat(getPageContentText): refactor content text extraction logic - add special case handling for various block types - maintain same functionality while improving structure Close #2151 --- pages/search/[keyword]/index.js | 160 +++++++++++++++++++++++--------- 1 file changed, 114 insertions(+), 46 deletions(-) diff --git a/pages/search/[keyword]/index.js b/pages/search/[keyword]/index.js index 4116e689..f0e63668 100644 --- a/pages/search/[keyword]/index.js +++ b/pages/search/[keyword]/index.js @@ -3,6 +3,7 @@ import { getDataFromCache } from '@/lib/cache/cache_manager' import { siteConfig } from '@/lib/config' import { getGlobalData } from '@/lib/db/getSiteData' import { DynamicLayout } from '@/themes/theme' +import { checkStrIsUuid } from '@/lib/utils' const Index = props => { const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG) @@ -58,42 +59,6 @@ export function getStaticPaths() { } } -/** - * 将对象的指定字段拼接到字符串 - * @param sourceTextArray - * @param targetObj - * @param key - * @returns {*} - */ -function appendText(sourceTextArray, targetObj, key) { - if (!targetObj) { - return sourceTextArray - } - const textArray = targetObj[key] - const text = textArray ? getTextContent(textArray) : '' - if (text && text !== 'Untitled') { - return sourceTextArray.concat(text) - } - return sourceTextArray -} - -/** - * 递归获取层层嵌套的数组 - * @param {*} textArray - * @returns - */ -function getTextContent(textArray) { - if (typeof textArray === 'object' && isIterable(textArray)) { - let result = '' - for (const textObj of textArray) { - result = result + getTextContent(textObj) - } - return result - } else if (typeof textArray === 'string') { - return textArray - } -} - /** * 对象是否可以遍历 * @param {*} obj @@ -124,12 +89,12 @@ async function filterByMemCache(allPosts, keyword) { : '' const articleInfo = post.title + post.summary + tagContent + categoryContent let hit = articleInfo.toLowerCase().indexOf(keyword) > -1 - const indexContent = getPageContentText(post, page) + const contentTextList = getPageContentText(post, page) // console.log('全文搜索缓存', cacheKey, page != null) post.results = [] let hitCount = 0 - for (const i of indexContent) { - const c = indexContent[i] + for (const i of contentTextList) { + const c = contentTextList[i] if (!c) { continue } @@ -152,17 +117,120 @@ async function filterByMemCache(allPosts, keyword) { } export function getPageContentText(post, pageBlockMap) { - let indexContent = [] + /** + * 将对象的指定字段拼接到字符串 + * @param sourceTextArray + * @param targetObj + * @param key + * @returns string + */ + function getText(targetObj) { + if (!targetObj) { + return '' + } + const textArray = targetObj['title'] || targetObj['caption'] + return getTextArray(textArray) + } + + function getTextArray(textArray) { + const text = textArray ? getTextContent(textArray) : '' + if (text && text !== 'Untitled') { + return text + } + return '' + } + + const removeTypeFlag = ['a', 'p', '‣'] + + /** + * 递归获取层层嵌套的数组 + * @param {*} textArray + * @returns string + */ + function getTextContent(textArray) { + if (typeof textArray === 'object' && isIterable(textArray)) { + let result = '' + for (const textObj of textArray) { + if (textArray.length > 1 && removeTypeFlag.includes(textArray[0])) { + return result + } + result = result + getTextContent(textObj) + } + return result + } else if (typeof textArray === 'string') { + if (checkStrIsUuid(textArray) && pageBlockMap.block[textArray]) { + return getBlockContentText(textArray) + } else if (textArray === pageBlockMap.block[postId].value.space_id) { + return '' + } + return textArray + } + } + + function getTransclusionReference(block) { + const result = [] + const blockPointer = block.format.transclusion_reference_pointer + const blockPointerId = blockPointer.id + if (blockPointer) { + const blockContentList = pageBlockMap.block[blockPointerId].value.content + for (const blockContent of blockContentList) { + result.push(getBlockContentText(blockContent)) + } + } + return result.join('') + } + + function getBlockContentText(id) { + const block = pageBlockMap?.block[id].value + const blockType = block.type + switch (blockType) { + case 'transclusion_reference': + return getTransclusionReference(block) + case 'table': + return getTableText(block.content) + case 'page': + if (id !== postId) { + return getText(block.properties) + } + return '' + case 'breadcrumb': + case 'divider': + return '' + case 'quote': + default: + const properties = block?.properties + return getText(properties) + } + } + + function getTableText(tableRowIds) { + const result = [] + for (const blockRowId of tableRowIds) { + if (pageBlockMap.block[blockRowId]) { + const blockRow = pageBlockMap.block[blockRowId].value + const blockRowProperties = blockRow.properties + for (const blockRowPropertyValue of Object.values(blockRowProperties)) { + result.push(getTextArray(blockRowPropertyValue)) + } + } + } + return result.join('') + } + + const postId = post.id + let contentTextList = [] // 防止搜到加密文章的内容 if (pageBlockMap && pageBlockMap.block && !post.password) { const contentIds = Object.keys(pageBlockMap.block) - contentIds.forEach(id => { - const properties = pageBlockMap?.block[id]?.value?.properties - indexContent = appendText(indexContent, properties, 'title') - indexContent = appendText(indexContent, properties, 'caption') - }) + for (const id of contentIds) { + const blockContentText = getBlockContentText(id) + if (blockContentText) { + contentTextList.push(blockContentText) + } + } } - return indexContent.join('') + console.log(contentTextList.join('')) + return contentTextList.join('') } export default Index From b4ba7d8f23a41294421c307e4633755ac421c907 Mon Sep 17 00:00:00 2001 From: anime Date: Tue, 8 Jul 2025 00:28:58 +0800 Subject: [PATCH 02/33] refactor(getPageContentText): Relocate getPageContentText to a dedicated file and eliminate the redundant isIterable function. --- lib/notion/getPageContentText.js | 118 ++++++++++++++++++++++++++++ lib/plugins/algolia.js | 2 +- lib/utils/post.js | 2 +- pages/search/[keyword]/index.js | 127 +------------------------------ 4 files changed, 121 insertions(+), 128 deletions(-) create mode 100644 lib/notion/getPageContentText.js diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js new file mode 100644 index 00000000..e636fab4 --- /dev/null +++ b/lib/notion/getPageContentText.js @@ -0,0 +1,118 @@ +import { checkStrIsUuid, isIterable } from '@/lib/utils' + +export function getPageContentText(post, pageBlockMap) { + /** + * 将对象的指定字段拼接到字符串 + * @param sourceTextArray + * @param targetObj + * @param key + * @returns string + */ + function getText(targetObj) { + if (!targetObj) { + return '' + } + const textArray = targetObj['title'] || targetObj['caption'] + return getTextArray(textArray) + } + + function getTextArray(textArray) { + const text = textArray ? getTextContent(textArray) : '' + if (text && text !== 'Untitled') { + return text + } + return '' + } + + const removeTypeFlag = ['a', 'p', '‣'] + + /** + * 递归获取层层嵌套的数组 + * @param {*} textArray + * @returns string + */ + function getTextContent(textArray) { + if (typeof textArray === 'object' && isIterable(textArray)) { + let result = '' + for (const textObj of textArray) { + if (textArray.length > 1 && removeTypeFlag.includes(textArray[0])) { + return result + } + result = result + getTextContent(textObj) + } + return result + } else if (typeof textArray === 'string') { + if (checkStrIsUuid(textArray) && pageBlockMap.block[textArray]) { + return getBlockContentText(textArray) + } else if (textArray === pageBlockMap.block[postId].value.space_id) { + return '' + } + return textArray + } + } + + function getTransclusionReference(block) { + const result = [] + const blockPointer = block.format.transclusion_reference_pointer + const blockPointerId = blockPointer.id + if (blockPointer) { + const blockContentList = pageBlockMap.block[blockPointerId].value.content + for (const blockContent of blockContentList) { + result.push(getBlockContentText(blockContent)) + } + } + return result.join('') + } + + function getBlockContentText(id) { + const block = pageBlockMap?.block[id].value + const blockType = block.type + switch (blockType) { + case 'transclusion_reference': + return getTransclusionReference(block) + case 'table': + return getTableText(block.content) + case 'page': + if (id !== postId) { + return getText(block.properties) + } + return '' + case 'breadcrumb': + case 'divider': + return '' + case 'quote': + default: + const properties = block?.properties + return getText(properties) + } + } + + function getTableText(tableRowIds) { + const result = [] + for (const blockRowId of tableRowIds) { + if (pageBlockMap.block[blockRowId]) { + const blockRow = pageBlockMap.block[blockRowId].value + const blockRowProperties = blockRow.properties + for (const blockRowPropertyValue of Object.values(blockRowProperties)) { + result.push(getTextArray(blockRowPropertyValue)) + } + } + } + return result.join('') + } + + const postId = post.id + let contentTextList = [] + // 防止搜到加密文章的内容 + if (pageBlockMap && pageBlockMap.block && !post.password) { + const contentIds = Object.keys(pageBlockMap.block) + for (const id of contentIds) { + const blockContentText = getBlockContentText(id) + if (blockContentText) { + contentTextList.push(blockContentText) + } + } + } + console.log(contentTextList.join('')) + return contentTextList.join('') +} diff --git a/lib/plugins/algolia.js b/lib/plugins/algolia.js index e6c76422..fceb7acc 100644 --- a/lib/plugins/algolia.js +++ b/lib/plugins/algolia.js @@ -1,6 +1,6 @@ import BLOG from '@/blog.config' -import { getPageContentText } from '@/pages/search/[keyword]' import algoliasearch from 'algoliasearch' +import { getPageContentText } from '@/lib/notion/getPageContentText' /** * 生成全文索引 diff --git a/lib/utils/post.js b/lib/utils/post.js index a3ee0f91..e4a22d2e 100644 --- a/lib/utils/post.js +++ b/lib/utils/post.js @@ -6,11 +6,11 @@ import { getPostBlocks } from '@/lib/db/getSiteData' import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents' import { siteConfig } from '@/lib/config' import { getDataFromCache, setDataToCache } from '@/lib/cache/cache_manager' -import { getPageContentText } from '@/pages/search/[keyword]' import { getAiSummary } from '@/lib/plugins/aiSummary' import BLOG from '@/blog.config' import { uploadDataToAlgolia } from '@/lib/plugins/algolia' import { countWords } from '@/lib/plugins/wordCount' +import { getPageContentText } from '@/lib/notion/getPageContentText' /** * 获取文章的关联推荐文章列表,目前根据标签关联性筛选 diff --git a/pages/search/[keyword]/index.js b/pages/search/[keyword]/index.js index f0e63668..cb486895 100644 --- a/pages/search/[keyword]/index.js +++ b/pages/search/[keyword]/index.js @@ -3,7 +3,7 @@ import { getDataFromCache } from '@/lib/cache/cache_manager' import { siteConfig } from '@/lib/config' import { getGlobalData } from '@/lib/db/getSiteData' import { DynamicLayout } from '@/themes/theme' -import { checkStrIsUuid } from '@/lib/utils' +import { getPageContentText } from '@/lib/notion/getPageContentText' const Index = props => { const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG) @@ -59,14 +59,6 @@ export function getStaticPaths() { } } -/** - * 对象是否可以遍历 - * @param {*} obj - * @returns - */ -const isIterable = obj => - obj != null && typeof obj[Symbol.iterator] === 'function' - /** * 在内存缓存中进行全文索引 * @param {*} allPosts @@ -116,121 +108,4 @@ async function filterByMemCache(allPosts, keyword) { return filterPosts } -export function getPageContentText(post, pageBlockMap) { - /** - * 将对象的指定字段拼接到字符串 - * @param sourceTextArray - * @param targetObj - * @param key - * @returns string - */ - function getText(targetObj) { - if (!targetObj) { - return '' - } - const textArray = targetObj['title'] || targetObj['caption'] - return getTextArray(textArray) - } - - function getTextArray(textArray) { - const text = textArray ? getTextContent(textArray) : '' - if (text && text !== 'Untitled') { - return text - } - return '' - } - - const removeTypeFlag = ['a', 'p', '‣'] - - /** - * 递归获取层层嵌套的数组 - * @param {*} textArray - * @returns string - */ - function getTextContent(textArray) { - if (typeof textArray === 'object' && isIterable(textArray)) { - let result = '' - for (const textObj of textArray) { - if (textArray.length > 1 && removeTypeFlag.includes(textArray[0])) { - return result - } - result = result + getTextContent(textObj) - } - return result - } else if (typeof textArray === 'string') { - if (checkStrIsUuid(textArray) && pageBlockMap.block[textArray]) { - return getBlockContentText(textArray) - } else if (textArray === pageBlockMap.block[postId].value.space_id) { - return '' - } - return textArray - } - } - - function getTransclusionReference(block) { - const result = [] - const blockPointer = block.format.transclusion_reference_pointer - const blockPointerId = blockPointer.id - if (blockPointer) { - const blockContentList = pageBlockMap.block[blockPointerId].value.content - for (const blockContent of blockContentList) { - result.push(getBlockContentText(blockContent)) - } - } - return result.join('') - } - - function getBlockContentText(id) { - const block = pageBlockMap?.block[id].value - const blockType = block.type - switch (blockType) { - case 'transclusion_reference': - return getTransclusionReference(block) - case 'table': - return getTableText(block.content) - case 'page': - if (id !== postId) { - return getText(block.properties) - } - return '' - case 'breadcrumb': - case 'divider': - return '' - case 'quote': - default: - const properties = block?.properties - return getText(properties) - } - } - - function getTableText(tableRowIds) { - const result = [] - for (const blockRowId of tableRowIds) { - if (pageBlockMap.block[blockRowId]) { - const blockRow = pageBlockMap.block[blockRowId].value - const blockRowProperties = blockRow.properties - for (const blockRowPropertyValue of Object.values(blockRowProperties)) { - result.push(getTextArray(blockRowPropertyValue)) - } - } - } - return result.join('') - } - - const postId = post.id - let contentTextList = [] - // 防止搜到加密文章的内容 - if (pageBlockMap && pageBlockMap.block && !post.password) { - const contentIds = Object.keys(pageBlockMap.block) - for (const id of contentIds) { - const blockContentText = getBlockContentText(id) - if (blockContentText) { - contentTextList.push(blockContentText) - } - } - } - console.log(contentTextList.join('')) - return contentTextList.join('') -} - export default Index From 2a89027bb6c26d4164d1015f4ec036b1438ae046 Mon Sep 17 00:00:00 2001 From: anime Date: Tue, 8 Jul 2025 00:32:16 +0800 Subject: [PATCH 03/33] chore(getPageContentText): add todo comments for future improvements - Add todo comment for cleaning up more useless tags - Add todo comment for handling more block types --- lib/notion/getPageContentText.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index e636fab4..9c29cc44 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -24,6 +24,7 @@ export function getPageContentText(post, pageBlockMap) { return '' } + // todo: 清除更多无用标签 const removeTypeFlag = ['a', 'p', '‣'] /** @@ -67,6 +68,7 @@ export function getPageContentText(post, pageBlockMap) { function getBlockContentText(id) { const block = pageBlockMap?.block[id].value const blockType = block.type + // todo: 处理更多类型 switch (blockType) { case 'transclusion_reference': return getTransclusionReference(block) From 7ce6ad0c2f77a91c42ffacb6d43619f17f0139fb Mon Sep 17 00:00:00 2001 From: anime Date: Tue, 8 Jul 2025 01:13:09 +0800 Subject: [PATCH 04/33] feat(algolia): add data deletion functionality and execute in index.js - Add `checkDataFromAlgolia` function to identify and delete unused data - Implement `deletePostDataFromAlgolia` helper function - Execute Algolia data check during homepage generation - Handle password-protected and draft pages deletion Fixes 1526 --- lib/plugins/algolia.js | 53 ++++++++++++++++++++++++++++++++++++++++++ pages/index.js | 3 +++ 2 files changed, 56 insertions(+) diff --git a/lib/plugins/algolia.js b/lib/plugins/algolia.js index e6c76422..fecec3a1 100644 --- a/lib/plugins/algolia.js +++ b/lib/plugins/algolia.js @@ -15,6 +15,59 @@ const generateAlgoliaSearch = ({ allPages, force = false }) => { }) } + +/** + * 检查数据是否需要从algolia删除 + * @param {*} props + */ +export const checkDataFromAlgolia = async props => { + const { allPages } = props + const deletions = (allPages || []) + .map(p => { + if (p && (p.password || p.status === 'Draft')) { + return deletePostDataFromAlgolia(p) + } + }) + .filter(Boolean) // 去除 undefined + await Promise.all(deletions) +} + +/** + * 删除数据 + * @param post + */ +const deletePostDataFromAlgolia = async post => { + // Connect and authenticate with your Algolia app + const client = algoliasearch(BLOG.ALGOLIA_APP_ID, BLOG.ALGOLIA_ADMIN_APP_KEY) + + // Create a new index and add a record + const index = client.initIndex(BLOG.ALGOLIA_INDEX) + + if (!post) { + return + } + + // 检查是否有索引 + let existed + try { + existed = await index.getObject(post.id) + } catch (error) { + // 通常是不存在索引 + } + + if (existed) { + await index + .deleteObject(post.id) + .wait() + .then(r => { + console.log('Algolia索引更新', r) + }) + .catch(err => { + console.log('Algolia异常', err) + }) + } +} + /** * 上传数据 * 根据上次修改文章日期和上次更新索引数据判断是否需要更新algolia索引 diff --git a/pages/index.js b/pages/index.js index b66b5610..b4b9937a 100644 --- a/pages/index.js +++ b/pages/index.js @@ -6,6 +6,7 @@ import { generateRss } from '@/lib/rss' import { generateSitemapXml } from '@/lib/sitemap.xml' import { DynamicLayout } from '@/themes/theme' import { generateRedirectJson } from '@/lib/redirect' +import { checkDataFromAlgolia } from '@/lib/plugins/algolia' /** * 首页布局 @@ -61,6 +62,8 @@ export async function getStaticProps(req) { generateRss(props) // 生成 generateSitemapXml(props) + // 检查数据是否需要从algolia删除 + checkDataFromAlgolia(props) if (siteConfig('UUID_REDIRECT', false, props?.NOTION_CONFIG)) { // 生成重定向 JSON generateRedirectJson(props) From 8d200120fc21c23605f6c00f1aaa77c2c0247720 Mon Sep 17 00:00:00 2001 From: anime Date: Tue, 8 Jul 2025 01:14:20 +0800 Subject: [PATCH 05/33] feat(algolia): add data deletion functionality and execute in index.js - Add `checkDataFromAlgolia` function to identify and delete unused data - Implement `deletePostDataFromAlgolia` helper function - Execute Algolia data check during homepage generation - Handle password-protected and draft pages deletion --- lib/plugins/algolia.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/algolia.js b/lib/plugins/algolia.js index fecec3a1..f3485ab7 100644 --- a/lib/plugins/algolia.js +++ b/lib/plugins/algolia.js @@ -60,7 +60,7 @@ const deletePostDataFromAlgolia = async post => { .deleteObject(post.id) .wait() .then(r => { - console.log('Algolia索引更新', r) + console.log('Algolia索引删除成功', r) }) .catch(err => { console.log('Algolia异常', err) From 55c39cbab8a45d90dc402b6b8163adb318ae6128 Mon Sep 17 00:00:00 2001 From: anime Date: Tue, 8 Jul 2025 01:41:50 +0800 Subject: [PATCH 06/33] feat(algolia): implement global client initialization and reuse - Add global Algolia client and index initialization - Initialize client once and reuse across functions - Remove redundant client initialization in individual functions - Add configuration validation during initialization --- lib/plugins/algolia.js | 46 ++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/lib/plugins/algolia.js b/lib/plugins/algolia.js index f3485ab7..439451f1 100644 --- a/lib/plugins/algolia.js +++ b/lib/plugins/algolia.js @@ -2,6 +2,31 @@ import BLOG from '@/blog.config' import { getPageContentText } from '@/pages/search/[keyword]' import algoliasearch from 'algoliasearch' +// 全局初始化 Algolia 客户端和索引 +let algoliaClient +let algoliaIndex + +const initAlgolia = () => { + if (!algoliaClient) { + if ( + !BLOG.ALGOLIA_APP_ID || + !BLOG.ALGOLIA_ADMIN_APP_KEY || + !BLOG.ALGOLIA_INDEX + ) { + throw new Error('Algolia configuration is missing') + } + algoliaClient = algoliasearch( + BLOG.ALGOLIA_APP_ID, + BLOG.ALGOLIA_ADMIN_APP_KEY + ) + algoliaIndex = algoliaClient.initIndex(BLOG.ALGOLIA_INDEX) + } + return { client: algoliaClient, index: algoliaIndex } +} + +// 初始化全局实例 +initAlgolia() + /** * 生成全文索引 * @param {*} allPages @@ -15,7 +40,6 @@ const generateAlgoliaSearch = ({ allPages, force = false }) => { }) } - /** * 检查数据是否需要从algolia删除 * @param {*} props @@ -37,12 +61,6 @@ export const checkDataFromAlgolia = async props => { * @param post */ const deletePostDataFromAlgolia = async post => { - // Connect and authenticate with your Algolia app - const client = algoliasearch(BLOG.ALGOLIA_APP_ID, BLOG.ALGOLIA_ADMIN_APP_KEY) - - // Create a new index and add a record - const index = client.initIndex(BLOG.ALGOLIA_INDEX) - if (!post) { return } @@ -50,13 +68,13 @@ const deletePostDataFromAlgolia = async post => { // 检查是否有索引 let existed try { - existed = await index.getObject(post.id) + existed = await algoliaIndex.getObject(post.id) } catch (error) { // 通常是不存在索引 } if (existed) { - await index + await algoliaIndex .deleteObject(post.id) .wait() .then(r => { @@ -73,12 +91,6 @@ const deletePostDataFromAlgolia = async post => { * 根据上次修改文章日期和上次更新索引数据判断是否需要更新algolia索引 */ const uploadDataToAlgolia = async post => { - // Connect and authenticate with your Algolia app - const client = algoliasearch(BLOG.ALGOLIA_APP_ID, BLOG.ALGOLIA_ADMIN_APP_KEY) - - // Create a new index and add a record - const index = client.initIndex(BLOG.ALGOLIA_INDEX) - if (!post) { return } @@ -87,7 +99,7 @@ const uploadDataToAlgolia = async post => { let existed let needUpdateIndex = false try { - existed = await index.getObject(post.id) + existed = await algoliaIndex.getObject(post.id) } catch (error) { // 通常是不存在索引 } @@ -117,7 +129,7 @@ const uploadDataToAlgolia = async post => { content: truncate(getPageContentText(post, post.blockMap), 8192) // 索引8192个字符,API限制总请求内容上限1万个字节 } // console.log('更新Algolia索引', record) - index + algoliaIndex .saveObject(record) .wait() .then(r => { From 93df743559a95f0bf9599fb2d94f8c4b5d9bd248 Mon Sep 17 00:00:00 2001 From: anime Date: Tue, 8 Jul 2025 15:37:59 +0800 Subject: [PATCH 07/33] feat(algolia): replace error throw with console.error for missing config Change error handling from throwing an exception to logging an error when Algolia configuration is missing. This provides better error reporting without breaking the application flow. --- lib/plugins/algolia.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/algolia.js b/lib/plugins/algolia.js index 439451f1..2421d142 100644 --- a/lib/plugins/algolia.js +++ b/lib/plugins/algolia.js @@ -13,7 +13,7 @@ const initAlgolia = () => { !BLOG.ALGOLIA_ADMIN_APP_KEY || !BLOG.ALGOLIA_INDEX ) { - throw new Error('Algolia configuration is missing') + console.error('Algolia configuration is missing') } algoliaClient = algoliasearch( BLOG.ALGOLIA_APP_ID, From d22e8bb177f2a48b616f4b25b97ca4cdfa3fed3d Mon Sep 17 00:00:00 2001 From: anime Date: Tue, 8 Jul 2025 15:50:54 +0800 Subject: [PATCH 08/33] feat(getPageContentText): add null checks for block references - Add validation for transclusion reference pointer existence - Return empty string when block is not found - Prevent potential errors from undefined block references --- lib/notion/getPageContentText.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index 9c29cc44..20c5a451 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -56,7 +56,7 @@ export function getPageContentText(post, pageBlockMap) { const result = [] const blockPointer = block.format.transclusion_reference_pointer const blockPointerId = blockPointer.id - if (blockPointer) { + if (blockPointer && pageBlockMap.block[blockPointerId].value) { const blockContentList = pageBlockMap.block[blockPointerId].value.content for (const blockContent of blockContentList) { result.push(getBlockContentText(blockContent)) @@ -67,6 +67,9 @@ export function getPageContentText(post, pageBlockMap) { function getBlockContentText(id) { const block = pageBlockMap?.block[id].value + if (!block) { + return '' + } const blockType = block.type // todo: 处理更多类型 switch (blockType) { From 645edd7eaddf060707ee064ced931b0437848ed4 Mon Sep 17 00:00:00 2001 From: anime Date: Tue, 8 Jul 2025 22:59:08 +0800 Subject: [PATCH 09/33] feat: enhance mailto/tel link handling and streamline imports - Introduced isMailOrTelLink utility function to validate mailto/tel links. - Updated getPageProperties to properly handle mailto/tel links with target=_self, preventing unintended conversion to internal links by avoiding the addition of slashes. Closes #3485 --- lib/notion/getPageProperties.js | 12 ++++++------ lib/utils/index.js | 9 +++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js index 571c1b8c..963607d1 100644 --- a/lib/notion/getPageProperties.js +++ b/lib/notion/getPageProperties.js @@ -4,11 +4,7 @@ import formatDate from '../utils/formatDate' // import { createHash } from 'crypto' import md5 from 'js-md5' import { siteConfig } from '../config' -import { - checkStartWithHttp, - convertUrlStartWithOneSlash, - getLastSegmentFromUrl -} from '../utils' +import { checkStartWithHttp, convertUrlStartWithOneSlash, getLastSegmentFromUrl, isMailOrTelLink } from '../utils' import { extractLangPrefix } from '../utils/pageId' import { mapImgUrl } from './mapImage' import notionAPI from '@/lib/notion/getNotionAPI' @@ -85,8 +81,9 @@ export default async function getPageProperties( const fieldNames = BLOG.NOTION_PROPERTY_NAME if (fieldNames) { Object.keys(fieldNames).forEach(key => { - if (fieldNames[key] && properties[fieldNames[key]]) + if (fieldNames[key] && properties[fieldNames[key]]) { properties[key] = properties[fieldNames[key]] + } }) } @@ -193,6 +190,9 @@ export function adjustPageProperties(properties, NOTION_CONFIG) { if (checkStartWithHttp(properties?.href)) { properties.href = properties?.slug properties.target = '_blank' + } else if (isMailOrTelLink(properties?.href)) { + properties.href = properties?.slug + properties.target = '_self' } else { properties.target = '_self' // 伪静态路径右侧拼接.html diff --git a/lib/utils/index.js b/lib/utils/index.js index e12f2f85..fe49c942 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -104,6 +104,15 @@ export function checkStartWithHttp(str) { } } +/** + * 检查是否是邮件或电话链接 + * @param href + * @returns {boolean} + */ +export function isMailOrTelLink(href) { + return /^(mailto:|tel:)/i.test(href) +} + // 检查一个字符串是否UUID https://ihateregex.io/expr/uuid/ export function checkStrIsUuid(str) { if (!str) { From b16512ac9aff156760a11c40a9e4f0f616d367cd Mon Sep 17 00:00:00 2001 From: anime Date: Tue, 8 Jul 2025 23:04:41 +0800 Subject: [PATCH 10/33] refactor: rename checkStartWithHttp to isHttpLink - Update function name and implementation in utils/index.js - Replace all occurrences in getPageProperties.js, post.js, and BlogPostCard.js - Improve function documentation and use regex for better URL matching --- lib/notion/getPageProperties.js | 6 +++--- lib/utils/index.js | 19 ++++++++----------- lib/utils/post.js | 8 ++++---- themes/nav/components/BlogPostCard.js | 4 ++-- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js index 963607d1..29bb5472 100644 --- a/lib/notion/getPageProperties.js +++ b/lib/notion/getPageProperties.js @@ -4,7 +4,7 @@ import formatDate from '../utils/formatDate' // import { createHash } from 'crypto' import md5 from 'js-md5' import { siteConfig } from '../config' -import { checkStartWithHttp, convertUrlStartWithOneSlash, getLastSegmentFromUrl, isMailOrTelLink } from '../utils' +import { convertUrlStartWithOneSlash, getLastSegmentFromUrl, isHttpLink, isMailOrTelLink } from '../utils' import { extractLangPrefix } from '../utils/pageId' import { mapImgUrl } from './mapImage' import notionAPI from '@/lib/notion/getNotionAPI' @@ -187,7 +187,7 @@ export function adjustPageProperties(properties, NOTION_CONFIG) { } // http or https 开头的视为外链 - if (checkStartWithHttp(properties?.href)) { + if (isHttpLink(properties?.href)) { properties.href = properties?.slug properties.target = '_blank' } else if (isMailOrTelLink(properties?.href)) { @@ -238,7 +238,7 @@ export function adjustPageProperties(properties, NOTION_CONFIG) { */ function generateCustomizeSlug(postProperties, NOTION_CONFIG) { // 外链不处理 - if (checkStartWithHttp(postProperties.slug)) { + if (isHttpLink(postProperties.slug)) { return postProperties.slug } let fullPrefix = '' diff --git a/lib/utils/index.js b/lib/utils/index.js index fe49c942..bfef0f46 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -89,19 +89,16 @@ export function isUrl(str) { return false } - return str?.indexOf('/') === 0 || checkStartWithHttp(str) + return str?.indexOf('/') === 0 || isHttpLink(str) } -// 检查是否外链 -export function checkStartWithHttp(str) { - // 检查字符串是否包含http - if (str?.indexOf('http:') === 0 || str?.indexOf('https:') === 0) { - // 如果包含,找到http的位置 - return true - } else { - // 不包含 - return false - } +/** + * 判断是否是 http(s) 开头的链接(外部网页) + * @param str + * @returns {boolean} + */ +export function isHttpLink(str) { + return typeof str === 'string' && /^https?:\/\//i.test(str) } /** diff --git a/lib/utils/post.js b/lib/utils/post.js index a3ee0f91..5cb769f2 100644 --- a/lib/utils/post.js +++ b/lib/utils/post.js @@ -1,7 +1,7 @@ /** * 文章相关工具 */ -import { checkStartWithHttp } from '.' +import { isHttpLink } from '.' import { getPostBlocks } from '@/lib/db/getSiteData' import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents' import { siteConfig } from '@/lib/config' @@ -59,7 +59,7 @@ export function checkSlugHasNoSlash(row) { } return ( (slug.match(/\//g) || []).length === 0 && - !checkStartWithHttp(slug) && + !isHttpLink(slug) && row.type.indexOf('Menu') < 0 ) } @@ -76,7 +76,7 @@ export function checkSlugHasOneSlash(row) { } return ( (slug.match(/\//g) || []).length === 1 && - !checkStartWithHttp(slug) && + !isHttpLink(slug) && row.type.indexOf('Menu') < 0 ) } @@ -94,7 +94,7 @@ export function checkSlugHasMorThanTwoSlash(row) { return ( (slug.match(/\//g) || []).length >= 2 && row.type.indexOf('Menu') < 0 && - !checkStartWithHttp(slug) + !isHttpLink(slug) ) } diff --git a/themes/nav/components/BlogPostCard.js b/themes/nav/components/BlogPostCard.js index 0f92a30a..cdff4d55 100755 --- a/themes/nav/components/BlogPostCard.js +++ b/themes/nav/components/BlogPostCard.js @@ -1,5 +1,5 @@ import { siteConfig } from '@/lib/config' -import { checkStartWithHttp } from '@/lib/utils' +import { isHttpLink } from '@/lib/utils' import Link from 'next/link' import { useRouter } from 'next/router' import NotionIcon from './NotionIcon' @@ -23,7 +23,7 @@ const BlogPostCard = ({ post, className }) => { return (
Date: Tue, 8 Jul 2025 23:06:07 +0800 Subject: [PATCH 11/33] refactor(utils): rename and improve isUrl to isUrlLikePath - Rename isUrl function to isUrlLikePath for better clarity - Simplify function logic and add type checking - Update all references to use the new function name - Improve function documentation and parameter typing --- lib/config.js | 4 ++-- lib/utils/index.js | 15 ++++++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/config.js b/lib/config.js index 54b043a7..81ff88e3 100644 --- a/lib/config.js +++ b/lib/config.js @@ -2,7 +2,7 @@ import BLOG from '@/blog.config' import { useGlobal } from './global' -import { deepClone, isUrl } from './utils' +import { deepClone, isUrlLikePath } from './utils' /** * 读取配置顺序 @@ -146,7 +146,7 @@ export const convertVal = val => { } // 检测是否为 URL - if (isUrl(val)) { + if (isUrlLikePath(val)) { return val } diff --git a/lib/utils/index.js b/lib/utils/index.js index bfef0f46..b0e0c77e 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -80,16 +80,13 @@ export function convertUrlStartWithOneSlash(str) { } /** - * 是否是一个相对或绝对路径的ur类 - * @param {*} str - * @returns + * 判断是否是一个“URL 样式”的路径(内部或外部) + * 内部如 /about,外部如 http://xxx.com + * @param str + * @returns {boolean} */ -export function isUrl(str) { - if (!str) { - return false - } - - return str?.indexOf('/') === 0 || isHttpLink(str) +export function isUrlLikePath(str) { + return typeof str === 'string' && (str.startsWith('/') || isHttpLink(str)) } /** From b52f81815461bd428ce8759978da79ebc12205e6 Mon Sep 17 00:00:00 2001 From: anime Date: Wed, 9 Jul 2025 13:11:52 +0800 Subject: [PATCH 12/33] feat(getPageContentText): replace custom text extraction with notion-utils The getTextContent function was removed and replaced with an import from notion-utils, simplifying the text extraction logic for Notion page content. This change removes the custom recursive implementation and uses the standardized utility function instead. --- lib/notion/getPageContentText.js | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index 20c5a451..fa93c9a8 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -1,4 +1,4 @@ -import { checkStrIsUuid, isIterable } from '@/lib/utils' +import { getTextContent } from 'notion-utils' export function getPageContentText(post, pageBlockMap) { /** @@ -24,34 +24,6 @@ export function getPageContentText(post, pageBlockMap) { return '' } - // todo: 清除更多无用标签 - const removeTypeFlag = ['a', 'p', '‣'] - - /** - * 递归获取层层嵌套的数组 - * @param {*} textArray - * @returns string - */ - function getTextContent(textArray) { - if (typeof textArray === 'object' && isIterable(textArray)) { - let result = '' - for (const textObj of textArray) { - if (textArray.length > 1 && removeTypeFlag.includes(textArray[0])) { - return result - } - result = result + getTextContent(textObj) - } - return result - } else if (typeof textArray === 'string') { - if (checkStrIsUuid(textArray) && pageBlockMap.block[textArray]) { - return getBlockContentText(textArray) - } else if (textArray === pageBlockMap.block[postId].value.space_id) { - return '' - } - return textArray - } - } - function getTransclusionReference(block) { const result = [] const blockPointer = block.format.transclusion_reference_pointer From 44ff4bcb230a6f1145df8b934727062e72f22028 Mon Sep 17 00:00:00 2001 From: anime Date: Wed, 9 Jul 2025 13:14:41 +0800 Subject: [PATCH 13/33] feat(getPageContentText): remove debug console.log from getPageContentText Commented out console.log statement in getPageContentText.js to remove debug output while maintaining the functionality. --- lib/notion/getPageContentText.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index fa93c9a8..19130991 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -90,6 +90,6 @@ export function getPageContentText(post, pageBlockMap) { } } } - console.log(contentTextList.join('')) + // console.log(contentTextList.join('')) return contentTextList.join('') } From 72d64d7184db69bb9b01f82bf585d38ac541935f Mon Sep 17 00:00:00 2001 From: anime Date: Wed, 9 Jul 2025 13:51:43 +0800 Subject: [PATCH 14/33] feat(getPageContentText): enhance getPageContentText to handle nested block content - refactor getText function to process block properties and content - add support for recursive processing of nested block content - improve null checks and error handling in block processing - update getBlockContentText to handle block value safely --- lib/notion/getPageContentText.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index 19130991..e4b79b37 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -3,17 +3,23 @@ import { getTextContent } from 'notion-utils' export function getPageContentText(post, pageBlockMap) { /** * 将对象的指定字段拼接到字符串 - * @param sourceTextArray - * @param targetObj - * @param key + * @param block * @returns string */ - function getText(targetObj) { - if (!targetObj) { + function getText(block) { + const result = [] + const properties = block.properties + if (!properties) { return '' } - const textArray = targetObj['title'] || targetObj['caption'] - return getTextArray(textArray) + const textArray = properties['title'] || properties['caption'] + result.push(getTextArray(textArray)) + if (block['content']?.length > 0) { + for (const blockContent of block.content) { + result.push(getBlockContentText(blockContent)) + } + } + return result.join('') } function getTextArray(textArray) { @@ -38,7 +44,7 @@ export function getPageContentText(post, pageBlockMap) { } function getBlockContentText(id) { - const block = pageBlockMap?.block[id].value + const block = pageBlockMap?.block[id]?.value if (!block) { return '' } @@ -51,7 +57,7 @@ export function getPageContentText(post, pageBlockMap) { return getTableText(block.content) case 'page': if (id !== postId) { - return getText(block.properties) + return getText(block) } return '' case 'breadcrumb': @@ -59,8 +65,7 @@ export function getPageContentText(post, pageBlockMap) { return '' case 'quote': default: - const properties = block?.properties - return getText(properties) + return getText(block) } } From 2a0f4fd49c086d92f3f98284dd45ff019621e4df Mon Sep 17 00:00:00 2001 From: anime Date: Wed, 9 Jul 2025 13:58:48 +0800 Subject: [PATCH 15/33] feat(getPageContentText): ensure proper spacing in concatenated text content Modify getPageContentText.js to use space delimiter when joining text blocks instead of empty string. This change affects three functions: getPageContentText, getTextArray, and getBlockContentText to improve text readability and proper spacing between concatenated content blocks. --- lib/notion/getPageContentText.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index e4b79b37..79fe5689 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -19,7 +19,7 @@ export function getPageContentText(post, pageBlockMap) { result.push(getBlockContentText(blockContent)) } } - return result.join('') + return result.join(' ') } function getTextArray(textArray) { @@ -40,7 +40,7 @@ export function getPageContentText(post, pageBlockMap) { result.push(getBlockContentText(blockContent)) } } - return result.join('') + return result.join(' ') } function getBlockContentText(id) { @@ -80,7 +80,7 @@ export function getPageContentText(post, pageBlockMap) { } } } - return result.join('') + return result.join(' ') } const postId = post.id From 3ad7605abe0551d3a583fb52c34517728a76639d Mon Sep 17 00:00:00 2001 From: anime Date: Wed, 9 Jul 2025 14:09:37 +0800 Subject: [PATCH 16/33] fix: prevent processing content for page type blocks - Skip content processing when block type is 'page' - Update debug log message for content text concatenation --- lib/notion/getPageContentText.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index 79fe5689..18672cc0 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -14,7 +14,7 @@ export function getPageContentText(post, pageBlockMap) { } const textArray = properties['title'] || properties['caption'] result.push(getTextArray(textArray)) - if (block['content']?.length > 0) { + if (block.type !== 'page' && block['content']?.length > 0) { for (const blockContent of block.content) { result.push(getBlockContentText(blockContent)) } @@ -95,6 +95,6 @@ export function getPageContentText(post, pageBlockMap) { } } } - // console.log(contentTextList.join('')) + console.log('开始', contentTextList.join(''), '结束') return contentTextList.join('') } From 9321b2dfaed30d631784472c91d05ae2eaa3d273 Mon Sep 17 00:00:00 2001 From: anime Date: Wed, 9 Jul 2025 14:39:47 +0800 Subject: [PATCH 17/33] feat(getPageContentText): update getPageContentText to use post.content array - modify content extraction logic to use post.content array - avoid extra but wrong result by checking pageBlockMap.block --- lib/notion/getPageContentText.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index 18672cc0..94f791a5 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -84,12 +84,12 @@ export function getPageContentText(post, pageBlockMap) { } const postId = post.id + const postContent = post.content let contentTextList = [] // 防止搜到加密文章的内容 - if (pageBlockMap && pageBlockMap.block && !post.password) { - const contentIds = Object.keys(pageBlockMap.block) - for (const id of contentIds) { - const blockContentText = getBlockContentText(id) + if (postContent.length > 0 && !post.password) { + for (const postContentId of postContent) { + const blockContentText = getBlockContentText(postContentId) if (blockContentText) { contentTextList.push(blockContentText) } From 23550a61d3580d593a98e0b6bf886311e133d6ea Mon Sep 17 00:00:00 2001 From: anime Date: Wed, 9 Jul 2025 15:19:47 +0800 Subject: [PATCH 18/33] feat(getPageContentText): add flexible property value retrieval and support for more block types - Add getPropertyValue helper function for flexible property retrieval - Enhance getText function to accept custom keys for property lookup - Add support for additional block types: image, bookmark, callout, header - Improve documentation with JSDoc comments for better code understanding --- lib/notion/getPageContentText.js | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index 94f791a5..dc94c8fc 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -1,18 +1,34 @@ import { getTextContent } from 'notion-utils' +/** + * 获取属性值,优先从 overrides 中读取,否则按顺序从 properties 中读取,最后返回默认值 + * @param {Object} properties 原始属性对象 + * @param {Array} keys 优先级字段名列表 + * @param {Object} overrides 自定义覆盖对象(可选) + * @param {string} defaultValue 默认值(可选) + */ +function getPropertyValue(properties, keys, overrides = {}, defaultValue = '') { + for (const key of keys) { + if (overrides[key]) return overrides[key] + if (properties[key]) return properties[key] + } + return defaultValue +} + export function getPageContentText(post, pageBlockMap) { /** * 将对象的指定字段拼接到字符串 * @param block + * @param customKeys 优先级字段名列表 * @returns string */ - function getText(block) { + function getText(block, customKeys = ['title', 'caption']) { const result = [] const properties = block.properties if (!properties) { return '' } - const textArray = properties['title'] || properties['caption'] + const textArray = getPropertyValue(properties, customKeys) result.push(getTextArray(textArray)) if (block.type !== 'page' && block['content']?.length > 0) { for (const blockContent of block.content) { @@ -61,9 +77,20 @@ export function getPageContentText(post, pageBlockMap) { } return '' case 'breadcrumb': + case 'external_object_instance': case 'divider': return '' + case 'image': + return getText(block, ['alt_text', 'title']) + // 除title以外,还有额外的link和description可供索引,但认为不需要 + case 'bookmark': case 'quote': + case 'callout': + case 'header': + case 'sub_header': + case 'code': + case 'equation': + case 'text': default: return getText(block) } From f9ac624498832b0d1b661b2bd158e1d92c9483f6 Mon Sep 17 00:00:00 2001 From: anime Date: Wed, 9 Jul 2025 16:00:15 +0800 Subject: [PATCH 19/33] feat(getPageContentText): implement getFullTextContent for enhanced text extraction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add new getFullTextContent function to handle various Notion text formats - Support equation extraction from decorated text - Handle special characters like '⁍' and '‣' with proper content resolution - Process date mentions, link mentions, and other reference types - Replace getTextContent with getFullTextContent in getTextArray function - Maintain backward compatibility with existing text processing --- lib/notion/getPageContentText.js | 60 ++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index dc94c8fc..d8095588 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -1,5 +1,3 @@ -import { getTextContent } from 'notion-utils' - /** * 获取属性值,优先从 overrides 中读取,否则按顺序从 properties 中读取,最后返回默认值 * @param {Object} properties 原始属性对象 @@ -15,6 +13,62 @@ function getPropertyValue(properties, keys, overrides = {}, defaultValue = '') { return defaultValue } +/** + * 提取 Notion 装饰文本的纯文本内容。 + * 可选传入 resolveRef 来解析引用(例如 '‣' 指向的页面标题) + * + * @param {Array} text - Notion Decoration[] 格式的文本数组 + * @returns {string} + */ +function getFullTextContent(text) { + if (!text) return '' + + if (!Array.isArray(text)) return String(text) + + return text.reduce((result, item) => { + const value = item[0] + const decorations = item[1] + + if (value === '⁍') { + // 检查是否有公式 + const equation = decorations?.find(d => d[0] === 'e') + if (equation) { + return result + equation[1] // 提取 LaTeX 内容 + } + return result // 否则什么都不加 + } + + if (value === '‣') { + const ref = Array.isArray(decorations) ? decorations[0] : null + const type = ref?.[0] + const data = ref?.[1] + + switch (type) { + case 'd': + // 日期字符串 + const date = + data?.start_date || + data?.start_time || + data?.end_date || + data?.end_time || + '[Date]' + return result + date + case 'lm': + // Link Mention + const title = data?.title || data?.href || '[Link]' + return result + title + // 用户 ID,这里不展开,默认忽略或标记 + case 'u': + default: + return result + } + } + + // 默认拼接普通文本 + return result + value + }, '') +} + export function getPageContentText(post, pageBlockMap) { /** * 将对象的指定字段拼接到字符串 @@ -39,7 +93,7 @@ export function getPageContentText(post, pageBlockMap) { } function getTextArray(textArray) { - const text = textArray ? getTextContent(textArray) : '' + const text = textArray ? getFullTextContent(textArray) : '' if (text && text !== 'Untitled') { return text } From 9886e4d146cf7270d7b833e7dc847bde797192c6 Mon Sep 17 00:00:00 2001 From: anime Date: Wed, 9 Jul 2025 16:12:12 +0800 Subject: [PATCH 20/33] feat(getPageContentText): add references to NotionX types and comment out debug log - Add reference links to NotionX type definitions for better documentation - Comment out debug console.log statement to clean up output - Maintain existing functionality while improving code clarity --- lib/notion/getPageContentText.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index d8095588..06a11f7f 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -42,7 +42,7 @@ function getFullTextContent(text) { const ref = Array.isArray(decorations) ? decorations[0] : null const type = ref?.[0] const data = ref?.[1] - + // todo: 处理更多类型 https://github.com/NotionX/react-notion-x/blob/9ee2d9334e260ee3600f4f8d7212f66b641b19cc/packages/notion-types/src/core.ts#L108 switch (type) { case 'd': // 日期字符串 @@ -119,7 +119,7 @@ export function getPageContentText(post, pageBlockMap) { return '' } const blockType = block.type - // todo: 处理更多类型 + // todo: 处理更多类型 https://github.com/NotionX/react-notion-x/blob/9ee2d9334e260ee3600f4f8d7212f66b641b19cc/packages/notion-types/src/block.ts#L3 switch (blockType) { case 'transclusion_reference': return getTransclusionReference(block) @@ -176,6 +176,6 @@ export function getPageContentText(post, pageBlockMap) { } } } - console.log('开始', contentTextList.join(''), '结束') + // console.log('开始', contentTextList.join(''), '结束') return contentTextList.join('') } From ea1b76f5b7c2f10ce80efea85e022a64d8d9ca06 Mon Sep 17 00:00:00 2001 From: anime Date: Wed, 9 Jul 2025 16:22:38 +0800 Subject: [PATCH 21/33] fix(getPageContentText): add null check for postContent before accessing length property Ensure postContent exists before checking its length property to prevent potential runtime errors when postContent is null or undefined. --- lib/notion/getPageContentText.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/notion/getPageContentText.js b/lib/notion/getPageContentText.js index 06a11f7f..0e52083b 100644 --- a/lib/notion/getPageContentText.js +++ b/lib/notion/getPageContentText.js @@ -168,7 +168,7 @@ export function getPageContentText(post, pageBlockMap) { const postContent = post.content let contentTextList = [] // 防止搜到加密文章的内容 - if (postContent.length > 0 && !post.password) { + if (postContent && postContent.length > 0 && !post.password) { for (const postContentId of postContent) { const blockContentText = getBlockContentText(postContentId) if (blockContentText) { From c6b3d0a10838ccb723552ec955499bbbc888bef8 Mon Sep 17 00:00:00 2001 From: yucui Date: Fri, 11 Jul 2025 13:38:58 +0800 Subject: [PATCH 22/33] =?UTF-8?q?Feat=20typography=20=E5=8D=9A=E5=AE=A2?= =?UTF-8?q?=E8=8B=B1=E6=96=87=E6=A0=87=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/typography/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/typography/config.js b/themes/typography/config.js index c496beb4..1f7d0957 100644 --- a/themes/typography/config.js +++ b/themes/typography/config.js @@ -1,7 +1,7 @@ const CONFIG = { // 博客標題 雙語言 TYPOGRAPHY_BLOG_NAME: process.env.NEXT_PUBLIC_TYPOGRAPHY_BLOG_NAME || '活字印刷', - TYPOGRAPHY_BLOG_NAME_EN: process.env.NEXT_PUBLIC_TYPOGRAPHY_BLOG_NAME || 'Typography', + TYPOGRAPHY_BLOG_NAME_EN: process.env.NEXT_PUBLIC_TYPOGRAPHY_BLOG_NAME_EN || process.env.NEXT_PUBLIC_TYPOGRAPHY_BLOG_NAME || 'Typography', TYPOGRAPHY_POST_AD_ENABLE: process.env.NEXT_PUBLIC_TYPOGRAPHY_POST_AD_ENABLE || false, // 文章列表是否插入广告 From b2c9ed50148e19898609a83f922f01d2583ee154 Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Fri, 11 Jul 2025 17:29:38 +0800 Subject: [PATCH 23/33] =?UTF-8?q?starter=E4=B8=BB=E9=A2=98=E6=96=B0?= =?UTF-8?q?=E5=A2=9Elite=E6=A8=A1=E5=BC=8F=EF=BC=8C=E9=9A=90=E8=97=8F?= =?UTF-8?q?=E9=A1=B5=E5=A4=B4=E9=A1=B5=E8=84=9A=E4=BE=BF=E4=BA=8E=E5=B5=8C?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/global.js | 5 ++++ themes/starter/index.js | 59 ++++++++++++++++++++++++++--------------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/lib/global.js b/lib/global.js index b5d76d83..5039b9f2 100644 --- a/lib/global.js +++ b/lib/global.js @@ -31,6 +31,7 @@ export function GlobalContextProvider(props) { ) // 默认语言 const [theme, setTheme] = useState(NOTION_CONFIG?.THEME || THEME) // 默认博客主题 const [THEME_CONFIG, SET_THEME_CONFIG] = useState(null) // 主题配置 + const [isLiteMode,setLiteMode] = useState(false) const defaultDarkMode = NOTION_CONFIG?.APPEARANCE || APPEARANCE const [isDarkMode, updateDarkMode] = useState(defaultDarkMode === 'dark') // 默认深色模式 @@ -107,6 +108,9 @@ export function GlobalContextProvider(props) { const newUrl = `${url}${url.includes('?') ? '&' : '?'}theme=${themeStr}` router.push(newUrl) } + if (router.query.lite && router.query.lite==='true') { + setLiteMode(true) + } if (!onLoading) { setOnLoading(true) } @@ -134,6 +138,7 @@ export function GlobalContextProvider(props) { return ( { - const { children } = props + const { children } = props + // 极简模式,会隐藏掉页头页脚等组件,便于嵌入网页等功能 + const { isLiteMode } = useGlobal() + const router = useRouter() - // 加载wow动画 - useEffect(() => { - loadWowJS() - }, []) + // 加载wow动画 + useEffect(() => { + loadWowJS() + }, []) - return ( -
-