From 33740681637e2b265138fb4fce562fc1eedbafeb Mon Sep 17 00:00:00 2001 From: anime Date: Fri, 8 Nov 2024 00:14:09 +0800 Subject: [PATCH 01/25] =?UTF-8?q?fix(=E4=BD=BF=E6=89=80=E6=9C=89=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E7=9A=84404=E8=83=BD=E5=A4=9F=E6=AD=A3=E5=B8=B8?= =?UTF-8?q?=E8=BF=90=E8=BD=AC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 3e3b7667d043522a3d782b804815b8f1683127d1) --- themes/commerce/index.js | 2 +- themes/example/index.js | 2 +- themes/fukasawa/index.js | 2 +- themes/game/index.js | 2 +- themes/heo/index.js | 2 +- themes/hexo/index.js | 2 +- themes/magzine/index.js | 2 +- themes/matery/index.js | 2 +- themes/medium/index.js | 2 +- themes/movie/index.js | 2 +- themes/nobelium/index.js | 2 +- themes/photo/index.js | 2 +- themes/plog/index.js | 2 +- themes/simple/index.js | 52 +++++++++++++++++++++------------------- themes/starter/index.js | 2 +- 15 files changed, 41 insertions(+), 39 deletions(-) diff --git a/themes/commerce/index.js b/themes/commerce/index.js index 7ced2e85726..f415f8e5200 100644 --- a/themes/commerce/index.js +++ b/themes/commerce/index.js @@ -246,7 +246,7 @@ const LayoutSlug = props => {
{lock && } - {!lock && ( + {!lock && post && (
diff --git a/themes/example/index.js b/themes/example/index.js index 60b896c1f4f..2d6ecfefaee 100644 --- a/themes/example/index.js +++ b/themes/example/index.js @@ -178,7 +178,7 @@ const LayoutSlug = props => { <> {lock ? ( - ) : ( + ) : post && (
diff --git a/themes/fukasawa/index.js b/themes/fukasawa/index.js index 96936df8229..2167a95027f 100644 --- a/themes/fukasawa/index.js +++ b/themes/fukasawa/index.js @@ -159,7 +159,7 @@ const LayoutSlug = props => { <> {lock ? ( - ) : ( + ) : post && ( )} diff --git a/themes/game/index.js b/themes/game/index.js index 718f6a92a8c..04bc192ccf5 100644 --- a/themes/game/index.js +++ b/themes/game/index.js @@ -307,7 +307,7 @@ const LayoutSlug = props => { <> {lock && } - {!lock && ( + {!lock && post && (
diff --git a/themes/heo/index.js b/themes/heo/index.js index 9bab5daffc8..42bfcb83f45 100644 --- a/themes/heo/index.js +++ b/themes/heo/index.js @@ -292,7 +292,7 @@ const LayoutSlug = props => { {/* 文章锁 */} {lock && } - {!lock && ( + {!lock && post && (
{/* 文章主体 */}
{
{lock && } - {!lock && ( + {!lock && post && (
{ {/* 文章锁 */} {lock && } - {!lock && ( + {!lock && post && (
{/* 文章信息 */} diff --git a/themes/matery/index.js b/themes/matery/index.js index 7cbcad19ddb..13a5992f094 100644 --- a/themes/matery/index.js +++ b/themes/matery/index.js @@ -253,7 +253,7 @@ const LayoutSlug = props => { className={`${fullWidth ? '' : '-mt-32'} transition-all duration-300 rounded-md mx-3 lg:border lg:rounded-xl lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black`}> {lock && } - {!lock && ( + {!lock && post && (
{/* 文章信息 */} {post?.type && post?.type === 'Post' && ( diff --git a/themes/medium/index.js b/themes/medium/index.js index ee5eb121f4e..b51db693622 100644 --- a/themes/medium/index.js +++ b/themes/medium/index.js @@ -209,7 +209,7 @@ const LayoutSlug = props => { {/* 文章锁 */} {lock && } - {!lock && ( + {!lock && post && (
{/* 文章信息 */} diff --git a/themes/movie/index.js b/themes/movie/index.js index 00b90346c4e..c205d6d02b8 100644 --- a/themes/movie/index.js +++ b/themes/movie/index.js @@ -315,7 +315,7 @@ const LayoutSlug = props => { return ( <> - {!lock ? ( + {!lock ? post && (
diff --git a/themes/nobelium/index.js b/themes/nobelium/index.js index ed2b6ea6ea4..44afc5c004a 100644 --- a/themes/nobelium/index.js +++ b/themes/nobelium/index.js @@ -243,7 +243,7 @@ const LayoutSlug = props => { <> {lock && } - {!lock && ( + {!lock && post && (
<> diff --git a/themes/photo/index.js b/themes/photo/index.js index f369e6fb28c..64f6a1f06b5 100644 --- a/themes/photo/index.js +++ b/themes/photo/index.js @@ -315,7 +315,7 @@ const LayoutSlug = props => { return ( <> - {!lock ? ( + {!lock ? post && (
diff --git a/themes/plog/index.js b/themes/plog/index.js index be778f685b7..b715206f42a 100644 --- a/themes/plog/index.js +++ b/themes/plog/index.js @@ -198,7 +198,7 @@ const LayoutSlug = props => { <> {lock && } - {!lock && ( + {!lock && post && (
<> diff --git a/themes/simple/index.js b/themes/simple/index.js index 397e6a69d34..29516202e1a 100644 --- a/themes/simple/index.js +++ b/themes/simple/index.js @@ -224,35 +224,37 @@ const LayoutSlug = props => { <> {lock && } -
- {/* 文章信息 */} - - - {/* 广告嵌入 */} - {/* */} - - -
- {/* Notion文章主体 */} - {!lock && } -
+ {!lock && post && ( +
+ {/* 文章信息 */} + + + {/* 广告嵌入 */} + {/* */} + + +
+ {/* Notion文章主体 */} + {!lock && } +
- {/* 分享 */} - + {/* 分享 */} + - {/* 广告嵌入 */} - + {/* 广告嵌入 */} + - {post?.type === 'Post' && ( - <> - - - - )} + {post?.type === 'Post' && ( + <> + + + + )} - {/* 评论区 */} - -
+ {/* 评论区 */} + +
+ )} ) } diff --git a/themes/starter/index.js b/themes/starter/index.js index 35d837bd559..c4f9af8c032 100644 --- a/themes/starter/index.js +++ b/themes/starter/index.js @@ -159,7 +159,7 @@ const LayoutSlug = props => {
{lock && } - {!lock && ( + {!lock && post && (
From c8d90a41660c0fff27601b4316880eddbfe8ae8f Mon Sep 17 00:00:00 2001 From: anime Date: Fri, 8 Nov 2024 00:30:44 +0800 Subject: [PATCH 02/25] =?UTF-8?q?fix(=E4=BD=BF=E6=89=80=E6=9C=89=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E7=9A=84404=E8=83=BD=E5=A4=9F=E6=AD=A3=E5=B8=B8?= =?UTF-8?q?=E8=BF=90=E8=BD=AC):=20=E5=90=8C=E6=97=B6=E8=AE=A9=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=96=87=E7=AB=A0DOM=E8=8A=82=E7=82=B9=E4=B9=9F?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E5=85=AC=E5=91=8A=E6=A0=8F=E7=AD=89=E5=85=B6?= =?UTF-8?q?=E4=BB=96=E4=BD=8D=E7=BD=AE=E7=9A=84=E5=B9=B2=E6=89=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/WordCount.js | 2 +- themes/commerce/index.js | 2 +- themes/example/index.js | 2 +- themes/fukasawa/index.js | 2 +- themes/gitbook/index.js | 4 ++-- themes/heo/index.js | 2 +- themes/hexo/index.js | 4 ++-- themes/landing/index.js | 2 +- themes/magzine/index.js | 2 +- themes/matery/components/WordCount.js | 2 +- themes/matery/index.js | 4 ++-- themes/medium/index.js | 2 +- themes/movie/index.js | 4 ++-- themes/nav/index.js | 2 +- themes/next/components/WordCount.js | 2 +- themes/next/index.js | 2 +- themes/nobelium/index.js | 2 +- themes/photo/index.js | 4 ++-- themes/plog/index.js | 2 +- themes/simple/index.js | 2 +- 20 files changed, 25 insertions(+), 25 deletions(-) diff --git a/components/WordCount.js b/components/WordCount.js index 315c58d39a7..7f7066cf1d6 100644 --- a/components/WordCount.js +++ b/components/WordCount.js @@ -28,7 +28,7 @@ export default function WordCount() { * 更新字数统计和阅读时间 */ function countWords() { - const articleText = deleteHtmlTag(document.getElementById('notion-article')?.innerHTML) + const articleText = deleteHtmlTag(document.querySelector('#article-wrapper #notion-article')?.innerHTML) const wordCount = fnGetCpmisWords(articleText) // 阅读速度 300-500每分钟 document.getElementById('wordCount').innerHTML = wordCount diff --git a/themes/commerce/index.js b/themes/commerce/index.js index f415f8e5200..9efbd684c3e 100644 --- a/themes/commerce/index.js +++ b/themes/commerce/index.js @@ -304,7 +304,7 @@ const Layout404 = props => { // 延时3秒如果加载失败就返回首页 setTimeout(() => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/').then(() => { // console.log('找不到页面', router.asPath) diff --git a/themes/example/index.js b/themes/example/index.js index 2d6ecfefaee..d78e20a4561 100644 --- a/themes/example/index.js +++ b/themes/example/index.js @@ -162,7 +162,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/fukasawa/index.js b/themes/fukasawa/index.js index 2167a95027f..0e2cf9d3623 100644 --- a/themes/fukasawa/index.js +++ b/themes/fukasawa/index.js @@ -143,7 +143,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/gitbook/index.js b/themes/gitbook/index.js index 9898f0aeeb9..0fac89b5f9b 100644 --- a/themes/gitbook/index.js +++ b/themes/gitbook/index.js @@ -255,7 +255,7 @@ const LayoutIndex = props => { // 重定向到指定文章 router.push(index).then(() => { setTimeout(() => { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { console.log( '请检查您的Notion数据库中是否包含此slug页面: ', @@ -309,7 +309,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/heo/index.js b/themes/heo/index.js index 42bfcb83f45..aafe116e32b 100644 --- a/themes/heo/index.js +++ b/themes/heo/index.js @@ -273,7 +273,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/hexo/index.js b/themes/hexo/index.js index fe90a26b829..49d20a31447 100644 --- a/themes/hexo/index.js +++ b/themes/hexo/index.js @@ -269,7 +269,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) @@ -333,7 +333,7 @@ const Layout404 = props => { // 延时3秒如果加载失败就返回首页 setTimeout(() => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/').then(() => { // console.log('找不到页面', router.asPath) diff --git a/themes/landing/index.js b/themes/landing/index.js index 62d8f9db844..9dbb3be6158 100644 --- a/themes/landing/index.js +++ b/themes/landing/index.js @@ -82,7 +82,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/magzine/index.js b/themes/magzine/index.js index c5814d36003..e5165bdd771 100644 --- a/themes/magzine/index.js +++ b/themes/magzine/index.js @@ -155,7 +155,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/matery/components/WordCount.js b/themes/matery/components/WordCount.js index 8e4af32a6f5..d7d7c02b526 100644 --- a/themes/matery/components/WordCount.js +++ b/themes/matery/components/WordCount.js @@ -29,7 +29,7 @@ export default function WordCount() { * 更新字数统计和阅读时间 */ function countWords() { - const articleText = deleteHtmlTag(document.getElementById('notion-article')?.innerHTML) + const articleText = deleteHtmlTag(document.querySelector('#article-wrapper #notion-article')?.innerHTML) const wordCount = fnGetCpmisWords(articleText) // 阅读速度 300-500每分钟 document.getElementById('wordCount').innerHTML = wordCount diff --git a/themes/matery/index.js b/themes/matery/index.js index 13a5992f094..cb844a5df66 100644 --- a/themes/matery/index.js +++ b/themes/matery/index.js @@ -231,7 +231,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) @@ -320,7 +320,7 @@ const Layout404 = props => { setTimeout(() => { const article = typeof document !== 'undefined' && - document.getElementById('notion-article') + document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/').then(() => { // console.log('找不到页面', router.asPath) diff --git a/themes/medium/index.js b/themes/medium/index.js index b51db693622..dfd37ce2cc0 100644 --- a/themes/medium/index.js +++ b/themes/medium/index.js @@ -191,7 +191,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/movie/index.js b/themes/movie/index.js index c205d6d02b8..6e969b7d7f3 100644 --- a/themes/movie/index.js +++ b/themes/movie/index.js @@ -156,7 +156,7 @@ const LayoutSlug = props => { // 用js 实现将页面中的多个视频聚合为一个分集的视频 function combineVideo() { // 找到 id 为 notion-article 的元素 - const notionArticle = document.getElementById('notion-article') + const notionArticle = document.querySelector('#article-wrapper #notion-article') if (!notionArticle) return // 如果找不到对应的元素,则退出函数 // 找到所有的 .notion-asset-wrapper 元素 @@ -291,7 +291,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/nav/index.js b/themes/nav/index.js index 48b3aaba64e..ed405186e97 100755 --- a/themes/nav/index.js +++ b/themes/nav/index.js @@ -261,7 +261,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/next/components/WordCount.js b/themes/next/components/WordCount.js index ccf146d453b..6cfd1cc6336 100644 --- a/themes/next/components/WordCount.js +++ b/themes/next/components/WordCount.js @@ -23,7 +23,7 @@ export default function WordCount() { * 更新字数统计和阅读时间 */ function countWords() { - const articleText = deleteHtmlTag(document.getElementById('notion-article')?.innerHTML) + const articleText = deleteHtmlTag(document.querySelector('#article-wrapper #notion-article')?.innerHTML) const wordCount = fnGetCpmisWords(articleText) // 阅读速度 300-500每分钟 document.getElementById('wordCount').innerHTML = wordCount diff --git a/themes/next/index.js b/themes/next/index.js index b7408f8a327..8c70fb8ff81 100644 --- a/themes/next/index.js +++ b/themes/next/index.js @@ -328,7 +328,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/nobelium/index.js b/themes/nobelium/index.js index 44afc5c004a..c8324277afa 100644 --- a/themes/nobelium/index.js +++ b/themes/nobelium/index.js @@ -227,7 +227,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/photo/index.js b/themes/photo/index.js index 64f6a1f06b5..b76eef756ce 100644 --- a/themes/photo/index.js +++ b/themes/photo/index.js @@ -156,7 +156,7 @@ const LayoutSlug = props => { // 用js 实现将页面中的多个视频聚合为一个分集的视频 function combineVideo() { // 找到 id 为 notion-article 的元素 - const notionArticle = document.getElementById('notion-article') + const notionArticle = document.querySelector('#article-wrapper #notion-article') if (!notionArticle) return // 如果找不到对应的元素,则退出函数 // 找到所有的 .notion-asset-wrapper 元素 @@ -291,7 +291,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/plog/index.js b/themes/plog/index.js index b715206f42a..4de0ba0a288 100644 --- a/themes/plog/index.js +++ b/themes/plog/index.js @@ -182,7 +182,7 @@ const LayoutSlug = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) diff --git a/themes/simple/index.js b/themes/simple/index.js index 29516202e1a..020bbf4e215 100644 --- a/themes/simple/index.js +++ b/themes/simple/index.js @@ -273,7 +273,7 @@ const Layout404 = props => { setTimeout( () => { if (isBrowser) { - const article = document.getElementById('notion-article') + const article = document.querySelector('#article-wrapper #notion-article') if (!article) { router.push('/404').then(() => { console.warn('找不到页面', router.asPath) From 734f60593a3bd21f5b7232c18c58911847ff5417 Mon Sep 17 00:00:00 2001 From: Zhenye Dong Date: Sun, 10 Nov 2024 17:57:05 +0800 Subject: [PATCH 03/25] refactor: improve version management - Move version number from env to package.json - Add dynamic version loading with fallback - Improve error handling for version loading --- blog.config.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/blog.config.js b/blog.config.js index 772cae9b671..ed0721cccf6 100644 --- a/blog.config.js +++ b/blog.config.js @@ -548,7 +548,15 @@ const BLOG = { process.env.npm_lifecycle_event === 'export', // 在打包过程中默认开启缓存,开发或运行时开启此功能意义不大。 isProd: process.env.VERCEL_ENV === 'production' || process.env.EXPORT, // distinguish between development and production environment (ref: https://vercel.com/docs/environment-variables#system-environment-variables) BUNDLE_ANALYZER: process.env.ANALYZE === 'true' || false, // 是否展示编译依赖内容与大小 - VERSION: process.env.NEXT_PUBLIC_VERSION // 版本号 + VERSION: (() => { + try { + // 优先使用环境变量,否则从package.json中获取版本号 + return process.env.NEXT_PUBLIC_VERSION || require('./package.json').version + } catch (error) { + console.warn('Failed to load package.json version:', error) + return '1.0.0' // 缺省版本号 + } + })() } module.exports = BLOG From e53db9ef727ae4b0e2229232ad264684b6462faf Mon Sep 17 00:00:00 2001 From: Zhenye Dong Date: Sun, 10 Nov 2024 17:57:34 +0800 Subject: [PATCH 04/25] Remove .env.local file --- .env.local | 176 ----------------------------------------------------- 1 file changed, 176 deletions(-) delete mode 100644 .env.local diff --git a/.env.local b/.env.local deleted file mode 100644 index 6952a6160be..00000000000 --- a/.env.local +++ /dev/null @@ -1,176 +0,0 @@ -# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables -NEXT_PUBLIC_VERSION=4.7.7 - - -# 可在此添加环境变量,去掉最左边的(# )注释即可 -# Notion页面ID,必须 -# NOTION_PAGE_ID=097e5f674880459d8e1b4407758dc4fb - -# 非必须 -# NEXT_PUBLIC_PSEUDO_STATIC= -# NEXT_PUBLIC_REVALIDATE_SECOND= -# NEXT_PUBLIC_THEME=matery -# NEXT_PUBLIC_THEME_SWITCH= -# NEXT_PUBLIC_LANG= -# NEXT_PUBLIC_APPEARANCE= -# NEXT_PUBLIC_APPEARANCE_DARK_TIME= -# NEXT_PUBLIC_GREETING_WORDS= -# NEXT_PUBLIC_CUSTOM_MENU= -# NEXT_PUBLIC_AUTHOR= -# NEXT_PUBLIC_BIO= -# NEXT_PUBLIC_LINK= -# NEXT_PUBLIC_KEYWORD= -# NEXT_PUBLIC_CONTACT_EMAIL= -# NEXT_PUBLIC_CONTACT_WEIBO= -# NEXT_PUBLIC_CONTACT_TWITTER= -# NEXT_PUBLIC_CONTACT_GITHUB= -# NEXT_PUBLIC_CONTACT_TELEGRAM= -# NEXT_PUBLIC_CONTACT_LINKEDIN= -# NEXT_PUBLIC_CONTACT_INSTAGRAM= -# NEXT_PUBLIC_CONTACT_BILIBILI= -# NEXT_PUBLIC_CONTACT_YOUTUBE= -# NEXT_PUBLIC_FAVICON= -# NEXT_PUBLIC_FONT_STYLE= -# NEXT_PUBLIC_FONT_URL= -# NEXT_PUBLIC_FONT_SANS= -# NEXT_PUBLIC_FONT_SERIF= -# NEXT_PUBLIC_FONT_AWESOME_PATH= -# NEXT_PUBLIC_PRISM_THEME_PREFIX_PATH= -# NEXT_PUBLIC_PRISM_THEME_SWITCH= -# NEXT_PUBLIC_PRISM_THEME_LIGHT_PATH= -# NEXT_PUBLIC_PRISM_THEME_DARK_PATH= -# NEXT_PUBLIC_CODE_MAC_BAR= -# NEXT_PUBLIC_CODE_LINE_NUMBERS= -# NEXT_PUBLIC_CODE_COLLAPSE= -# NEXT_PUBLIC_CODE_COLLAPSE_EXPAND_DEFAULT= -# NEXT_PUBLIC_MERMAID_CDN= -# NEXT_PUBLIC_QR_CODE_CDN= -# NEXT_PUBLIC_BACKGROUND_LIGHT= -# NEXT_PUBLIC_BACKGROUND_DARK= -# NEXT_PUBLIC_SUB_PATH= -# NEXT_PUBLIC_POST_SHARE_BAR= -# NEXT_PUBLIC_POST_SHARE_SERVICES= -# NEXT_PUBLIC_POST_URL_PREFIX= -# NEXT_PUBLIC_POST_LIST_STYLE= -# NEXT_PUBLIC_POST_PREVIEW= -# NEXT_PUBLIC_POST_RECOMMEND_COUNT= -# NEXT_PUBLIC_POSTS_PER_PAGE= -# NEXT_PUBLIC_POST_SORT_BY= -# NEXT_PUBLIC_ALGOLIA_APP_ID= -# ALGOLIA_ADMIN_APP_KEY= -# NEXT_PUBLIC_ALGOLIA_SEARCH_ONLY_APP_KEY= -# NEXT_PUBLIC_ALGOLIA_INDEX= -# NEXT_PUBLIC_PREVIEW_CATEGORY_COUNT= -# NEXT_PUBLIC_PREVIEW_TAG_COUNT= -# NEXT_PUBLIC_POST_TITLE_ICON= -# NEXT_PUBLIC_POST_DISABLE_GALLERY_CLICK= -# NEXT_PUBLIC_FIREWORKS= -# NEXT_PUBLIC_FIREWORKS_COLOR= -# NEXT_PUBLIC_SAKURA= -# NEXT_PUBLIC_NEST= -# NEXT_PUBLIC_FLUTTERINGRIBBON= -# NEXT_PUBLIC_RIBBON= -# NEXT_PUBLIC_STARRY_SKY= -# NEXT_PUBLIC_CHATBASE_ID= -# NEXT_PUBLIC_WEB_WHIZ_ENABLED= -# NEXT_PUBLIC_WEB_WHIZ_BASE_URL= -# NEXT_PUBLIC_WEB_WHIZ_CHAT_BOT_ID= -# NEXT_PUBLIC_WIDGET_PET= -# NEXT_PUBLIC_WIDGET_PET_LINK= -# NEXT_PUBLIC_WIDGET_PET_SWITCH_THEME= -# NEXT_PUBLIC_MUSIC_PLAYER= -# NEXT_PUBLIC_MUSIC_PLAYER_VISIBLE= -# NEXT_PUBLIC_MUSIC_PLAYER_AUTO_PLAY= -# NEXT_PUBLIC_MUSIC_PLAYER_LRC_TYPE= -# NEXT_PUBLIC_MUSIC_PLAYER_CDN_URL= -# NEXT_PUBLIC_MUSIC_PLAYER_ORDER= -# NEXT_PUBLIC_MUSIC_PLAYER_AUDIO_LIST= -# NEXT_PUBLIC_MUSIC_PLAYER_METING= -# NEXT_PUBLIC_MUSIC_PLAYER_METING_SERVER= -# NEXT_PUBLIC_MUSIC_PLAYER_METING_ID= -# NEXT_PUBLIC_MUSIC_PLAYER_METING_LRC_TYPE= -# NEXT_PUBLIC_COMMENT_ARTALK_SERVER= -# NEXT_PUBLIC_COMMENT_ARTALK_JS= -# NEXT_PUBLIC_COMMENT_ARTALK_CSS= -# NEXT_PUBLIC_COMMENT_ENV_ID= -# NEXT_PUBLIC_COMMENT_TWIKOO_COUNT_ENABLE= -# NEXT_PUBLIC_COMMENT_TWIKOO_CDN_URL= -# NEXT_PUBLIC_COMMENT_UTTERRANCES_REPO= -# NEXT_PUBLIC_COMMENT_GISCUS_REPO= -# NEXT_PUBLIC_COMMENT_GISCUS_REPO_ID= -# NEXT_PUBLIC_COMMENT_GISCUS_CATEGORY_ID= -# NEXT_PUBLIC_COMMENT_GISCUS_MAPPING= -# NEXT_PUBLIC_COMMENT_GISCUS_REACTIONS_ENABLED= -# NEXT_PUBLIC_COMMENT_GISCUS_EMIT_METADATA= -# NEXT_PUBLIC_COMMENT_GISCUS_INPUT_POSITION= -# NEXT_PUBLIC_COMMENT_GISCUS_LANG= -# NEXT_PUBLIC_COMMENT_GISCUS_LOADING= -# NEXT_PUBLIC_COMMENT_GISCUS_CROSSORIGIN= -# NEXT_PUBLIC_COMMENT_CUSDIS_APP_ID= -# NEXT_PUBLIC_COMMENT_CUSDIS_HOST= -# NEXT_PUBLIC_COMMENT_CUSDIS_SCRIPT_SRC= -# NEXT_PUBLIC_COMMENT_GITALK_REPO= -# NEXT_PUBLIC_COMMENT_GITALK_OWNER= -# NEXT_PUBLIC_COMMENT_GITALK_ADMIN= -# NEXT_PUBLIC_COMMENT_GITALK_CLIENT_ID= -# NEXT_PUBLIC_COMMENT_GITALK_CLIENT_SECRET= -# NEXT_PUBLIC_COMMENT_GITALK_JS_CDN_URL= -# NEXT_PUBLIC_COMMENT_GITALK_CSS_CDN_URL= -# NEXT_PUBLIC_COMMENT_GITTER_ROOM= -# NEXT_PUBLIC_COMMENT_DAO_VOICE_ID= -# NEXT_PUBLIC_COMMENT_TIDIO_ID= -# NEXT_PUBLIC_VALINE_CDN= -# NEXT_PUBLIC_VALINE_ID= -# NEXT_PUBLIC_VALINE_KEY= -# NEXT_PUBLIC_VALINE_SERVER_URLS= -# NEXT_PUBLIC_VALINE_PLACEHOLDER= -# NEXT_PUBLIC_WALINE_SERVER_URL= -# NEXT_PUBLIC_WALINE_RECENT= -# NEXT_PUBLIC_WEBMENTION_ENABLE= -# NEXT_PUBLIC_WEBMENTION_AUTH= -# NEXT_PUBLIC_WEBMENTION_HOSTNAME= -# NEXT_PUBLIC_TWITTER_USERNAME= -# NEXT_PUBLIC_WEBMENTION_TOKEN= -# NEXT_PUBLIC_ANALYTICS_VERCEL= -# NEXT_PUBLIC_ANALYTICS_BUSUANZI_ENABLE= -# NEXT_PUBLIC_ANALYTICS_BAIDU_ID= -# NEXT_PUBLIC_ANALYTICS_CNZZ_ID= -# NEXT_PUBLIC_ANALYTICS_GOOGLE_ID= -# NEXT_PUBLIC_ANALYTICS_ACKEE_TRACKER= -# NEXT_PUBLIC_ANALYTICS_ACKEE_DATA_SERVER= -# NEXT_PUBLIC_ANALYTICS_ACKEE_DOMAIN_ID= -# NEXT_PUBLIC_SEO_GOOGLE_SITE_VERIFICATION= -# NEXT_PUBLIC_SEO_BAIDU_SITE_VERIFICATION= -# NEXT_PUBLIC_ADSENSE_GOOGLE_ID= -# NEXT_PUBLIC_ADSENSE_GOOGLE_TEST= -# NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_IN_ARTICLE= -# NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_FLOW= -# NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_NATIVE= -# NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_AUTO= -# NEXT_PUBLIC_WWAD_ID= -# NEXT_PUBLIC_WWADS_AD_BLOCK_DETECT= -# NEXT_PUBLIC_NOTION_PROPERTY_PASSWORD= -# NEXT_PUBLIC_NOTION_PROPERTY_TYPE= -# NEXT_PUBLIC_NOTION_PROPERTY_TYPE_POST= -# NEXT_PUBLIC_NOTION_PROPERTY_TYPE_PAGE= -# NEXT_PUBLIC_NOTION_PROPERTY_TYPE_NOTICE= -# NEXT_PUBLIC_NOTION_PROPERTY_TYPE_MENU= -# NEXT_PUBLIC_NOTION_PROPERTY_TYPE_SUB_MENU= -# NEXT_PUBLIC_NOTION_PROPERTY_TITLE= -# NEXT_PUBLIC_NOTION_PROPERTY_STATUS= -# NEXT_PUBLIC_NOTION_PROPERTY_STATUS_PUBLISH= -# NEXT_PUBLIC_NOTION_PROPERTY_STATUS_INVISIBLE= -# NEXT_PUBLIC_NOTION_PROPERTY_SUMMARY= -# NEXT_PUBLIC_NOTION_PROPERTY_SLUG= -# NEXT_PUBLIC_NOTION_PROPERTY_CATEGORY= -# NEXT_PUBLIC_NOTION_PROPERTY_DATE= -# NEXT_PUBLIC_NOTION_PROPERTY_TAGS= -# NEXT_PUBLIC_NOTION_PROPERTY_ICON= -# NEXT_PUBLIC_ENABLE_RSS= -# NEXT_PUBLIC_IS_TAG_COLOR_DISTINGUISHED= -# MAILCHIMP_LIST_ID= -# MAILCHIMP_API_KEY= -# NEXT_PUBLIC_DEBUG= -# ENABLE_CACHE= -# VERCEL_ENV= -# NEXT_PUBLIC_VERSION= From 04ee6b04c5015bcd3febdeef71e83b0defbf06bc Mon Sep 17 00:00:00 2001 From: Zhenye Dong Date: Sun, 10 Nov 2024 17:58:34 +0800 Subject: [PATCH 05/25] Add .env.example file with no pre-enabled configuration --- .env.example | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 00000000000..eb29e18cf32 --- /dev/null +++ b/.env.example @@ -0,0 +1,175 @@ +# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables + +# 可在此添加环境变量,去掉最左边的(# )注释即可 +# Notion页面ID,必须 +# NOTION_PAGE_ID=097e5f674880459d8e1b4407758dc4fb + +# 非必须 +# NEXT_PUBLIC_VERSION= +# NEXT_PUBLIC_PSEUDO_STATIC= +# NEXT_PUBLIC_REVALIDATE_SECOND= +# NEXT_PUBLIC_THEME=matery +# NEXT_PUBLIC_THEME_SWITCH= +# NEXT_PUBLIC_LANG= +# NEXT_PUBLIC_APPEARANCE= +# NEXT_PUBLIC_APPEARANCE_DARK_TIME= +# NEXT_PUBLIC_GREETING_WORDS= +# NEXT_PUBLIC_CUSTOM_MENU= +# NEXT_PUBLIC_AUTHOR= +# NEXT_PUBLIC_BIO= +# NEXT_PUBLIC_LINK= +# NEXT_PUBLIC_KEYWORD= +# NEXT_PUBLIC_CONTACT_EMAIL= +# NEXT_PUBLIC_CONTACT_WEIBO= +# NEXT_PUBLIC_CONTACT_TWITTER= +# NEXT_PUBLIC_CONTACT_GITHUB= +# NEXT_PUBLIC_CONTACT_TELEGRAM= +# NEXT_PUBLIC_CONTACT_LINKEDIN= +# NEXT_PUBLIC_CONTACT_INSTAGRAM= +# NEXT_PUBLIC_CONTACT_BILIBILI= +# NEXT_PUBLIC_CONTACT_YOUTUBE= +# NEXT_PUBLIC_FAVICON= +# NEXT_PUBLIC_FONT_STYLE= +# NEXT_PUBLIC_FONT_URL= +# NEXT_PUBLIC_FONT_SANS= +# NEXT_PUBLIC_FONT_SERIF= +# NEXT_PUBLIC_FONT_AWESOME_PATH= +# NEXT_PUBLIC_PRISM_THEME_PREFIX_PATH= +# NEXT_PUBLIC_PRISM_THEME_SWITCH= +# NEXT_PUBLIC_PRISM_THEME_LIGHT_PATH= +# NEXT_PUBLIC_PRISM_THEME_DARK_PATH= +# NEXT_PUBLIC_CODE_MAC_BAR= +# NEXT_PUBLIC_CODE_LINE_NUMBERS= +# NEXT_PUBLIC_CODE_COLLAPSE= +# NEXT_PUBLIC_CODE_COLLAPSE_EXPAND_DEFAULT= +# NEXT_PUBLIC_MERMAID_CDN= +# NEXT_PUBLIC_QR_CODE_CDN= +# NEXT_PUBLIC_BACKGROUND_LIGHT= +# NEXT_PUBLIC_BACKGROUND_DARK= +# NEXT_PUBLIC_SUB_PATH= +# NEXT_PUBLIC_POST_SHARE_BAR= +# NEXT_PUBLIC_POST_SHARE_SERVICES= +# NEXT_PUBLIC_POST_URL_PREFIX= +# NEXT_PUBLIC_POST_LIST_STYLE= +# NEXT_PUBLIC_POST_PREVIEW= +# NEXT_PUBLIC_POST_RECOMMEND_COUNT= +# NEXT_PUBLIC_POSTS_PER_PAGE= +# NEXT_PUBLIC_POST_SORT_BY= +# NEXT_PUBLIC_ALGOLIA_APP_ID= +# ALGOLIA_ADMIN_APP_KEY= +# NEXT_PUBLIC_ALGOLIA_SEARCH_ONLY_APP_KEY= +# NEXT_PUBLIC_ALGOLIA_INDEX= +# NEXT_PUBLIC_PREVIEW_CATEGORY_COUNT= +# NEXT_PUBLIC_PREVIEW_TAG_COUNT= +# NEXT_PUBLIC_POST_TITLE_ICON= +# NEXT_PUBLIC_POST_DISABLE_GALLERY_CLICK= +# NEXT_PUBLIC_FIREWORKS= +# NEXT_PUBLIC_FIREWORKS_COLOR= +# NEXT_PUBLIC_SAKURA= +# NEXT_PUBLIC_NEST= +# NEXT_PUBLIC_FLUTTERINGRIBBON= +# NEXT_PUBLIC_RIBBON= +# NEXT_PUBLIC_STARRY_SKY= +# NEXT_PUBLIC_CHATBASE_ID= +# NEXT_PUBLIC_WEB_WHIZ_ENABLED= +# NEXT_PUBLIC_WEB_WHIZ_BASE_URL= +# NEXT_PUBLIC_WEB_WHIZ_CHAT_BOT_ID= +# NEXT_PUBLIC_WIDGET_PET= +# NEXT_PUBLIC_WIDGET_PET_LINK= +# NEXT_PUBLIC_WIDGET_PET_SWITCH_THEME= +# NEXT_PUBLIC_MUSIC_PLAYER= +# NEXT_PUBLIC_MUSIC_PLAYER_VISIBLE= +# NEXT_PUBLIC_MUSIC_PLAYER_AUTO_PLAY= +# NEXT_PUBLIC_MUSIC_PLAYER_LRC_TYPE= +# NEXT_PUBLIC_MUSIC_PLAYER_CDN_URL= +# NEXT_PUBLIC_MUSIC_PLAYER_ORDER= +# NEXT_PUBLIC_MUSIC_PLAYER_AUDIO_LIST= +# NEXT_PUBLIC_MUSIC_PLAYER_METING= +# NEXT_PUBLIC_MUSIC_PLAYER_METING_SERVER= +# NEXT_PUBLIC_MUSIC_PLAYER_METING_ID= +# NEXT_PUBLIC_MUSIC_PLAYER_METING_LRC_TYPE= +# NEXT_PUBLIC_COMMENT_ARTALK_SERVER= +# NEXT_PUBLIC_COMMENT_ARTALK_JS= +# NEXT_PUBLIC_COMMENT_ARTALK_CSS= +# NEXT_PUBLIC_COMMENT_ENV_ID= +# NEXT_PUBLIC_COMMENT_TWIKOO_COUNT_ENABLE= +# NEXT_PUBLIC_COMMENT_TWIKOO_CDN_URL= +# NEXT_PUBLIC_COMMENT_UTTERRANCES_REPO= +# NEXT_PUBLIC_COMMENT_GISCUS_REPO= +# NEXT_PUBLIC_COMMENT_GISCUS_REPO_ID= +# NEXT_PUBLIC_COMMENT_GISCUS_CATEGORY_ID= +# NEXT_PUBLIC_COMMENT_GISCUS_MAPPING= +# NEXT_PUBLIC_COMMENT_GISCUS_REACTIONS_ENABLED= +# NEXT_PUBLIC_COMMENT_GISCUS_EMIT_METADATA= +# NEXT_PUBLIC_COMMENT_GISCUS_INPUT_POSITION= +# NEXT_PUBLIC_COMMENT_GISCUS_LANG= +# NEXT_PUBLIC_COMMENT_GISCUS_LOADING= +# NEXT_PUBLIC_COMMENT_GISCUS_CROSSORIGIN= +# NEXT_PUBLIC_COMMENT_CUSDIS_APP_ID= +# NEXT_PUBLIC_COMMENT_CUSDIS_HOST= +# NEXT_PUBLIC_COMMENT_CUSDIS_SCRIPT_SRC= +# NEXT_PUBLIC_COMMENT_GITALK_REPO= +# NEXT_PUBLIC_COMMENT_GITALK_OWNER= +# NEXT_PUBLIC_COMMENT_GITALK_ADMIN= +# NEXT_PUBLIC_COMMENT_GITALK_CLIENT_ID= +# NEXT_PUBLIC_COMMENT_GITALK_CLIENT_SECRET= +# NEXT_PUBLIC_COMMENT_GITALK_JS_CDN_URL= +# NEXT_PUBLIC_COMMENT_GITALK_CSS_CDN_URL= +# NEXT_PUBLIC_COMMENT_GITTER_ROOM= +# NEXT_PUBLIC_COMMENT_DAO_VOICE_ID= +# NEXT_PUBLIC_COMMENT_TIDIO_ID= +# NEXT_PUBLIC_VALINE_CDN= +# NEXT_PUBLIC_VALINE_ID= +# NEXT_PUBLIC_VALINE_KEY= +# NEXT_PUBLIC_VALINE_SERVER_URLS= +# NEXT_PUBLIC_VALINE_PLACEHOLDER= +# NEXT_PUBLIC_WALINE_SERVER_URL= +# NEXT_PUBLIC_WALINE_RECENT= +# NEXT_PUBLIC_WEBMENTION_ENABLE= +# NEXT_PUBLIC_WEBMENTION_AUTH= +# NEXT_PUBLIC_WEBMENTION_HOSTNAME= +# NEXT_PUBLIC_TWITTER_USERNAME= +# NEXT_PUBLIC_WEBMENTION_TOKEN= +# NEXT_PUBLIC_ANALYTICS_VERCEL= +# NEXT_PUBLIC_ANALYTICS_BUSUANZI_ENABLE= +# NEXT_PUBLIC_ANALYTICS_BAIDU_ID= +# NEXT_PUBLIC_ANALYTICS_CNZZ_ID= +# NEXT_PUBLIC_ANALYTICS_GOOGLE_ID= +# NEXT_PUBLIC_ANALYTICS_ACKEE_TRACKER= +# NEXT_PUBLIC_ANALYTICS_ACKEE_DATA_SERVER= +# NEXT_PUBLIC_ANALYTICS_ACKEE_DOMAIN_ID= +# NEXT_PUBLIC_SEO_GOOGLE_SITE_VERIFICATION= +# NEXT_PUBLIC_SEO_BAIDU_SITE_VERIFICATION= +# NEXT_PUBLIC_ADSENSE_GOOGLE_ID= +# NEXT_PUBLIC_ADSENSE_GOOGLE_TEST= +# NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_IN_ARTICLE= +# NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_FLOW= +# NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_NATIVE= +# NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_AUTO= +# NEXT_PUBLIC_WWAD_ID= +# NEXT_PUBLIC_WWADS_AD_BLOCK_DETECT= +# NEXT_PUBLIC_NOTION_PROPERTY_PASSWORD= +# NEXT_PUBLIC_NOTION_PROPERTY_TYPE= +# NEXT_PUBLIC_NOTION_PROPERTY_TYPE_POST= +# NEXT_PUBLIC_NOTION_PROPERTY_TYPE_PAGE= +# NEXT_PUBLIC_NOTION_PROPERTY_TYPE_NOTICE= +# NEXT_PUBLIC_NOTION_PROPERTY_TYPE_MENU= +# NEXT_PUBLIC_NOTION_PROPERTY_TYPE_SUB_MENU= +# NEXT_PUBLIC_NOTION_PROPERTY_TITLE= +# NEXT_PUBLIC_NOTION_PROPERTY_STATUS= +# NEXT_PUBLIC_NOTION_PROPERTY_STATUS_PUBLISH= +# NEXT_PUBLIC_NOTION_PROPERTY_STATUS_INVISIBLE= +# NEXT_PUBLIC_NOTION_PROPERTY_SUMMARY= +# NEXT_PUBLIC_NOTION_PROPERTY_SLUG= +# NEXT_PUBLIC_NOTION_PROPERTY_CATEGORY= +# NEXT_PUBLIC_NOTION_PROPERTY_DATE= +# NEXT_PUBLIC_NOTION_PROPERTY_TAGS= +# NEXT_PUBLIC_NOTION_PROPERTY_ICON= +# NEXT_PUBLIC_ENABLE_RSS= +# NEXT_PUBLIC_IS_TAG_COLOR_DISTINGUISHED= +# MAILCHIMP_LIST_ID= +# MAILCHIMP_API_KEY= +# NEXT_PUBLIC_DEBUG= +# ENABLE_CACHE= +# VERCEL_ENV= +# NEXT_PUBLIC_VERSION= From 77c2c5903ad32d4408d9c4c76b83975647bddf0d Mon Sep 17 00:00:00 2001 From: Zhenye Dong Date: Sun, 10 Nov 2024 17:59:59 +0800 Subject: [PATCH 06/25] Add .env.local into .gitignore file for better privacy and practice --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b400f485732..a0811bd90d7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,7 @@ yarn-debug.log* yarn-error.log* # local env files -# .env.local # 版本号放在此环境变量中 +.env.local .env.development.local .env.test.local .env.production.local From fe90d94d881141bbd3a7ef9751250ac77d89eb12 Mon Sep 17 00:00:00 2001 From: Zhenye Dong Date: Sun, 10 Nov 2024 18:01:04 +0800 Subject: [PATCH 07/25] docs: improve environment variables documentation --- CONTRIBUTING.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5fffb37aca2..9fde0549768 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,7 @@ - [Setup](#setup) - [Creating new themes](#creating-new-themes) - [Adding localizations](#adding-localizations) +- [Environment Variables](#environment-variables) Thanks for considering to contribute! @@ -42,6 +43,19 @@ localization! Follow these steps to add a new localization: 3. Add your language config to [lang.js][lang.js]. 4. [Create a PR][pr] with your localization updates. +## Environment Variables + +NotionNext uses environment variables for configuration. To set up your development environment: + +1. Copy `.env.example` to `.env.local` +2. Fill in the required values in `.env.local` +3. Never commit `.env.local` to version control + +The configuration priority is: +1. Notion Config Table (highest) +2. Environment Variables +3. blog.config.js (lowest) + [fork]: https://github.com/tangly1024/NotionNext/fork [pr]: https://github.com/tangly1024/NotionNext/compare [next.js]: https://github.com/vercel/next.js From b6a6a7215daa0f0fc1a7fa02fcdd6f2ca7db2f9c Mon Sep 17 00:00:00 2001 From: Zhenye Dong Date: Sun, 10 Nov 2024 18:11:21 +0800 Subject: [PATCH 08/25] chore: echo $npm_package_version for dev --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index dff2f46a9f5..6a87045eee4 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "post-build": "next-sitemap --config next-sitemap.config.js", "export": "cross-env EXPORT=true next build && next-sitemap --config next-sitemap.config.js", "bundle-report": "cross-env ANALYZE=true next build", - "build-all-in-dev": "cross-env VERCEL_ENV=production next build" + "build-all-in-dev": "cross-env VERCEL_ENV=production next build", + "version": "echo $npm_package_version" }, "dependencies": { "@clerk/localizations": "^3.0.4", From 4798b5b4225f240ba4a1c668126e5557344025e5 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Wed, 13 Nov 2024 10:16:00 +0800 Subject: [PATCH 09/25] fix starter hero - bug --- themes/starter/components/Hero.js | 34 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/themes/starter/components/Hero.js b/themes/starter/components/Hero.js index 00a43a0666d..9223a534be6 100644 --- a/themes/starter/components/Hero.js +++ b/themes/starter/components/Hero.js @@ -1,11 +1,13 @@ /* eslint-disable @next/next/no-img-element */ import LazyImage from '@/components/LazyImage' import { siteConfig } from '@/lib/config' +import CONFIG from '../config' + /** * 英雄大图区块 */ export const Hero = props => { - const CONFIG = props?.NOTION_CONFIG || CONFIG + const config = props?.NOTION_CONFIG || CONFIG return ( <> {/* */} @@ -20,30 +22,30 @@ export const Hero = props => { data-wow-delay='.2s'> {/* 主标题 */}

- {siteConfig('STARTER_HERO_TITLE_1', null, CONFIG)} + {siteConfig('STARTER_HERO_TITLE_1', null, config)}

{/* 次标题 */}

- {siteConfig('STARTER_HERO_TITLE_2', null, CONFIG)} + {siteConfig('STARTER_HERO_TITLE_2', null, config)}

{/* 按钮组 */}
{/* 产品预览图片 */} - {siteConfig('STARTER_HERO_PREVIEW_IMAGE', null, CONFIG) && ( + {siteConfig('STARTER_HERO_PREVIEW_IMAGE', null, config) && (
{ src={siteConfig( 'STARTER_HERO_PREVIEW_IMAGE', null, - CONFIG + config )} - alt={siteConfig('TITLE', null, CONFIG)} - title={siteConfig('TITLE', null, CONFIG)} + alt={siteConfig('TITLE', null, config)} + title={siteConfig('TITLE', null, config)} className='mx-auto max-w-full rounded-t-xl rounded-tr-xl' />
@@ -104,7 +106,7 @@ export const Hero = props => {
{/* 横幅图片 */} - {siteConfig('STARTER_HERO_BANNER_IMAGE', null, CONFIG) && ( + {siteConfig('STARTER_HERO_BANNER_IMAGE', null, config) && (
{ src={siteConfig( 'STARTER_HERO_BANNER_IMAGE', null, - CONFIG + config )}>
)} From eed08777d1a36fbf96e5b376ca24c32159dcb272 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Wed, 13 Nov 2024 10:50:17 +0800 Subject: [PATCH 10/25] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/db/getSiteData.js | 473 ++++++++++++++++---------------- lib/notion/getNotionConfig.js | 3 +- lib/notion/getPageProperties.js | 12 +- lib/notion/getPostBlocks.js | 125 ++++----- lib/sitemap.xml.js | 47 ++-- 5 files changed, 327 insertions(+), 333 deletions(-) diff --git a/lib/db/getSiteData.js b/lib/db/getSiteData.js index 4d615824af2..cefc25f0594 100755 --- a/lib/db/getSiteData.js +++ b/lib/db/getSiteData.js @@ -1,5 +1,4 @@ import BLOG from '@/blog.config' -import { getDataFromCache, setDataToCache } from '@/lib/cache/cache_manager' import { getAllCategories } from '@/lib/notion/getAllCategories' import getAllPageIds from '@/lib/notion/getAllPageIds' import { getAllTags } from '@/lib/notion/getAllTags' @@ -42,7 +41,7 @@ export async function getGlobalData({ const prefix = extractLangPrefix(siteId) // 第一个id站点默认语言 if (index === 0 || locale === prefix) { - data = await getNotionPageData({ + data = await getSiteDataByPageId({ pageId: id, from }) @@ -60,24 +59,241 @@ export async function getGlobalData({ * @param from 请求来源 * @returns {Promise} */ -export async function getNotionPageData({ pageId, from }) { - // 尝试从缓存获取 - const cacheKey = 'page_block_' + pageId - let data = await getDataFromCache(cacheKey) - if (data && data.pageIds?.length > 0) { - console.debug('[API<<--缓存]', `from:${from}`, `root-page-id:${pageId}`) - return data +export async function getSiteDataByPageId({ pageId, from }) { + // 获取NOTION原始数据,此接支持mem缓存。 + const pageRecordMap = await getPage(pageId, from) + // 将Notion数据按规则转成站点数据 + const data = await converNotionToSiteDate(pageId, from, pageRecordMap) + return data +} + +/** + * 获取公告 + */ +async function getNotice(post) { + if (!post) { + return null + } + + post.blockMap = await getPage(post.id, 'data-notice') + return post +} + +/** + * 空的默认数据 + * @param {*} pageId + * @returns + */ +const EmptyData = pageId => { + const empty = { + notice: null, + siteInfo: getSiteInfo({}), + allPages: [ + { + id: 1, + title: `无法获取Notion数据,请检查Notion_ID: \n 当前 ${pageId}`, + summary: + '访问文档获取帮助→ https://tangly1024.com/article/vercel-deploy-notion-next', + status: 'Published', + type: 'Post', + slug: '13a171332816461db29d50e9f575b00d', + publishDay: '2024-11-13', + pageCoverThumbnail: BLOG.HOME_BANNER_IMAGE, + date: { + start_date: '2023-04-24', + lastEditedDay: '2023-04-24', + tagItems: [] + } + } + ], + allNavPages: [], + collection: [], + collectionQuery: {}, + collectionId: null, + collectionView: {}, + viewIds: [], + block: {}, + schema: {}, + tagOptions: [], + categoryOptions: [], + rawMetadata: {}, + customNav: [], + customMenu: [], + postCount: 1, + pageIds: [], + latestPosts: [] + } + return empty +} + +/** + * 将Notion数据转站点数据 + * 这里统一对数据格式化 + * @returns {Promise} + */ +async function converNotionToSiteDate(pageId, from, pageRecordMap) { + if (!pageRecordMap) { + console.error('can`t get Notion Data ; Which id is: ', pageId) + return {} + } + pageId = idToUuid(pageId) + let block = pageRecordMap.block || {} + const rawMetadata = block[pageId]?.value + // Check Type Page-Database和Inline-Database + if ( + rawMetadata?.type !== 'collection_view_page' && + rawMetadata?.type !== 'collection_view' + ) { + console.error(`pageId "${pageId}" is not a database`) + return EmptyData(pageId) + } + const collection = Object.values(pageRecordMap.collection)[0]?.value || {} + const collectionId = rawMetadata?.collection_id + const collectionQuery = pageRecordMap.collection_query + const collectionView = pageRecordMap.collection_view + const schema = collection?.schema + + const viewIds = rawMetadata?.view_ids + const collectionData = [] + + const pageIds = getAllPageIds( + collectionQuery, + collectionId, + collectionView, + viewIds + ) + + if (pageIds?.length === 0) { + console.error( + '获取到的文章列表为空,请检查notion模板', + collectionQuery, + collection, + collectionView, + viewIds, + pageRecordMap + ) } else { - // 从接口读取 - data = await getDataBaseInfoByNotionAPI({ pageId, from }) - // 存入缓存 - if (data) { - await setDataToCache(cacheKey, data) + // console.log('有效Page数量', pageIds?.length) + } + + // 抓取主数据库最多抓取1000个blocks,溢出的数block这里统一抓取一遍 + const blockIdsNeedFetch = [] + for (let i = 0; i < pageIds.length; i++) { + const id = pageIds[i] + const value = block[id]?.value + if (!value) { + blockIdsNeedFetch.push(id) } } + const fetchedBlocks = await fetchInBatches(blockIdsNeedFetch) + block = Object.assign({}, block, fetchedBlocks) - // 返回给前端的数据做处理 - return data + // 获取每篇文章基础数据 + for (let i = 0; i < pageIds.length; i++) { + const id = pageIds[i] + const value = block[id]?.value || fetchedBlocks[id]?.value + const properties = + (await getPageProperties( + id, + value, + schema, + null, + getTagOptions(schema) + )) || null + + if (properties) { + collectionData.push(properties) + } + } + + // 站点配置优先读取配置表格,否则读取blog.config.js 文件 + const NOTION_CONFIG = (await getConfigMapFromConfigPage(collectionData)) || {} + + // 处理每一条数据的字段 + collectionData.forEach(function (element) { + adjustPageProperties(element, NOTION_CONFIG) + }) + + // 站点基础信息 + const siteInfo = getSiteInfo({ collection, block, pageId }) + + // 文章计数 + let postCount = 0 + + // 查找所有的Post和Page + const allPages = collectionData.filter(post => { + if (post?.type === 'Post' && post.status === 'Published') { + postCount++ + } + return ( + post && + post?.slug && + // !post?.slug?.startsWith('http') && + (post?.status === 'Invisible' || post?.status === 'Published') + ) + }) + + // Sort by date + if (siteConfig('POSTS_SORT_BY', '', NOTION_CONFIG) === 'date') { + allPages.sort((a, b) => { + return b?.publishDate - a?.publishDate + }) + } + + const notice = await getNotice( + collectionData.filter(post => { + return ( + post && + post?.type && + post?.type === 'Notice' && + post.status === 'Published' + ) + })?.[0] + ) + // 所有分类 + const categoryOptions = getAllCategories({ + allPages, + categoryOptions: getCategoryOptions(schema) + }) + // 所有标签 + const tagOptions = getAllTags({ + allPages, + tagOptions: getTagOptions(schema), + NOTION_CONFIG + }) + // 旧的菜单 + const customNav = getCustomNav({ + allPages: collectionData.filter( + post => post?.type === 'Page' && post.status === 'Published' + ) + }) + // 新的菜单 + const customMenu = await getCustomMenu({ collectionData, NOTION_CONFIG }) + const latestPosts = getLatestPosts({ allPages, from, latestPostCount: 6 }) + const allNavPages = getNavPages({ allPages }) + + return { + NOTION_CONFIG, + notice, + siteInfo, + allPages, + allNavPages, + collection, + collectionQuery, + collectionId, + collectionView, + viewIds, + block, + schema, + tagOptions, + categoryOptions, + rawMetadata, + customNav, + customMenu, + postCount, + pageIds, + latestPosts + } } /** @@ -404,228 +620,3 @@ export function getNavPages({ allPages }) { ext: item.ext || {} })) } - -/** - * 获取公告 - */ -async function getNotice(post) { - if (!post) { - return null - } - - post.blockMap = await getPage(post.id, 'data-notice') - return post -} - -// 没有数据时返回 -const EmptyData = pageId => { - const empty = { - notice: null, - siteInfo: getSiteInfo({}), - allPages: [ - { - id: 1, - title: `无法获取Notion数据,请检查Notion_ID: \n 当前 ${pageId}`, - summary: - '访问文档获取帮助→ https://tangly1024.com/article/vercel-deploy-notion-next', - status: 'Published', - type: 'Post', - slug: '13a171332816461db29d50e9f575b00d', - pageCoverThumbnail: BLOG.HOME_BANNER_IMAGE, - date: { - start_date: '2023-04-24', - lastEditedDay: '2023-04-24', - tagItems: [] - } - } - ], - allNavPages: [], - collection: [], - collectionQuery: {}, - collectionId: null, - collectionView: {}, - viewIds: [], - block: {}, - schema: {}, - tagOptions: [], - categoryOptions: [], - rawMetadata: {}, - customNav: [], - customMenu: [], - postCount: 1, - pageIds: [], - latestPosts: [] - } - return empty -} - -/** - * 调用NotionAPI获取Page数据 - * @returns {Promise} - */ -async function getDataBaseInfoByNotionAPI({ pageId, from }) { - console.log('[Fetching Data]', pageId, from) - const pageRecordMap = await getPage(pageId, from) - if (!pageRecordMap) { - console.error('can`t get Notion Data ; Which id is: ', pageId) - return {} - } - pageId = idToUuid(pageId) - let block = pageRecordMap.block || {} - const rawMetadata = block[pageId]?.value - // Check Type Page-Database和Inline-Database - if ( - rawMetadata?.type !== 'collection_view_page' && - rawMetadata?.type !== 'collection_view' - ) { - console.error(`pageId "${pageId}" is not a database`) - return EmptyData(pageId) - } - const collection = Object.values(pageRecordMap.collection)[0]?.value || {} - const collectionId = rawMetadata?.collection_id - const collectionQuery = pageRecordMap.collection_query - const collectionView = pageRecordMap.collection_view - const schema = collection?.schema - - const viewIds = rawMetadata?.view_ids - const collectionData = [] - - const pageIds = getAllPageIds( - collectionQuery, - collectionId, - collectionView, - viewIds - ) - - if (pageIds?.length === 0) { - console.error( - '获取到的文章列表为空,请检查notion模板', - collectionQuery, - collection, - collectionView, - viewIds, - pageRecordMap - ) - } else { - // console.log('有效Page数量', pageIds?.length) - } - - // 抓取主数据库最多抓取1000个blocks,溢出的数block这里统一抓取一遍 - const blockIdsNeedFetch = [] - for (let i = 0; i < pageIds.length; i++) { - const id = pageIds[i] - const value = block[id]?.value - if (!value) { - blockIdsNeedFetch.push(id) - } - } - const fetchedBlocks = await fetchInBatches(blockIdsNeedFetch) - block = Object.assign({}, block, fetchedBlocks) - - // 获取每篇文章基础数据 - for (let i = 0; i < pageIds.length; i++) { - const id = pageIds[i] - const value = block[id]?.value || fetchedBlocks[id]?.value - const properties = - (await getPageProperties( - id, - value, - schema, - null, - getTagOptions(schema) - )) || null - - if (properties) { - collectionData.push(properties) - } - } - - // 站点配置优先读取配置表格,否则读取blog.config.js 文件 - const NOTION_CONFIG = (await getConfigMapFromConfigPage(collectionData)) || {} - - // 处理每一条数据的字段 - collectionData.forEach(function (element) { - adjustPageProperties(element, NOTION_CONFIG) - }) - - // 站点基础信息 - const siteInfo = getSiteInfo({ collection, block, pageId }) - - // 文章计数 - let postCount = 0 - - // 查找所有的Post和Page - const allPages = collectionData.filter(post => { - if (post?.type === 'Post' && post.status === 'Published') { - postCount++ - } - return ( - post && - post?.slug && - // !post?.slug?.startsWith('http') && - (post?.status === 'Invisible' || post?.status === 'Published') - ) - }) - - // Sort by date - if (siteConfig('POSTS_SORT_BY', '', NOTION_CONFIG) === 'date') { - allPages.sort((a, b) => { - return b?.publishDate - a?.publishDate - }) - } - - const notice = await getNotice( - collectionData.filter(post => { - return ( - post && - post?.type && - post?.type === 'Notice' && - post.status === 'Published' - ) - })?.[0] - ) - // 所有分类 - const categoryOptions = getAllCategories({ - allPages, - categoryOptions: getCategoryOptions(schema) - }) - // 所有标签 - const tagOptions = getAllTags({ - allPages, - tagOptions: getTagOptions(schema), - NOTION_CONFIG - }) - // 旧的菜单 - const customNav = getCustomNav({ - allPages: collectionData.filter( - post => post?.type === 'Page' && post.status === 'Published' - ) - }) - // 新的菜单 - const customMenu = await getCustomMenu({ collectionData, NOTION_CONFIG }) - const latestPosts = getLatestPosts({ allPages, from, latestPostCount: 6 }) - const allNavPages = getNavPages({ allPages }) - - return { - NOTION_CONFIG, - notice, - siteInfo, - allPages, - allNavPages, - collection, - collectionQuery, - collectionId, - collectionView, - viewIds, - block, - schema, - tagOptions, - categoryOptions, - rawMetadata, - customNav, - customMenu, - postCount, - pageIds, - latestPosts - } -} diff --git a/lib/notion/getNotionConfig.js b/lib/notion/getNotionConfig.js index c0ef7c29a5f..ae98736975c 100644 --- a/lib/notion/getNotionConfig.js +++ b/lib/notion/getNotionConfig.js @@ -157,7 +157,8 @@ export async function getConfigMapFromConfigPage(allPages) { // 只导入生效的配置 if (config.enable) { // console.log('[Notion配置]', config.key, config.value) - notionConfig[config.key] = config.value + notionConfig[config.key] = config.value || '' + // 配置不能是undefined,至少是空字符串 } } } diff --git a/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js index d62568cd2c2..27d140476b9 100644 --- a/lib/notion/getPageProperties.js +++ b/lib/notion/getPageProperties.js @@ -180,9 +180,7 @@ export function adjustPageProperties(properties, NOTION_CONFIG) { // 1.按照用户配置的URL_PREFIX 转换一下slug // 2.为文章添加一个href字段,存储最终调整的路径 if (properties.type === 'Post') { - if (siteConfig('POST_URL_PREFIX', '', NOTION_CONFIG)) { - properties.slug = generateCustomizeSlug(properties, NOTION_CONFIG) - } + properties.slug = generateCustomizeSlug(properties, NOTION_CONFIG) properties.href = properties.slug ?? properties.id } else if (properties.type === 'Page') { properties.href = properties.slug ?? properties.id @@ -245,11 +243,9 @@ function generateCustomizeSlug(postProperties, NOTION_CONFIG) { return postProperties.slug } let fullPrefix = '' - const allSlugPatterns = siteConfig( - 'POST_URL_PREFIX', - '', - NOTION_CONFIG - ).split('/') + const allSlugPatterns = + NOTION_CONFIG?.POST_URL_PREFIX || + siteConfig('POST_URL_PREFIX', '', NOTION_CONFIG).split('/') const POST_URL_PREFIX_MAPPING_CATEGORY = siteConfig( 'POST_URL_PREFIX_MAPPING_CATEGORY', diff --git a/lib/notion/getPostBlocks.js b/lib/notion/getPostBlocks.js index 2859345f72c..1f8733f56d3 100644 --- a/lib/notion/getPostBlocks.js +++ b/lib/notion/getPostBlocks.js @@ -10,19 +10,20 @@ import { deepClone, delay } from '../utils' * @param {*} slice * @returns */ -export async function getPage(id, from, slice) { - const cacheKey = 'page_block_' + id +export async function getPage(id, from = null, slice) { + const cacheKey = `page_block_${id}` let pageBlock = await getDataFromCache(cacheKey) if (pageBlock) { - // console.log('[API<<--缓存]', `from:${from}`, cacheKey) - return filterPostBlocks(id, pageBlock, slice) + // console.debug('[API<<--缓存]', `from:${from}`, cacheKey) + return convertNotionBlocksToPost(id, pageBlock, slice) } + // 抓取最新数据 pageBlock = await getPageWithRetry(id, from) if (pageBlock) { await setDataToCache(cacheKey, pageBlock) - return filterPostBlocks(id, pageBlock, slice) + return convertNotionBlocksToPost(id, pageBlock, slice) } return pageBlock } @@ -69,7 +70,7 @@ export async function getPageWithRetry(id, from, retryAttempts = 3) { } /** - * 获取到的页面BLOCK特殊处理 + * Notion页面BLOCK格式化处理 * 1.删除冗余字段 * 2.比如文件、视频、音频、url格式化 * 3.代码块等元素兼容 @@ -78,72 +79,72 @@ export async function getPageWithRetry(id, from, retryAttempts = 3) { * @param {*} slice 截取数量 * @returns */ -function filterPostBlocks(id, blockMap, slice) { +function convertNotionBlocksToPost(id, blockMap, slice) { const clonePageBlock = deepClone(blockMap) let count = 0 const blocksToProcess = Object.keys(clonePageBlock?.block || {}) // 循环遍历文档的每个block for (let i = 0; i < blocksToProcess.length; i++) { - const blockId = blocksToProcess[i] - const b = clonePageBlock?.block[blockId] - - if (slice && slice > 0 && count > slice) { - delete clonePageBlock?.block[blockId] - continue - } - - // 当BlockId等于PageId时移除 - if (b?.value?.id === id) { - // 此block含有敏感信息 - delete b?.value?.properties - continue - } - - count++ - - if (b?.value?.type === 'sync_block' && b?.value?.children) { - const childBlocks = b.value.children - // 移除同步块 - delete clonePageBlock.block[blockId] - // 用子块替代同步块 - childBlocks.forEach((childBlock, index) => { - const newBlockId = `${blockId}_child_${index}` - clonePageBlock.block[newBlockId] = childBlock - blocksToProcess.splice(i + index + 1, 0, newBlockId) - }) - // 重新处理新加入的子块 - i-- - continue - } - - // 处理 c++、c#、汇编等语言名字映射 - if (b?.value?.type === 'code') { - if (b?.value?.properties?.language?.[0][0] === 'C++') { - b.value.properties.language[0][0] = 'cpp' + const blockId = blocksToProcess[i] + const b = clonePageBlock?.block[blockId] + + if (slice && slice > 0 && count > slice) { + delete clonePageBlock?.block[blockId] + continue } - if (b?.value?.properties?.language?.[0][0] === 'C#') { - b.value.properties.language[0][0] = 'csharp' + + // 当BlockId等于PageId时移除 + if (b?.value?.id === id) { + // 此block含有敏感信息 + delete b?.value?.properties + continue } - if (b?.value?.properties?.language?.[0][0] === 'Assembly') { - b.value.properties.language[0][0] = 'asm6502' + + count++ + + if (b?.value?.type === 'sync_block' && b?.value?.children) { + const childBlocks = b.value.children + // 移除同步块 + delete clonePageBlock.block[blockId] + // 用子块替代同步块 + childBlocks.forEach((childBlock, index) => { + const newBlockId = `${blockId}_child_${index}` + clonePageBlock.block[newBlockId] = childBlock + blocksToProcess.splice(i + index + 1, 0, newBlockId) + }) + // 重新处理新加入的子块 + i-- + continue + } + + // 处理 c++、c#、汇编等语言名字映射 + if (b?.value?.type === 'code') { + if (b?.value?.properties?.language?.[0][0] === 'C++') { + b.value.properties.language[0][0] = 'cpp' + } + if (b?.value?.properties?.language?.[0][0] === 'C#') { + b.value.properties.language[0][0] = 'csharp' + } + if (b?.value?.properties?.language?.[0][0] === 'Assembly') { + b.value.properties.language[0][0] = 'asm6502' + } + } + + // 如果是文件,或嵌入式PDF,需要重新加密签名 + if ( + (b?.value?.type === 'file' || + b?.value?.type === 'pdf' || + b?.value?.type === 'video' || + b?.value?.type === 'audio') && + b?.value?.properties?.source?.[0][0] && + b?.value?.properties?.source?.[0][0].indexOf('amazonaws.com') > 0 + ) { + const oldUrl = b?.value?.properties?.source?.[0][0] + const newUrl = `https://notion.so/signed/${encodeURIComponent(oldUrl)}?table=block&id=${b?.value?.id}` + b.value.properties.source[0][0] = newUrl } } - - // 如果是文件,或嵌入式PDF,需要重新加密签名 - if ( - (b?.value?.type === 'file' || - b?.value?.type === 'pdf' || - b?.value?.type === 'video' || - b?.value?.type === 'audio') && - b?.value?.properties?.source?.[0][0] && - b?.value?.properties?.source?.[0][0].indexOf('amazonaws.com') > 0 - ) { - const oldUrl = b?.value?.properties?.source?.[0][0] - const newUrl = `https://notion.so/signed/${encodeURIComponent(oldUrl)}?table=block&id=${b?.value?.id}` - b.value.properties.source[0][0] = newUrl - } -} // 去掉不用的字段 if (id === BLOG.NOTION_PAGE_ID) { diff --git a/lib/sitemap.xml.js b/lib/sitemap.xml.js index c520c0ff094..55b85b9baef 100644 --- a/lib/sitemap.xml.js +++ b/lib/sitemap.xml.js @@ -1,29 +1,34 @@ - -import fs from 'fs' import BLOG from '@/blog.config' +import fs from 'fs' export async function generateSitemapXml({ allPages }) { - const urls = [{ - loc: `${BLOG.LINK}`, - lastmod: new Date().toISOString().split('T')[0], - changefreq: 'daily' - }, { - loc: `${BLOG.LINK}/archive`, - lastmod: new Date().toISOString().split('T')[0], - changefreq: 'daily' - }, { - loc: `${BLOG.LINK}/category`, - lastmod: new Date().toISOString().split('T')[0], - changefreq: 'daily' - }, { - loc: `${BLOG.LINK}/tag`, - lastmod: new Date().toISOString().split('T')[0], - changefreq: 'daily' - }] - + const urls = [ + { + loc: `${BLOG.LINK}`, + lastmod: new Date().toISOString().split('T')[0], + changefreq: 'daily' + }, + { + loc: `${BLOG.LINK}/archive`, + lastmod: new Date().toISOString().split('T')[0], + changefreq: 'daily' + }, + { + loc: `${BLOG.LINK}/category`, + lastmod: new Date().toISOString().split('T')[0], + changefreq: 'daily' + }, + { + loc: `${BLOG.LINK}/tag`, + lastmod: new Date().toISOString().split('T')[0], + changefreq: 'daily' + } + ] // 循环页面生成 allPages?.forEach(post => { - const slugWithoutLeadingSlash = post?.slug?.startsWith('/') ? post?.slug?.slice(1) : post.slug + const slugWithoutLeadingSlash = post?.slug?.startsWith('/') + ? post?.slug?.slice(1) + : post.slug urls.push({ loc: `${BLOG.LINK}/${slugWithoutLeadingSlash}`, lastmod: new Date(post?.publishDay).toISOString().split('T')[0], From cc44d4a8a39808e43f2567b462a053994c75f282 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Wed, 13 Nov 2024 11:11:48 +0800 Subject: [PATCH 11/25] =?UTF-8?q?Starter=20=E4=B8=A4=E4=B8=AA=E7=BB=84?= =?UTF-8?q?=E4=BB=B6z-index=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/starter/components/FAQ.js | 2 +- themes/starter/components/Pricing.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/themes/starter/components/FAQ.js b/themes/starter/components/FAQ.js index 29f9d5958ef..381498716ec 100644 --- a/themes/starter/components/FAQ.js +++ b/themes/starter/components/FAQ.js @@ -17,7 +17,7 @@ export const FAQ = () => { return ( <> {/* */} -
+
diff --git a/themes/starter/components/Pricing.js b/themes/starter/components/Pricing.js index 204bdce51a7..5728f703b3a 100644 --- a/themes/starter/components/Pricing.js +++ b/themes/starter/components/Pricing.js @@ -10,7 +10,7 @@ export const Pricing = () => { {/* */}
+ className='relative overflow-hidden bg-white pb-12 pt-20 dark:bg-dark lg:pb-[90px] lg:pt-[120px]'>
From e5a848c585b73b488c401e5c9a51249402a0115d Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Wed, 13 Nov 2024 11:16:55 +0800 Subject: [PATCH 12/25] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=96=87=E7=AB=A0?= =?UTF-8?q?=E5=89=8D=E7=BC=80=E9=97=AE=E9=A2=98=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=A9=BA=E5=AD=97=E7=AC=A6=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/notion/getPageProperties.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js index 27d140476b9..44f050c54b4 100644 --- a/lib/notion/getPageProperties.js +++ b/lib/notion/getPageProperties.js @@ -243,10 +243,14 @@ function generateCustomizeSlug(postProperties, NOTION_CONFIG) { return postProperties.slug } let fullPrefix = '' - const allSlugPatterns = - NOTION_CONFIG?.POST_URL_PREFIX || - siteConfig('POST_URL_PREFIX', '', NOTION_CONFIG).split('/') - + let allSlugPatterns = NOTION_CONFIG?.POST_URL_PREFIX + if (allSlugPatterns === undefined) { + allSlugPatterns = siteConfig('POST_URL_PREFIX', '', NOTION_CONFIG).split( + '/' + ) + } else { + allSlugPatterns = allSlugPatterns.split('/') + } const POST_URL_PREFIX_MAPPING_CATEGORY = siteConfig( 'POST_URL_PREFIX_MAPPING_CATEGORY', {}, From b927542391b3bbd4cda1f9f52f7e9c84e1c89f05 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Wed, 13 Nov 2024 11:35:06 +0800 Subject: [PATCH 13/25] =?UTF-8?q?Github=20PR=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/pull_request_template.md | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..c9ec6df732a --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,34 @@ +## 已知问题 + +1. (示例)版本号管理不规范 + - 版本号直接写在环境变量中,容易出错 + - 多处维护版本号,可能不一致 + +## 解决方案 + +1. (示例)将版本号管理从 `.env.local` 迁移到 `package.json` + - 统一从 `package.json` 读取版本号 + - 使用 IIFE 优雅处理版本号获取逻辑 + - 保持向后兼容,支持环境变量覆盖 + +## 改动收益 + +1. (示例)更规范的版本管理 + - 统一从 `package.json` 读取 + - 保持与 npm 生态一致 + - 减少人为错误 + +## 具体改动 + +1. (示例)`blog.config.js` + - 移除原有的静态版本号配置 + - 在文件末尾添加动态版本号获取逻辑 + - 保持向后兼容,优先使用环境变量 + - 添加错误处理和默认值 + +## 测试确认 + +- [x] 本地开发环境测试通过 +- [x] 生产环境构建测试通过 +- [x] 版本号正确显示 +- [x] 环境变量配置正常工作 From 2f91b5f4b23db2fb3c9ad7ecae555c0e775e6bad Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Wed, 13 Nov 2024 12:15:06 +0800 Subject: [PATCH 14/25] =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B74.7.8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6a87045eee4..6231202592b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "notion-next", - "version": "4.7.7", + "version": "4.7.8", "homepage": "https://github.com/tangly1024/NotionNext.git", "license": "MIT", "repository": { From 1c654a511862564b3632f5e52d60301d4b877845 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Wed, 13 Nov 2024 14:24:16 +0800 Subject: [PATCH 15/25] =?UTF-8?q?=E4=B8=BB=E9=A2=98=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E5=BE=AE=E8=B0=83=20Magzine=E5=92=8CNext?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/magzine/components/Header.js | 2 +- themes/magzine/components/MenuItemDrop.js | 4 ++-- themes/magzine/components/PostItemCardTop.js | 22 +++++++++---------- themes/magzine/components/PostItemCardWide.js | 22 +++++++++---------- themes/magzine/components/PostNavAround.js | 2 +- themes/magzine/components/Progress.js | 4 ++-- themes/next/components/MenuItemDrop.js | 6 ++--- themes/next/components/SideAreaLeft.js | 2 +- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/themes/magzine/components/Header.js b/themes/magzine/components/Header.js index aa0463e4ea4..45b6547a746 100644 --- a/themes/magzine/components/Header.js +++ b/themes/magzine/components/Header.js @@ -148,7 +148,7 @@ export default function Header(props) {
{/* 桌面端顶部菜单 */} -
+
{links && links?.map((link, index) => ( diff --git a/themes/magzine/components/MenuItemDrop.js b/themes/magzine/components/MenuItemDrop.js index 95a7cdb5f43..4fd096238e5 100644 --- a/themes/magzine/components/MenuItemDrop.js +++ b/themes/magzine/components/MenuItemDrop.js @@ -22,7 +22,7 @@ export const MenuItemDrop = ({ link }) => { {hasSubMenu && (
{ {/* 子菜单 */} {hasSubMenu && (
    + className={`${show ? 'visible opacity-100 top-14' : 'invisible opacity-0 top-20'} absolute border bg-white dark:bg-black dark:border-gray-800 transition-all duration-150 z-20 block rounded-lg drop-shadow-lg p-4 `}> {link?.subMenus?.map(sLink => { return (
  • { - const showPreview = siteConfig('MAGZINE_POST_LIST_PREVIEW') && post.blockMap + const showPreview = siteConfig('MAGZINE_POST_LIST_PREVIEW') && post?.blockMap const { locale } = useGlobal() return (
    {
    {siteConfig('MAGZINE_POST_LIST_COVER') && post?.pageCoverThumbnail && ( {
    @@ -45,7 +45,7 @@ const PostItemCardTop = ({ post, showSummary }) => {
    {siteConfig('MAGZINE_POST_LIST_CATEGORY') && ( - + )}
    {

    {siteConfig('POST_TITLE_ICON') && ( - + )} - {post.title} + {post?.title}

    @@ -76,7 +76,7 @@ const PostItemCardTop = ({ post, showSummary }) => { {(!showPreview || showSummary) && (
    - {post.summary} + {post?.summary}
    )} @@ -97,7 +97,7 @@ const PostItemCardTop = ({ post, showSummary }) => {
    )} -
    {post.date?.start_date}
    +
    {post?.date?.start_date}
) diff --git a/themes/magzine/components/PostItemCardWide.js b/themes/magzine/components/PostItemCardWide.js index 49ab3bca085..2aec9a8e2d6 100644 --- a/themes/magzine/components/PostItemCardWide.js +++ b/themes/magzine/components/PostItemCardWide.js @@ -12,32 +12,32 @@ import CategoryItem from './CategoryItem' * @returns */ const PostItemCardWide = ({ post, showSummary }) => { - const showPreview = siteConfig('MAGZINE_POST_LIST_PREVIEW') && post.blockMap + const showPreview = siteConfig('MAGZINE_POST_LIST_PREVIEW') && post?.blockMap const { locale } = useGlobal() return ( -
+
{/* 卡牌左侧 */}
{siteConfig('MAGZINE_POST_LIST_CATEGORY') && ( - + )}

{siteConfig('POST_TITLE_ICON') && ( - + )} - {post.title} + {post?.title}

{(!showPreview || showSummary) && (
- {post.summary} + {post?.summary}
)} @@ -47,7 +47,7 @@ const PostItemCardWide = ({ post, showSummary }) => {
{locale.COMMON.ARTICLE_DETAIL} @@ -66,7 +66,7 @@ const PostItemCardWide = ({ post, showSummary }) => { post?.tagItems?.map(tag => ( ))} */} -
{post.date?.start_date}
+
{post?.date?.start_date}
@@ -74,8 +74,8 @@ const PostItemCardWide = ({ post, showSummary }) => {
diff --git a/themes/magzine/components/PostNavAround.js b/themes/magzine/components/PostNavAround.js index 3eb1222cd1c..754e1257ca4 100644 --- a/themes/magzine/components/PostNavAround.js +++ b/themes/magzine/components/PostNavAround.js @@ -90,7 +90,7 @@ export default function PostNavAround({ prev, next }) { className={`${isShow ? 'mb-5 opacity-100' : '-mb-24 opacity-0'} hidden md:block fixed z-40 right-10 bottom-4 duration-200 transition-all`}> + className='text-sm block p-4 w-72 h-28 cursor-pointer drop-shadow-xl duration transition-all dark:bg-[#1e1e1e] border dark:border-gray-800 bg-white dark:text-gray-300 dark:hover:text-yellow-600 hover:font-bold hover:text-green-600'>
{locale.COMMON.NEXT_POST}

{next?.title}
diff --git a/themes/magzine/components/Progress.js b/themes/magzine/components/Progress.js index 38ad79c4be9..31ef6a24d60 100644 --- a/themes/magzine/components/Progress.js +++ b/themes/magzine/components/Progress.js @@ -29,9 +29,9 @@ const Progress = ({ targetRef, showPercent = true }) => { }, []) return ( -
+
{showPercent && (
{percent}%
diff --git a/themes/next/components/MenuItemDrop.js b/themes/next/components/MenuItemDrop.js index aec9212e65e..b4078e4369c 100644 --- a/themes/next/components/MenuItemDrop.js +++ b/themes/next/components/MenuItemDrop.js @@ -42,18 +42,18 @@ export const MenuItemDrop = ({ link }) => { {/* 子菜单 */} {hasSubMenu && (
    + className={`${show ? 'visible opacity-100 left-56' : 'invisible opacity-0 left-40'} ml-3 whitespace-nowrap absolute right-0 top-0 w-full border-gray-100 bg-white dark:bg-black dark:border-gray-800 transition-all duration-300 drop-shadow-lg `}> {link?.subMenus?.map(sLink => { return (
  • + className='my-auto h-9 pl-4 items-center justify-start flex not:last-child:border-b-0 border-b text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-900 tracking-widest transition-all duration-200 dark:border-gray-800 '> {sLink.icon && ( )} -
    {sLink.name}
    + {sLink.name} {sLink.slot}
  • diff --git a/themes/next/components/SideAreaLeft.js b/themes/next/components/SideAreaLeft.js index e2800a7cbad..cd52d935a1b 100644 --- a/themes/next/components/SideAreaLeft.js +++ b/themes/next/components/SideAreaLeft.js @@ -28,7 +28,7 @@ const SideAreaLeft = props => { id='left' className={ (JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE')) ? 'ml-4' : 'mr-4') + - ' hidden lg:block flex-col w-60 z-20 relative' + ' hidden lg:block flex-col w-60 relative z-30' }>
    {/* 菜单 */} From 3c2959027a12088be799cb36fbdbb5aa21a99de3 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Wed, 13 Nov 2024 14:51:28 +0800 Subject: [PATCH 16/25] =?UTF-8?q?=E4=BF=AE=E5=A4=8DNav=E4=B8=BB=E9=A2=98?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AB=AF=E7=9A=84=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/nav/components/MenuItemCollapse.js | 15 ++- themes/nav/components/TopNavBar.js | 123 +++++++++++++--------- 2 files changed, 82 insertions(+), 56 deletions(-) diff --git a/themes/nav/components/MenuItemCollapse.js b/themes/nav/components/MenuItemCollapse.js index 4f332337d59..065e92286fa 100755 --- a/themes/nav/components/MenuItemCollapse.js +++ b/themes/nav/components/MenuItemCollapse.js @@ -20,7 +20,9 @@ export const MenuItemCollapse = props => { if (!link || !link.show) { return null } - + // #号加标题 快速跳转到指定锚点 + const isAnchor = link?.href === '#' + const url = isAnchor ? `#${link.name}` : link.href const selected = router.pathname === link.href || router.asPath === link.href const toggleShow = () => { @@ -42,7 +44,7 @@ export const MenuItemCollapse = props => { onClick={toggleShow}> {!hasSubMenu && (
    @@ -72,21 +74,24 @@ export const MenuItemCollapse = props => { {hasSubMenu && ( {link?.subMenus?.map((sLink, index) => { + // #号加标题 快速跳转到指定锚点 + const sIsAnchor = sLink?.href === '#' + const sUrl = sIsAnchor ? `#${sLink.name}` : sLink.href + return (
    - {/* */} - + ) })} diff --git a/themes/nav/components/TopNavBar.js b/themes/nav/components/TopNavBar.js index cee758c6a2b..f9e9438b67a 100755 --- a/themes/nav/components/TopNavBar.js +++ b/themes/nav/components/TopNavBar.js @@ -1,10 +1,10 @@ -import { useCallback, useEffect, useRef, useState } from 'react' import Collapse from '@/components/Collapse' -import { MenuBarMobile } from './MenuBarMobile' -import throttle from 'lodash.throttle' -import SearchInput from './SearchInput' import DarkModeButton from '@/components/DarkModeButton' +import throttle from 'lodash.throttle' +import { useCallback, useEffect, useRef, useState } from 'react' import LogoBar from './LogoBar' +import { MenuBarMobile } from './MenuBarMobile' +import SearchInput from './SearchInput' /** * 顶部导航栏 + 菜单 @@ -29,20 +29,22 @@ export default function TopNavBar(props) { const throttleMs = 200 - const scrollTrigger = useCallback(throttle(() => { - const scrollS = window.scrollY - const nav = document.querySelector('#nav-bg') - // const header = document.querySelector('#top-nav') - const header = document.querySelector('#container-inner') - const showNav = scrollS <= windowTop || scrollS < 5 || (scrollS <= header.clientHeight)// 非首页无大图时影藏顶部 滚动条置顶时隐藏 - if (!showNav) { - nav && nav.classList.replace('-top-20', 'top-0') - windowTop = scrollS - } else { - nav && nav.classList.replace('top-0', '-top-20') - windowTop = scrollS - } - }, throttleMs) + const scrollTrigger = useCallback( + throttle(() => { + const scrollS = window.scrollY + const nav = document.querySelector('#nav-bg') + // const header = document.querySelector('#top-nav') + const header = document.querySelector('#container-inner') + const showNav = + scrollS <= windowTop || scrollS < 5 || scrollS <= header.clientHeight // 非首页无大图时影藏顶部 滚动条置顶时隐藏 + if (!showNav) { + nav && nav.classList.replace('-top-20', 'top-0') + windowTop = scrollS + } else { + nav && nav.classList.replace('top-0', '-top-20') + windowTop = scrollS + } + }, throttleMs) ) const toggleMenuOpen = () => { @@ -50,42 +52,61 @@ export default function TopNavBar(props) { } return ( -
    - {/* 图标Logo */} -
    - -
    +
    + {/* 图标Logo */} +
    + +
    - {/* 移动端折叠菜单 */} - -
    - collapseRef.current?.updateCollapseHeight(param)} /> -
    -
    - - {/* 导航栏菜单 */} -
    + {/* 导航栏菜单 */} +
    +
    + {/* 搜索框、折叠按钮、仅移动端显示 */} +
    +
    + +
    + +
    + {isOpen ? ( + + ) : ( + + )} +
    +
    -
    - {/* 搜索框、折叠按钮、仅移动端显示 */} -
    -
    - -
    - -
    - {isOpen ? : } -
    -
    + {/* 桌面端顶部菜单 */} +
    + {/* {links && links?.map((link, index) => )} */} + + +
    +
    +
    - {/* 桌面端顶部菜单 */} -
    - {/* {links && links?.map((link, index) => )} */} - - -
    -
    -
    + {/* 移动端折叠菜单 */} + +
    + + collapseRef.current?.updateCollapseHeight(param) + } + />
    +
    +
    ) } From 39e3fb4d13830a9e01e318c57be0048e2895abf5 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Wed, 13 Nov 2024 15:12:19 +0800 Subject: [PATCH 17/25] =?UTF-8?q?Starter=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/starter/components/SearchInput.js | 107 +++++++++++++++++++++++ themes/starter/index.js | 33 ++++++- 2 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 themes/starter/components/SearchInput.js diff --git a/themes/starter/components/SearchInput.js b/themes/starter/components/SearchInput.js new file mode 100644 index 00000000000..1baf29e8730 --- /dev/null +++ b/themes/starter/components/SearchInput.js @@ -0,0 +1,107 @@ +import { useGlobal } from '@/lib/global' +import { useRouter } from 'next/router' +import { useImperativeHandle, useRef, useState } from 'react' + +let lock = false + +/** + * 搜索输入框 + * @param {*} param0 + * @returns + */ +const SearchInput = ({ currentTag, keyword, cRef }) => { + const { locale } = useGlobal() + const router = useRouter() + const searchInputRef = useRef(null) + useImperativeHandle(cRef, () => { + return { + focus: () => { + searchInputRef?.current?.focus() + } + } + }) + const handleSearch = () => { + const key = searchInputRef.current.value + if (key && key !== '') { + router.push({ pathname: '/search/' + key }).then(r => {}) + } else { + router.push({ pathname: '/' }).then(r => {}) + } + } + const handleKeyUp = e => { + if (e.keyCode === 13) { + // 回车 + handleSearch(searchInputRef.current.value) + } else if (e.keyCode === 27) { + // ESC + cleanSearch() + } + } + const cleanSearch = () => { + searchInputRef.current.value = '' + setShowClean(false) + } + function lockSearchInput() { + lock = true + } + + function unLockSearchInput() { + lock = false + } + const [showClean, setShowClean] = useState(false) + const updateSearchKey = val => { + if (lock) { + return + } + searchInputRef.current.value = val + if (val) { + setShowClean(true) + } else { + setShowClean(false) + } + } + + return ( +
    + updateSearchKey(e.target.value)} + defaultValue={keyword || ''} + /> + +
    + +
    + + {showClean && ( +
    + +
    + )} +
    + ) +} + +export default SearchInput diff --git a/themes/starter/index.js b/themes/starter/index.js index c4f9af8c032..3ae161f6ea3 100644 --- a/themes/starter/index.js +++ b/themes/starter/index.js @@ -25,6 +25,7 @@ import CONFIG from './config' import { Style } from './style' // import { MadeWithButton } from './components/MadeWithButton' import Comment from '@/components/Comment' +import replaceSearchResult from '@/components/Mark' import ShareBar from '@/components/ShareBar' import { useGlobal } from '@/lib/global' import { loadWowJS } from '@/lib/plugins/wow' @@ -33,6 +34,7 @@ import Link from 'next/link' import { ArticleLock } from './components/ArticleLock' import { Banner } from './components/Banner' import { CTA } from './components/CTA' +import SearchInput from './components/SearchInput' import { SignInForm } from './components/SignInForm' import { SignUpForm } from './components/SignUpForm' import { SVG404 } from './components/svg/SVG404' @@ -61,7 +63,9 @@ const LayoutBase = props => { {/* 页头 */}
    - {children} +
    + {children} +
    {/* 页脚 */}