多语言支持初版,不支持static export

This commit is contained in:
tangly1024.com
2024-04-08 16:01:41 +08:00
parent 214b40fb5a
commit 1c9526f4b5
23 changed files with 585 additions and 230 deletions

View File

@@ -1,7 +1,9 @@
// 注: process.env.XX是Vercel的环境变量配置方式见https://docs.tangly1024.com/article/how-to-config-notion-next#c4768010ae7d44609b744e79e2f9959a
const BLOG = {
// Important page_idDuplicate Template from https://www.notion.so/tanghh/02ab3b8678004aa69e9e415905ef32a5
NOTION_PAGE_ID: process.env.NOTION_PAGE_ID || '02ab3b8678004aa69e9e415905ef32a5',
NOTION_PAGE_ID:
process.env.NOTION_PAGE_ID ||
'02ab3b8678004aa69e9e415905ef32a5,en:7c1d570661754c8fbc568e00a01fd70e',
PSEUDO_STATIC: process.env.NEXT_PUBLIC_PSEUDO_STATIC || false, // 伪静态路径开启后所有文章URL都以 .html 结尾。
NEXT_REVALIDATE_SECOND: process.env.NEXT_PUBLIC_REVALIDATE_SECOND || 5, // 更新内容缓存间隔 单位(秒)即每个页面有5秒的纯静态期、此期间无论多少次访问都不会抓取notion数据调大该值有助于节省Vercel资源、同时提升访问速率但也会使文章更新有延迟。
THEME: process.env.NEXT_PUBLIC_THEME || 'simple', // 当前主题在themes文件夹下可找到所有支持的主题主题名称就是文件夹名例如 example,fukasawa,gitbook,heo,hexo,landing,matery,medium,next,nobelium,plog,simple
@@ -11,7 +13,8 @@ const BLOG = {
APPEARANCE: process.env.NEXT_PUBLIC_APPEARANCE || 'light', // ['light', 'dark', 'auto'], // light 日间模式 dark夜间模式 auto根据时间和主题自动夜间模式
APPEARANCE_DARK_TIME: process.env.NEXT_PUBLIC_APPEARANCE_DARK_TIME || [18, 6], // 夜间模式起至时间false时关闭根据时间自动切换夜间模式
IS_TAG_COLOR_DISTINGUISHED: process.env.NEXT_PUBLIC_IS_TAG_COLOR_DISTINGUISHED === 'true' || true, // 对于名称相同的tag是否区分tag的颜色
IS_TAG_COLOR_DISTINGUISHED:
process.env.NEXT_PUBLIC_IS_TAG_COLOR_DISTINGUISHED === 'true' || true, // 对于名称相同的tag是否区分tag的颜色
// 3.14.1版本后,欢迎语在此配置,英文逗号隔开 , 即可支持多个欢迎语打字效果。
GREETING_WORDS:
@@ -43,7 +46,9 @@ const BLOG = {
IMAGE_COMPRESS_WIDTH: process.env.NEXT_PUBLIC_IMAGE_COMPRESS_WIDTH || 800, // 图片压缩宽度默认值,作用于博客封面和文章内容 越小加载图片越快
IMAGE_ZOOM_IN_WIDTH: process.env.NEXT_PUBLIC_IMAGE_ZOOM_IN_WIDTH || 1200, // 文章图片点击放大后的画质宽度,不代表在网页中的实际展示宽度
RANDOM_IMAGE_URL: process.env.NEXT_PUBLIC_RANDOM_IMAGE_URL || '', // 随机图片API,如果未配置下面的关键字,主页封面,头像,文章封面图都会被替换为随机图片
RANDOM_IMAGE_REPLACE_TEXT: process.env.NEXT_PUBLIC_RANDOM_IMAGE_NOT_REPLACE_TEXT || 'images.unsplash.com', // 触发替换图片的 url 关键字(多个支持用英文逗号分开)只有图片地址中包含此关键字才会替换为上方随机图片url
RANDOM_IMAGE_REPLACE_TEXT:
process.env.NEXT_PUBLIC_RANDOM_IMAGE_NOT_REPLACE_TEXT ||
'images.unsplash.com', // 触发替换图片的 url 关键字(多个支持用英文逗号分开)只有图片地址中包含此关键字才会替换为上方随机图片url
// eg: images.unsplash.com(notion图床的所有图片都会替换),如果你在 notion 里已经添加了一个随机图片 url恰巧那个服务跑路或者挂掉想一键切换所有配图可以将该 url 配置在这里
// 默认下会将你上传到 notion的主页封面图和头像也给替换建议将主页封面图和头像放在其他图床在 notion 里配置 link 即可。
@@ -122,23 +127,29 @@ const BLOG = {
CAN_COPY: process.env.NEXT_PUBLIC_CAN_COPY || true, // 是否允许复制页面内容 默认允许如果设置为false、则全栈禁止复制内容。
// 自定义右键菜单
CUSTOM_RIGHT_CLICK_CONTEXT_MENU: process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU || true, // 自定义右键菜单,覆盖系统菜单
CUSTOM_RIGHT_CLICK_CONTEXT_MENU:
process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU || true, // 自定义右键菜单,覆盖系统菜单
CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH:
process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH || true, // 是否显示切换主题
CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE: process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE || true, // 是否显示深色模式
process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH ||
true, // 是否显示切换主题
CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE:
process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE || true, // 是否显示深色模式
CUSTOM_RIGHT_CLICK_CONTEXT_MENU_SHARE_LINK:
process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_SHARE_LINK || true, // 是否显示分享链接
CUSTOM_RIGHT_CLICK_CONTEXT_MENU_RANDOM_POST:
process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_RANDOM_POST || true, // 是否显示随机博客
CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY: process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY || true, // 是否显示分类
CUSTOM_RIGHT_CLICK_CONTEXT_MENU_TAG: process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_TAG || true, // 是否显示标签
CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY:
process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY || true, // 是否显示分类
CUSTOM_RIGHT_CLICK_CONTEXT_MENU_TAG:
process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_TAG || true, // 是否显示标签
// 自定义外部脚本,外部样式
CUSTOM_EXTERNAL_JS: [''], // e.g. ['http://xx.com/script.js','http://xx.com/script.js']
CUSTOM_EXTERNAL_CSS: [''], // e.g. ['http://xx.com/style.css','http://xx.com/style.css']
// 侧栏布局 是否反转(左变右,右变左) 已支持主题: hexo next medium fukasawa example
LAYOUT_SIDEBAR_REVERSE: process.env.NEXT_PUBLIC_LAYOUT_SIDEBAR_REVERSE || false,
LAYOUT_SIDEBAR_REVERSE:
process.env.NEXT_PUBLIC_LAYOUT_SIDEBAR_REVERSE || false,
// 一个小插件展示你的facebook fan page~ @see https://tw.andys.pro/article/add-facebook-fanpage-notionnext
FACEBOOK_PAGE_TITLE: process.env.NEXT_PUBLIC_FACEBOOK_PAGE_TITLE || null, // 邊欄 Facebook Page widget 的標題欄,填''則無標題欄 e.g FACEBOOK 粉絲團'
@@ -151,7 +162,8 @@ const BLOG = {
// START********代码相关********
// PrismJs 代码相关
PRISM_JS_PATH: 'https://npm.elemecdn.com/prismjs@1.29.0/components/',
PRISM_JS_AUTO_LOADER: 'https://npm.elemecdn.com/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js',
PRISM_JS_AUTO_LOADER:
'https://npm.elemecdn.com/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js',
// 代码主题 @see https://github.com/PrismJS/prism-themes
PRISM_THEME_PREFIX_PATH:
@@ -168,16 +180,19 @@ const BLOG = {
CODE_MAC_BAR: process.env.NEXT_PUBLIC_CODE_MAC_BAR || true, // 代码左上角显示mac的红黄绿图标
CODE_LINE_NUMBERS: process.env.NEXT_PUBLIC_CODE_LINE_NUMBERS || false, // 是否显示行号
CODE_COLLAPSE: process.env.NEXT_PUBLIC_CODE_COLLAPSE || true, // 是否支持折叠代码框
CODE_COLLAPSE_EXPAND_DEFAULT: process.env.NEXT_PUBLIC_CODE_COLLAPSE_EXPAND_DEFAULT || true, // 折叠代码默认是展开状态
CODE_COLLAPSE_EXPAND_DEFAULT:
process.env.NEXT_PUBLIC_CODE_COLLAPSE_EXPAND_DEFAULT || true, // 折叠代码默认是展开状态
// END********代码相关********
// Mermaid 图表CDN
MERMAID_CDN:
process.env.NEXT_PUBLIC_MERMAID_CDN || 'https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.2.4/mermaid.min.js', // CDN
process.env.NEXT_PUBLIC_MERMAID_CDN ||
'https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.2.4/mermaid.min.js', // CDN
// QRCodeCDN
QR_CODE_CDN:
process.env.NEXT_PUBLIC_QR_CODE_CDN || 'https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js',
process.env.NEXT_PUBLIC_QR_CODE_CDN ||
'https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js',
BACKGROUND_LIGHT: '#eeeeee', // use hex value, don't forget '#' e.g #fffefc
BACKGROUND_DARK: '#000000', // use hex value, don't forget '#'
@@ -202,24 +217,32 @@ const BLOG = {
POSTS_PER_PAGE: process.env.NEXT_PUBLIC_POST_PER_PAGE || 12, // post counts per page
POSTS_SORT_BY: process.env.NEXT_PUBLIC_POST_SORT_BY || 'notion', // 排序方式 'date'按时间,'notion'由notion控制
POST_WAITING_TIME_FOR_404: process.env.NEXT_PUBLIC_POST_WAITING_TIME_FOR_404 || '8', // 文章加载超时时间单位秒超时后跳转到404页面
POST_WAITING_TIME_FOR_404:
process.env.NEXT_PUBLIC_POST_WAITING_TIME_FOR_404 || '8', // 文章加载超时时间单位秒超时后跳转到404页面
ALGOLIA_APP_ID: process.env.NEXT_PUBLIC_ALGOLIA_APP_ID || null, // 在这里查看 https://dashboard.algolia.com/account/api-keys/
ALGOLIA_ADMIN_APP_KEY: process.env.ALGOLIA_ADMIN_APP_KEY || null, // 管理后台的KEY不要暴露在代码中在这里查看 https://dashboard.algolia.com/account/api-keys/
ALGOLIA_SEARCH_ONLY_APP_KEY: process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_ONLY_APP_KEY || null, // 客户端搜索用的KEY
ALGOLIA_SEARCH_ONLY_APP_KEY:
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_ONLY_APP_KEY || null, // 客户端搜索用的KEY
ALGOLIA_INDEX: process.env.NEXT_PUBLIC_ALGOLIA_INDEX || null, // 在Algolia中创建一个index用作数据库
// ALGOLIA_RECREATE_DATA: process.env.ALGOLIA_RECREATE_DATA || process.env.npm_lifecycle_event === 'build', // 为true时重新构建索引数据; 默认在build时会构建
PREVIEW_CATEGORY_COUNT: 16, // 首页最多展示的分类数量0为不限制
PREVIEW_TAG_COUNT: 16, // 首页最多展示的标签数量0为不限制
POST_DISABLE_GALLERY_CLICK: process.env.NEXT_PUBLIC_POST_DISABLE_GALLERY_CLICK || false, // 画册视图禁止点击,方便在友链页面的画册插入链接
POST_DISABLE_GALLERY_CLICK:
process.env.NEXT_PUBLIC_POST_DISABLE_GALLERY_CLICK || false, // 画册视图禁止点击,方便在友链页面的画册插入链接
// ********动态特效相关********
// 鼠标点击烟花特效
FIREWORKS: process.env.NEXT_PUBLIC_FIREWORKS || false, // 开关
// 烟花色彩,感谢 https://github.com/Vixcity 提交的色彩
FIREWORKS_COLOR: ['255, 20, 97', '24, 255, 146', '90, 135, 255', '251, 243, 140'],
FIREWORKS_COLOR: [
'255, 20, 97',
'24, 255, 146',
'90, 135, 255',
'251, 243, 140'
],
// 樱花飘落特效
SAKURA: process.env.NEXT_PUBLIC_SAKURA || false, // 开关
@@ -238,14 +261,16 @@ const BLOG = {
process.env.NEXT_PUBLIC_TIANLI_GPT_CSS ||
'https://cdn1.tianli0.top/gh/zhheo/Post-Abstract-AI@0.15.2/tianli_gpt.css',
TianliGPT_JS:
process.env.NEXT_PUBLIC_TIANLI_GPT_JS || 'https://cdn1.tianli0.top/gh/zhheo/Post-Abstract-AI@0.15.2/tianli_gpt.js',
process.env.NEXT_PUBLIC_TIANLI_GPT_JS ||
'https://cdn1.tianli0.top/gh/zhheo/Post-Abstract-AI@0.15.2/tianli_gpt.js',
TianliGPT_KEY: process.env.NEXT_PUBLIC_TIANLI_GPT_KEY || '',
// Chatbase 是否显示chatbase机器人 https://www.chatbase.co/
CHATBASE_ID: process.env.NEXT_PUBLIC_CHATBASE_ID || null,
// WebwhizAI 机器人 @see https://github.com/webwhiz-ai/webwhiz
WEB_WHIZ_ENABLED: process.env.NEXT_PUBLIC_WEB_WHIZ_ENABLED || false, // 是否显示
WEB_WHIZ_BASE_URL: process.env.NEXT_PUBLIC_WEB_WHIZ_BASE_URL || 'https://api.webwhiz.ai', // 可以自建服务器
WEB_WHIZ_BASE_URL:
process.env.NEXT_PUBLIC_WEB_WHIZ_BASE_URL || 'https://api.webwhiz.ai', // 可以自建服务器
WEB_WHIZ_CHAT_BOT_ID: process.env.NEXT_PUBLIC_WEB_WHIZ_CHAT_BOT_ID || null, // 在后台获取ID
DIFY_CHATBOT_ENABLED: process.env.NEXT_PUBLIC_DIFY_CHATBOT_ENABLED || false,
DIFY_CHATBOT_BASE_URL: process.env.NEXT_PUBLIC_DIFY_CHATBOT_BASE_URL || '',
@@ -255,12 +280,14 @@ const BLOG = {
WIDGET_PET_LINK:
process.env.NEXT_PUBLIC_WIDGET_PET_LINK ||
'https://cdn.jsdelivr.net/npm/live2d-widget-model-wanko@1.0.5/assets/wanko.model.json', // 挂件模型地址 @see https://github.com/xiazeyu/live2d-widget-models
WIDGET_PET_SWITCH_THEME: process.env.NEXT_PUBLIC_WIDGET_PET_SWITCH_THEME || true, // 点击宠物挂件切换博客主题
WIDGET_PET_SWITCH_THEME:
process.env.NEXT_PUBLIC_WIDGET_PET_SWITCH_THEME || true, // 点击宠物挂件切换博客主题
// 音乐播放插件
MUSIC_PLAYER: process.env.NEXT_PUBLIC_MUSIC_PLAYER || false, // 是否使用音乐播放插件
MUSIC_PLAYER_VISIBLE: process.env.NEXT_PUBLIC_MUSIC_PLAYER_VISIBLE || true, // 是否在左下角显示播放和切换,如果使用播放器,打开自动播放再隐藏,就会以类似背景音乐的方式播放,无法取消和暂停
MUSIC_PLAYER_AUTO_PLAY: process.env.NEXT_PUBLIC_MUSIC_PLAYER_AUTO_PLAY || true, // 是否自动播放,不过自动播放时常不生效(移动设备不支持自动播放)
MUSIC_PLAYER_AUTO_PLAY:
process.env.NEXT_PUBLIC_MUSIC_PLAYER_AUTO_PLAY || true, // 是否自动播放,不过自动播放时常不生效(移动设备不支持自动播放)
MUSIC_PLAYER_LRC_TYPE: process.env.NEXT_PUBLIC_MUSIC_PLAYER_LRC_TYPE || '0', // 歌词显示类型,可选值: 3 | 1 | 00禁用 lrc 歌词1lrc 格式的字符串3lrc 文件 url前提是有配置歌词路径对 meting 无效)
MUSIC_PLAYER_CDN_URL:
process.env.NEXT_PUBLIC_MUSIC_PLAYER_CDN_URL ||
@@ -272,78 +299,105 @@ const BLOG = {
name: '风を共に舞う気持ち',
artist: 'Falcom Sound Team jdk',
url: 'https://music.163.com/song/media/outer/url?id=731419.mp3',
cover: 'https://p2.music.126.net/kn6ugISTonvqJh3LHLaPtQ==/599233837187278.jpg'
cover:
'https://p2.music.126.net/kn6ugISTonvqJh3LHLaPtQ==/599233837187278.jpg'
},
{
name: '王都グランセル',
artist: 'Falcom Sound Team jdk',
url: 'https://music.163.com/song/media/outer/url?id=731355.mp3',
cover: 'https://p1.music.126.net/kn6ugISTonvqJh3LHLaPtQ==/599233837187278.jpg'
cover:
'https://p1.music.126.net/kn6ugISTonvqJh3LHLaPtQ==/599233837187278.jpg'
}
],
MUSIC_PLAYER_METING: process.env.NEXT_PUBLIC_MUSIC_PLAYER_METING || false, // 是否要开启 MetingJS从平台获取歌单。会覆盖自定义的 MUSIC_PLAYER_AUDIO_LIST更多配置信息https://github.com/metowolf/MetingJS
MUSIC_PLAYER_METING_SERVER: process.env.NEXT_PUBLIC_MUSIC_PLAYER_METING_SERVER || 'netease', // 音乐平台,[netease, tencent, kugou, xiami, baidu]
MUSIC_PLAYER_METING_ID: process.env.NEXT_PUBLIC_MUSIC_PLAYER_METING_ID || '60198', // 对应歌单的 id
MUSIC_PLAYER_METING_LRC_TYPE: process.env.NEXT_PUBLIC_MUSIC_PLAYER_METING_LRC_TYPE || '1', // 可选值: 3 | 1 | 00禁用 lrc 歌词1lrc 格式的字符串3lrc 文件 url
MUSIC_PLAYER_METING_SERVER:
process.env.NEXT_PUBLIC_MUSIC_PLAYER_METING_SERVER || 'netease', // 音乐平台,[netease, tencent, kugou, xiami, baidu]
MUSIC_PLAYER_METING_ID:
process.env.NEXT_PUBLIC_MUSIC_PLAYER_METING_ID || '60198', // 对应歌单的 id
MUSIC_PLAYER_METING_LRC_TYPE:
process.env.NEXT_PUBLIC_MUSIC_PLAYER_METING_LRC_TYPE || '1', // 可选值: 3 | 1 | 00禁用 lrc 歌词1lrc 格式的字符串3lrc 文件 url
// ********挂件组件相关********
// ----> 评论互动 可同时开启多个支持 WALINE VALINE GISCUS CUSDIS UTTERRANCES GITALK
COMMENT_HIDE_SINGLE_TAB: process.env.NEXT_PUBLIC_COMMENT_HIDE_SINGLE_TAB || false, // Whether hide the tab when there's no tabs. 只有一个评论组件时是否隐藏切换组件的标签页
COMMENT_HIDE_SINGLE_TAB:
process.env.NEXT_PUBLIC_COMMENT_HIDE_SINGLE_TAB || false, // Whether hide the tab when there's no tabs. 只有一个评论组件时是否隐藏切换组件的标签页
// artalk 评论插件
COMMENT_ARTALK_SERVER: process.env.NEXT_PUBLIC_COMMENT_ARTALK_SERVER || '', // ArtalkServert后端地址 https://artalk.js.org/guide/deploy.html
COMMENT_ARTALK_JS:
process.env.NEXT_PUBLIC_COMMENT_ARTALK_JS || 'https://cdnjs.cloudflare.com/ajax/libs/artalk/2.5.5/Artalk.js', // ArtalkServert js cdn
process.env.NEXT_PUBLIC_COMMENT_ARTALK_JS ||
'https://cdnjs.cloudflare.com/ajax/libs/artalk/2.5.5/Artalk.js', // ArtalkServert js cdn
COMMENT_ARTALK_CSS:
process.env.NEXT_PUBLIC_COMMENT_ARTALK_CSS || 'https://cdnjs.cloudflare.com/ajax/libs/artalk/2.5.5/Artalk.css', // ArtalkServert css cdn
process.env.NEXT_PUBLIC_COMMENT_ARTALK_CSS ||
'https://cdnjs.cloudflare.com/ajax/libs/artalk/2.5.5/Artalk.css', // ArtalkServert css cdn
// twikoo
COMMENT_TWIKOO_ENV_ID: process.env.NEXT_PUBLIC_COMMENT_ENV_ID || '', // TWIKOO后端地址 腾讯云环境填envIdVercel环境填域名教程https://tangly1024.com/article/notionnext-twikoo
COMMENT_TWIKOO_COUNT_ENABLE: process.env.NEXT_PUBLIC_COMMENT_TWIKOO_COUNT_ENABLE || false, // 博客列表是否显示评论数
COMMENT_TWIKOO_COUNT_ENABLE:
process.env.NEXT_PUBLIC_COMMENT_TWIKOO_COUNT_ENABLE || false, // 博客列表是否显示评论数
COMMENT_TWIKOO_CDN_URL:
process.env.NEXT_PUBLIC_COMMENT_TWIKOO_CDN_URL || 'https://cdn.staticfile.org/twikoo/1.6.17/twikoo.min.js', // twikoo客户端cdn
process.env.NEXT_PUBLIC_COMMENT_TWIKOO_CDN_URL ||
'https://cdn.staticfile.org/twikoo/1.6.17/twikoo.min.js', // twikoo客户端cdn
// utterance
COMMENT_UTTERRANCES_REPO: process.env.NEXT_PUBLIC_COMMENT_UTTERRANCES_REPO || '', // 你的代码仓库名, 例如我是 'tangly1024/NotionNext' 更多文档参考 https://utteranc.es/
COMMENT_UTTERRANCES_REPO:
process.env.NEXT_PUBLIC_COMMENT_UTTERRANCES_REPO || '', // 你的代码仓库名, 例如我是 'tangly1024/NotionNext' 更多文档参考 https://utteranc.es/
// giscus @see https://giscus.app/
COMMENT_GISCUS_REPO: process.env.NEXT_PUBLIC_COMMENT_GISCUS_REPO || '', // 你的Github仓库名 e.g 'tangly1024/NotionNext'
COMMENT_GISCUS_REPO_ID: process.env.NEXT_PUBLIC_COMMENT_GISCUS_REPO_ID || '', // 你的Github Repo ID e.g ( 設定完 giscus 即可看到 )
COMMENT_GISCUS_CATEGORY_ID: process.env.NEXT_PUBLIC_COMMENT_GISCUS_CATEGORY_ID || '', // 你的Github Discussions 內的 Category ID ( 設定完 giscus 即可看到 )
COMMENT_GISCUS_MAPPING: process.env.NEXT_PUBLIC_COMMENT_GISCUS_MAPPING || 'pathname', // 你的Github Discussions 使用哪種方式來標定文章, 預設 'pathname'
COMMENT_GISCUS_REACTIONS_ENABLED: process.env.NEXT_PUBLIC_COMMENT_GISCUS_REACTIONS_ENABLED || '1', // 你的 Giscus 是否開啟文章表情符號 '1' 開啟 "0" 關閉 預設開啟
COMMENT_GISCUS_EMIT_METADATA: process.env.NEXT_PUBLIC_COMMENT_GISCUS_EMIT_METADATA || '0', // 你的 Giscus 是否提取 Metadata '1' 開啟 '0' 關閉 預設關閉
COMMENT_GISCUS_INPUT_POSITION: process.env.NEXT_PUBLIC_COMMENT_GISCUS_INPUT_POSITION || 'bottom', // 你的 Giscus 發表留言位置 'bottom' 尾部 'top' 頂部, 預設 'bottom'
COMMENT_GISCUS_CATEGORY_ID:
process.env.NEXT_PUBLIC_COMMENT_GISCUS_CATEGORY_ID || '', // 你的Github Discussions 內的 Category ID ( 設定完 giscus 即可看到 )
COMMENT_GISCUS_MAPPING:
process.env.NEXT_PUBLIC_COMMENT_GISCUS_MAPPING || 'pathname', // 你的Github Discussions 使用哪種方式來標定文章, 預設 'pathname'
COMMENT_GISCUS_REACTIONS_ENABLED:
process.env.NEXT_PUBLIC_COMMENT_GISCUS_REACTIONS_ENABLED || '1', // 你的 Giscus 是否開啟文章表情符號 '1' 開啟 "0" 關閉 預設開啟
COMMENT_GISCUS_EMIT_METADATA:
process.env.NEXT_PUBLIC_COMMENT_GISCUS_EMIT_METADATA || '0', // 你的 Giscus 是否提取 Metadata '1' 開啟 '0' 關閉 預設關閉
COMMENT_GISCUS_INPUT_POSITION:
process.env.NEXT_PUBLIC_COMMENT_GISCUS_INPUT_POSITION || 'bottom', // 你的 Giscus 發表留言位置 'bottom' 尾部 'top' 頂部, 預設 'bottom'
COMMENT_GISCUS_LANG: process.env.NEXT_PUBLIC_COMMENT_GISCUS_LANG || 'zh-CN', // 你的 Giscus 語言 e.g 'en', 'zh-TW', 'zh-CN', 預設 'en'
COMMENT_GISCUS_LOADING: process.env.NEXT_PUBLIC_COMMENT_GISCUS_LOADING || 'lazy', // 你的 Giscus 載入是否漸進式載入, 預設 'lazy'
COMMENT_GISCUS_CROSSORIGIN: process.env.NEXT_PUBLIC_COMMENT_GISCUS_CROSSORIGIN || 'anonymous', // 你的 Giscus 可以跨網域, 預設 'anonymous'
COMMENT_GISCUS_LOADING:
process.env.NEXT_PUBLIC_COMMENT_GISCUS_LOADING || 'lazy', // 你的 Giscus 載入是否漸進式載入, 預設 'lazy'
COMMENT_GISCUS_CROSSORIGIN:
process.env.NEXT_PUBLIC_COMMENT_GISCUS_CROSSORIGIN || 'anonymous', // 你的 Giscus 可以跨網域, 預設 'anonymous'
COMMENT_CUSDIS_APP_ID: process.env.NEXT_PUBLIC_COMMENT_CUSDIS_APP_ID || '', // data-app-id 36位 see https://cusdis.com/
COMMENT_CUSDIS_HOST: process.env.NEXT_PUBLIC_COMMENT_CUSDIS_HOST || 'https://cusdis.com', // data-host, change this if you're using self-hosted version
COMMENT_CUSDIS_SCRIPT_SRC: process.env.NEXT_PUBLIC_COMMENT_CUSDIS_SCRIPT_SRC || '/js/cusdis.es.js', // change this if you're using self-hosted version
COMMENT_CUSDIS_HOST:
process.env.NEXT_PUBLIC_COMMENT_CUSDIS_HOST || 'https://cusdis.com', // data-host, change this if you're using self-hosted version
COMMENT_CUSDIS_SCRIPT_SRC:
process.env.NEXT_PUBLIC_COMMENT_CUSDIS_SCRIPT_SRC || '/js/cusdis.es.js', // change this if you're using self-hosted version
// gitalk评论插件 更多参考 https://gitalk.github.io/
COMMENT_GITALK_REPO: process.env.NEXT_PUBLIC_COMMENT_GITALK_REPO || '', // 你的Github仓库名例如 'NotionNext'
COMMENT_GITALK_OWNER: process.env.NEXT_PUBLIC_COMMENT_GITALK_OWNER || '', // 你的用户名 e.g tangly1024
COMMENT_GITALK_ADMIN: process.env.NEXT_PUBLIC_COMMENT_GITALK_ADMIN || '', // 管理员用户名、一般是自己 e.g 'tangly1024'
COMMENT_GITALK_CLIENT_ID: process.env.NEXT_PUBLIC_COMMENT_GITALK_CLIENT_ID || '', // e.g 20位ID 在gitalk后台获取
COMMENT_GITALK_CLIENT_SECRET: process.env.NEXT_PUBLIC_COMMENT_GITALK_CLIENT_SECRET || '', // e.g 40位ID 在gitalk后台获取
COMMENT_GITALK_CLIENT_ID:
process.env.NEXT_PUBLIC_COMMENT_GITALK_CLIENT_ID || '', // e.g 20位ID 在gitalk后台获取
COMMENT_GITALK_CLIENT_SECRET:
process.env.NEXT_PUBLIC_COMMENT_GITALK_CLIENT_SECRET || '', // e.g 40位ID 在gitalk后台获取
COMMENT_GITALK_DISTRACTION_FREE_MODE: false, // 类似facebook的无干扰模式
COMMENT_GITALK_JS_CDN_URL:
process.env.NEXT_PUBLIC_COMMENT_GITALK_JS_CDN_URL || 'https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js', // gitalk客户端 js cdn
process.env.NEXT_PUBLIC_COMMENT_GITALK_JS_CDN_URL ||
'https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js', // gitalk客户端 js cdn
COMMENT_GITALK_CSS_CDN_URL:
process.env.NEXT_PUBLIC_COMMENT_GITALK_CSS_CDN_URL || 'https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css', // gitalk客户端 css cdn
process.env.NEXT_PUBLIC_COMMENT_GITALK_CSS_CDN_URL ||
'https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css', // gitalk客户端 css cdn
COMMENT_GITTER_ROOM: process.env.NEXT_PUBLIC_COMMENT_GITTER_ROOM || '', // gitter聊天室 see https://gitter.im/ 不需要则留空
COMMENT_DAO_VOICE_ID: process.env.NEXT_PUBLIC_COMMENT_DAO_VOICE_ID || '', // DaoVoice http://dashboard.daovoice.io/get-started
COMMENT_TIDIO_ID: process.env.NEXT_PUBLIC_COMMENT_TIDIO_ID || '', // [tidio_id] -> //code.tidio.co/[tidio_id].js
COMMENT_VALINE_CDN: process.env.NEXT_PUBLIC_VALINE_CDN || 'https://unpkg.com/valine@1.5.1/dist/Valine.min.js',
COMMENT_VALINE_CDN:
process.env.NEXT_PUBLIC_VALINE_CDN ||
'https://unpkg.com/valine@1.5.1/dist/Valine.min.js',
COMMENT_VALINE_APP_ID: process.env.NEXT_PUBLIC_VALINE_ID || '', // Valine @see https://valine.js.org/quickstart.html 或 https://github.com/stonehank/react-valine#%E8%8E%B7%E5%8F%96app-id-%E5%92%8C-app-key
COMMENT_VALINE_APP_KEY: process.env.NEXT_PUBLIC_VALINE_KEY || '',
COMMENT_VALINE_SERVER_URLS: process.env.NEXT_PUBLIC_VALINE_SERVER_URLS || '', // 该配置适用于国内自定义域名用户, 海外版本会自动检测(无需手动填写) @see https://valine.js.org/configuration.html#serverURLs
COMMENT_VALINE_PLACEHOLDER: process.env.NEXT_PUBLIC_VALINE_PLACEHOLDER || '抢个沙发吧~', // 可以搭配后台管理评论 https://github.com/DesertsP/Valine-Admin 便于查看评论,以及邮件通知,垃圾评论过滤等功能
COMMENT_VALINE_PLACEHOLDER:
process.env.NEXT_PUBLIC_VALINE_PLACEHOLDER || '抢个沙发吧~', // 可以搭配后台管理评论 https://github.com/DesertsP/Valine-Admin 便于查看评论,以及邮件通知,垃圾评论过滤等功能
COMMENT_WALINE_SERVER_URL: process.env.NEXT_PUBLIC_WALINE_SERVER_URL || '', // 请配置完整的Waline评论地址 例如 hhttps://preview-waline.tangly1024.com @see https://waline.js.org/guide/get-started.html
COMMENT_WALINE_RECENT: process.env.NEXT_PUBLIC_WALINE_RECENT || false, // 最新评论
@@ -357,15 +411,18 @@ const BLOG = {
// TOKEN: Webmention的API token
COMMENT_WEBMENTION_ENABLE: process.env.NEXT_PUBLIC_WEBMENTION_ENABLE || false,
COMMENT_WEBMENTION_AUTH: process.env.NEXT_PUBLIC_WEBMENTION_AUTH || '',
COMMENT_WEBMENTION_HOSTNAME: process.env.NEXT_PUBLIC_WEBMENTION_HOSTNAME || '',
COMMENT_WEBMENTION_TWITTER_USERNAME: process.env.NEXT_PUBLIC_TWITTER_USERNAME || '',
COMMENT_WEBMENTION_HOSTNAME:
process.env.NEXT_PUBLIC_WEBMENTION_HOSTNAME || '',
COMMENT_WEBMENTION_TWITTER_USERNAME:
process.env.NEXT_PUBLIC_TWITTER_USERNAME || '',
COMMENT_WEBMENTION_TOKEN: process.env.NEXT_PUBLIC_WEBMENTION_TOKEN || '',
// <---- 评论插件
// ----> 站点统计
ANALYTICS_VERCEL: process.env.NEXT_PUBLIC_ANALYTICS_VERCEL || false, // vercel自带的统计 https://vercel.com/docs/concepts/analytics/quickstart https://github.com/tangly1024/NotionNext/issues/897
ANALYTICS_BUSUANZI_ENABLE: process.env.NEXT_PUBLIC_ANALYTICS_BUSUANZI_ENABLE || true, // 展示网站阅读量、访问数 see http://busuanzi.ibruce.info/
ANALYTICS_BUSUANZI_ENABLE:
process.env.NEXT_PUBLIC_ANALYTICS_BUSUANZI_ENABLE || true, // 展示网站阅读量、访问数 see http://busuanzi.ibruce.info/
ANALYTICS_BAIDU_ID: process.env.NEXT_PUBLIC_ANALYTICS_BAIDU_ID || '', // e.g 只需要填写百度统计的id[baidu_id] -> https://hm.baidu.com/hm.js?[baidu_id]
ANALYTICS_CNZZ_ID: process.env.NEXT_PUBLIC_ANALYTICS_CNZZ_ID || '', // 只需要填写站长统计的id, [cnzz_id] -> https://s9.cnzz.com/z_stat.php?id=[cnzz_id]&web_id=[cnzz_id]
ANALYTICS_GOOGLE_ID: process.env.NEXT_PUBLIC_ANALYTICS_GOOGLE_ID || '', // 谷歌Analytics的id e.g: G-XXXXXXXXXX
@@ -378,13 +435,18 @@ const BLOG = {
MATOMO_HOST_URL: process.env.NEXT_PUBLIC_MATOMO_HOST_URL || '', // Matomo服务器地址不带斜杠
MATOMO_SITE_ID: process.env.NEXT_PUBLIC_MATOMO_SITE_ID || '', // Matomo网站ID
// ACKEE网站访客统计工具
ANALYTICS_ACKEE_TRACKER: process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_TRACKER || '', // e.g 'https://ackee.tangly1024.com/tracker.js'
ANALYTICS_ACKEE_DATA_SERVER: process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_DATA_SERVER || '', // e.g https://ackee.tangly1024.com , don't end with a slash
ANALYTICS_ACKEE_DOMAIN_ID: process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_DOMAIN_ID || '', // e.g '82e51db6-dec2-423a-b7c9-b4ff7ebb3302'
ANALYTICS_ACKEE_TRACKER:
process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_TRACKER || '', // e.g 'https://ackee.tangly1024.com/tracker.js'
ANALYTICS_ACKEE_DATA_SERVER:
process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_DATA_SERVER || '', // e.g https://ackee.tangly1024.com , don't end with a slash
ANALYTICS_ACKEE_DOMAIN_ID:
process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_DOMAIN_ID || '', // e.g '82e51db6-dec2-423a-b7c9-b4ff7ebb3302'
SEO_GOOGLE_SITE_VERIFICATION: process.env.NEXT_PUBLIC_SEO_GOOGLE_SITE_VERIFICATION || '', // Remove the value or replace it with your own google site verification code
SEO_GOOGLE_SITE_VERIFICATION:
process.env.NEXT_PUBLIC_SEO_GOOGLE_SITE_VERIFICATION || '', // Remove the value or replace it with your own google site verification code
SEO_BAIDU_SITE_VERIFICATION: process.env.NEXT_PUBLIC_SEO_BAIDU_SITE_VERIFICATION || '', // Remove the value or replace it with your own google site verification code
SEO_BAIDU_SITE_VERIFICATION:
process.env.NEXT_PUBLIC_SEO_BAIDU_SITE_VERIFICATION || '', // Remove the value or replace it with your own google site verification code
// 微软 Clarity 站点分析
CLARITY_ID: process.env.NEXT_PUBLIC_CLARITY_ID || null, // 只需要复制Clarity脚本中的ID部分ID是一个十位的英文数字组合
@@ -396,10 +458,14 @@ const BLOG = {
// 谷歌广告
ADSENSE_GOOGLE_ID: process.env.NEXT_PUBLIC_ADSENSE_GOOGLE_ID || '', // 谷歌广告ID e.g ca-pub-xxxxxxxxxxxxxxxx
ADSENSE_GOOGLE_TEST: process.env.NEXT_PUBLIC_ADSENSE_GOOGLE_TEST || false, // 谷歌广告ID测试模式这种模式获取假的测试广告用于开发 https://www.tangly1024.com/article/local-dev-google-adsense
ADSENSE_GOOGLE_SLOT_IN_ARTICLE: process.env.NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_IN_ARTICLE || '3806269138', // Google AdScene>广告>按单元广告>新建文章内嵌广告 粘贴html代码中的data-ad-slot值
ADSENSE_GOOGLE_SLOT_FLOW: process.env.NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_FLOW || '1510444138', // Google AdScene>广告>按单元广告>新建信息流广告
ADSENSE_GOOGLE_SLOT_NATIVE: process.env.NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_NATIVE || '4980048999', // Google AdScene>广告>按单元广告>新建原生广告
ADSENSE_GOOGLE_SLOT_AUTO: process.env.NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_AUTO || '8807314373', // Google AdScene>广告>按单元广告>新建展示广告 (自动广告
ADSENSE_GOOGLE_SLOT_IN_ARTICLE:
process.env.NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_IN_ARTICLE || '3806269138', // Google AdScene>广告>按单元广告>新建文章内嵌广告 粘贴html代码中的data-ad-slot值
ADSENSE_GOOGLE_SLOT_FLOW:
process.env.NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_FLOW || '1510444138', // Google AdScene>广告>按单元广告>新建信息流广告
ADSENSE_GOOGLE_SLOT_NATIVE:
process.env.NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_NATIVE || '4980048999', // Google AdScene>广告>按单元广告>新建原生广告
ADSENSE_GOOGLE_SLOT_AUTO:
process.env.NEXT_PUBLIC_ADSENSE_GOOGLE_SLOT_AUTO || '8807314373', // Google AdScene>广告>按单元广告>新建展示广告 (自动广告)
// 万维广告
AD_WWADS_ID: process.env.NEXT_PUBLIC_WWAD_ID || null, // https://wwads.cn/ 创建您的万维广告单元ID
@@ -413,13 +479,17 @@ const BLOG = {
type: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE || 'type', // 文章类型,
type_post: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_POST || 'Post', // 当type文章类型与此值相同时为博文。
type_page: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_PAGE || 'Page', // 当type文章类型与此值相同时为单页。
type_notice: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_NOTICE || 'Notice', // 当type文章类型与此值相同时为公告。
type_notice:
process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_NOTICE || 'Notice', // 当type文章类型与此值相同时为公告。
type_menu: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_MENU || 'Menu', // 当type文章类型与此值相同时为菜单。
type_sub_menu: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_SUB_MENU || 'SubMenu', // 当type文章类型与此值相同时为子菜单。
type_sub_menu:
process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_SUB_MENU || 'SubMenu', // 当type文章类型与此值相同时为子菜单。
title: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TITLE || 'title', // 文章标题
status: process.env.NEXT_PUBLIC_NOTION_PROPERTY_STATUS || 'status',
status_publish: process.env.NEXT_PUBLIC_NOTION_PROPERTY_STATUS_PUBLISH || 'Published', // 当status状态值与此相同时为发布可以为中文
status_invisible: process.env.NEXT_PUBLIC_NOTION_PROPERTY_STATUS_INVISIBLE || 'Invisible', // 当status状态值与此相同时为隐藏发布,可以为中文 除此之外其他页面状态不会显示在博客上
status_publish:
process.env.NEXT_PUBLIC_NOTION_PROPERTY_STATUS_PUBLISH || 'Published', // 当status状态值与此相同时为发布可以为中文
status_invisible:
process.env.NEXT_PUBLIC_NOTION_PROPERTY_STATUS_INVISIBLE || 'Invisible', // 当status状态值与此相同时为隐藏发布可以为中文 除此之外其他页面状态不会显示在博客上
summary: process.env.NEXT_PUBLIC_NOTION_PROPERTY_SUMMARY || 'summary',
slug: process.env.NEXT_PUBLIC_NOTION_PROPERTY_SLUG || 'slug',
category: process.env.NEXT_PUBLIC_NOTION_PROPERTY_CATEGORY || 'category',
@@ -450,8 +520,10 @@ const BLOG = {
// 作废配置
AVATAR: process.env.NEXT_PUBLIC_AVATAR || '/avatar.svg', // 作者头像被notion中的ICON覆盖。若无ICON则取public目录下的avatar.png
TITLE: process.env.NEXT_PUBLIC_TITLE || 'NotionNext BLOG', // 站点标题 被notion中的页面标题覆盖此处请勿留空白否则服务器无法编译
HOME_BANNER_IMAGE: process.env.NEXT_PUBLIC_HOME_BANNER_IMAGE || '/bg_image.jpg', // 首页背景大图, 会被notion中的封面图覆盖若无封面图则会使用代码中的 /public/bg_image.jpg 文件
DESCRIPTION: process.env.NEXT_PUBLIC_DESCRIPTION || '这是一个由NotionNext生成的站点', // 站点描述被notion中的页面描述覆盖
HOME_BANNER_IMAGE:
process.env.NEXT_PUBLIC_HOME_BANNER_IMAGE || '/bg_image.jpg', // 首页背景大图, 会被notion中的封面图覆盖若无封面图则会使用代码中的 /public/bg_image.jpg 文件
DESCRIPTION:
process.env.NEXT_PUBLIC_DESCRIPTION || '这是一个由NotionNext生成的站点', // 站点描述被notion中的页面描述覆盖
// 开发相关
NOTION_ACCESS_TOKEN: process.env.NOTION_ACCESS_TOKEN || '', // Useful if you prefer not to make your database public

View File

@@ -9,6 +9,7 @@ import { getPostBlocks, getSingleBlock } from '@/lib/notion/getPostBlocks'
import { compressImage, mapImgUrl } from '@/lib/notion/mapImage'
import { deepClone } from '@/lib/utils'
import { idToUuid } from 'notion-utils'
import { extractLangId, extractLangPrefix } from '../utils/pageId'
export { getAllTags } from '../notion/getAllTags'
export { getPost } from '../notion/getNotionPost'
@@ -18,18 +19,62 @@ export { getPostBlocks } from '../notion/getPostBlocks'
* 获取博客数据; 基于Notion实现
* @param {*} pageId
* @param {*} from
* @param latestPostCount 截取最新文章数量
* @param categoryCount
* @param tagsCount 截取标签数量
* @param pageType 过滤的文章类型,数组格式 ['Page','Post']
* @param {*} locale 语言 zh|en|jp 等等
* @returns
*
*/
export async function getGlobalData({ pageId = BLOG.NOTION_PAGE_ID, from }) {
// 从notion获取
const data = await getNotionPageData({ pageId, from })
export async function getGlobalData({
pageId = BLOG.NOTION_PAGE_ID,
from,
locale
}) {
// 获取站点数据 如果pageId有逗号隔开则分次取数据
const siteIds = pageId.split(',')
let data = EmptyData(pageId)
try {
for (let index = 0; index < siteIds.length; index++) {
const siteId = siteIds[index]
const id = extractLangId(siteId)
const prefix = extractLangPrefix(siteId)
// 第一个id站点默认语言
if (index === 0 || locale === prefix) {
data = await getNotionPageData({
pageId: id,
from
})
}
}
} catch (error) {
console.error('异常', error)
}
return data
}
/**
* 获取指定notion的collection数据
* @param pageId
* @param from 请求来源
* @returns {Promise<JSX.Element|*|*[]>}
*/
export async function getNotionPageData({ pageId, from }) {
// 尝试从缓存获取
const cacheKey = 'page_block_' + pageId
let data = await getDataFromCache(cacheKey)
if (data && data.pageIds?.length > 0) {
// console.log('[API<<--缓存]', `from:${from}`, `root-page-id:${pageId}`)
// return data
} else {
// 从接口读取
data = await getDataBaseInfoByNotionAPI({ pageId, from })
// 存入缓存
if (data) {
await setDataToCache(cacheKey, data)
}
}
// 返回给前端的数据做处理
const db = deepClone(data)
// 减少返回给前端的数据,减少流量损耗
delete db.block
delete db.schema
delete db.rawMetadata
@@ -47,10 +92,12 @@ export async function getGlobalData({ pageId = BLOG.NOTION_PAGE_ID, from }) {
if (db?.post) {
db.post = cleanBlock(db?.post)
}
return db
}
/**
* 清理block数据
*/
function cleanBlock(post) {
const pageBlock = post?.blockMap?.block
for (const i in pageBlock) {
@@ -98,28 +145,6 @@ function getLatestPosts({ allPages, from, latestPostCount }) {
return latestPosts.slice(0, latestPostCount)
}
/**
* 获取指定notion的collection数据
* @param pageId
* @param from 请求来源
* @returns {Promise<JSX.Element|*|*[]>}
*/
export async function getNotionPageData({ pageId, from }) {
// 尝试从缓存获取
const cacheKey = 'page_block_' + pageId
const data = await getDataFromCache(cacheKey)
if (data && data.pageIds?.length > 0) {
// console.log('[API<<--缓存]', `from:${from}`, `root-page-id:${pageId}`)
return data
}
const db = await getDataBaseInfoByNotionAPI({ pageId, from })
// 存入缓存
if (db) {
await setDataToCache(cacheKey, db)
}
return db
}
/**
* 获取用户自定义单页菜单
* 旧版本不读取Menu菜单而是读取type=Page生成菜单
@@ -308,6 +333,7 @@ const EmptyData = pageId => {
status: 'Published',
type: 'Post',
slug: '13a171332816461db29d50e9f575b00d',
pageCoverThumbnail: BLOG.HOME_BANNER_IMAGE,
date: {
start_date: '2023-04-24',
lastEditedDay: '2023-04-24',

View File

@@ -1,11 +1,11 @@
import zhCN from './lang/zh-CN'
import { getQueryVariable, isBrowser, mergeDeep } from '@/lib/utils'
import enUS from './lang/en-US'
import frFR from './lang/fr-FR'
import jaJP from './lang/ja-JP'
import trTR from './lang/tr-TR'
import zhCN from './lang/zh-CN'
import zhHK from './lang/zh-HK'
import zhTW from './lang/zh-TW'
import frFR from './lang/fr-FR'
import trTR from './lang/tr-TR'
import jaJP from './lang/ja-JP'
import { getQueryVariable, isBrowser, mergeDeep } from '@/lib/utils'
/**
* 在这里配置所有支持的语言
@@ -43,7 +43,9 @@ export function generateLocaleDict(langString) {
// 然后尝试匹配只有语言匹配的情况
if (!userLocale) {
const languageOnlyLocales = supportedLocales.filter(locale => locale.startsWith(language))
const languageOnlyLocales = supportedLocales.filter(locale =>
locale.startsWith(language)
)
if (languageOnlyLocales.length > 0) {
userLocale = LANGS[languageOnlyLocales[0]]
}
@@ -51,7 +53,9 @@ export function generateLocaleDict(langString) {
// 如果还没匹配到,则返回最接近的语言包
if (!userLocale) {
const fallbackLocale = supportedLocales.find(locale => locale.startsWith('en'))
const fallbackLocale = supportedLocales.find(locale =>
locale.startsWith('en')
)
userLocale = LANGS[fallbackLocale]
}
@@ -64,7 +68,11 @@ export function generateLocaleDict(langString) {
*/
export function initLocale(lang, locale, changeLang, changeLocale) {
if (isBrowser) {
const queryLang = getQueryVariable('lang') || loadLangFromLocalStorage()
// 用户请求的预研
const queryLang =
getQueryVariable('locale') ||
getQueryVariable('lang') ||
loadLangFromLocalStorage()
let currentLang = lang
if (queryLang && queryLang !== 'undefined' && queryLang !== lang) {
currentLang = queryLang
@@ -91,6 +99,6 @@ export const loadLangFromLocalStorage = () => {
* 保存语言
* @param newTheme
*/
export const saveLangToLocalStorage = (lang) => {
export const saveLangToLocalStorage = lang => {
localStorage.setItem('lang', lang)
}

View File

@@ -22,17 +22,27 @@ const mapImgUrl = (img, block, type = 'block', from = 'post') => {
}
// Notion 图床转换为永久地址
const isNotionSignImg = ret.indexOf('https://www.notion.so/image') !== 0 && (ret.indexOf('secure.notion-static.com') > 0 || ret.indexOf('prod-files-secure') > 0)
const isNotionSignImg =
ret.indexOf('https://www.notion.so/image') !== 0 &&
(ret.indexOf('secure.notion-static.com') > 0 ||
ret.indexOf('prod-files-secure') > 0)
const isImgBlock = BLOG.IMG_URL_TYPE === 'Notion' || type !== 'block'
if (isNotionSignImg && isImgBlock) {
ret = BLOG.NOTION_HOST + '/image/' + encodeURIComponent(ret) + '?table=' + type + '&id=' + block.id
ret =
BLOG.NOTION_HOST +
'/image/' +
encodeURIComponent(ret) +
'?table=' +
type +
'&id=' +
block.id
}
if (!isEmoji(ret) && ret.indexOf('notion.so/images/page-cover') < 0) {
if (BLOG.RANDOM_IMAGE_URL) {
// 只有配置了随机图片接口,才会替换图片
const texts = BLOG.RANDOM_IMAGE_REPLACE_TEXT
let isReplace = false;
let isReplace = false
if (texts) {
const textArr = texts.split(',')
// 判断是否包含替换的文本
@@ -58,7 +68,11 @@ const mapImgUrl = (img, block, type = 'block', from = 'post') => {
}
// 统一压缩图片
if (from === 'pageCoverThumbnail' || block.type === 'image' || block.type === 'page') {
if (
from === 'pageCoverThumbnail' ||
block?.type === 'image' ||
block?.type === 'page'
) {
const width = block?.format?.block_width
ret = compressImage(ret, width)
}
@@ -72,8 +86,9 @@ const mapImgUrl = (img, block, type = 'block', from = 'post') => {
* @returns
*/
function isEmoji(str) {
const emojiRegex = /[\u{1F300}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{1F900}-\u{1F9FF}\u{1F018}-\u{1F270}\u{238C}\u{2B06}\u{2B07}\u{2B05}\u{27A1}\u{2194}-\u{2199}\u{2194}\u{21A9}\u{21AA}\u{2934}\u{2935}\u{25AA}\u{25AB}\u{25FE}\u{25FD}\u{25FB}\u{25FC}\u{25B6}\u{25C0}\u{1F200}-\u{1F251}]/u;
return emojiRegex.test(str);
const emojiRegex =
/[\u{1F300}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{1F900}-\u{1F9FF}\u{1F018}-\u{1F270}\u{238C}\u{2B06}\u{2B07}\u{2B05}\u{27A1}\u{2194}-\u{2199}\u{2194}\u{21A9}\u{21AA}\u{2934}\u{2935}\u{25AA}\u{25AB}\u{25FE}\u{25FD}\u{25FB}\u{25FC}\u{25B6}\u{25C0}\u{1F200}-\u{1F251}]/u
return emojiRegex.test(str)
}
/**
@@ -97,7 +112,10 @@ const compressImage = (image, width, quality = 50, fmt = 'webp') => {
const params = new URLSearchParams(urlObj.search)
// Notion图床
if (image.indexOf(BLOG.NOTION_HOST) === 0 && image.indexOf('amazonaws.com') > 0) {
if (
image.indexOf(BLOG.NOTION_HOST) === 0 &&
image.indexOf('amazonaws.com') > 0
) {
params.set('width', width)
params.set('cache', 'v2')
// 生成新的URL
@@ -117,11 +135,11 @@ const compressImage = (image, width, quality = 50, fmt = 'webp') => {
return urlObj.toString()
} else if (image.indexOf('https://your_picture_bed') === 0) {
// 此处还可以添加您的自定义图传的封面图压缩参数。
// .e.g
// .e.g
return 'do_somethin_here'
}
return image
}
export { mapImgUrl, compressImage }
export { compressImage, mapImgUrl }

33
lib/utils/pageId.js Normal file
View File

@@ -0,0 +1,33 @@
/**
* 截取page-id的语言前缀
* notionPageId的格式可以是 en:xxxxx
* @param {*} str
* @returns en|zh|xx
*/
function extractLangPrefix(str) {
const match = str.match(/^(.+?):/)
if (match && match[1]) {
return match[1]
} else {
return ''
}
}
/**
* 截取page-id的id
* notionPageId的格式可以是 en:xxxxx * @param {*} str
* @returns xxxxx
*/
function extractLangId(str) {
// 使用正则表达式匹配字符串
const match = str.match(/:\s*(.+)/)
// 如果匹配成功,则返回匹配到的内容
if (match && match[1]) {
return match[1]
} else {
// 如果没有匹配到,则返回空字符串或者其他你想要返回的值
return str
}
}
module.exports = { extractLangPrefix, extractLangId }

View File

@@ -2,11 +2,36 @@ const { THEME } = require('./blog.config')
const fs = require('fs')
const path = require('path')
const BLOG = require('./blog.config')
const { extractLangPrefix } = require('./lib/utils/pageId')
// 打包时是否分析代码
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: BLOG.BUNDLE_ANALYZER
})
// 扫描项目 /themes下的目录名
const themes = scanSubdirectories(path.resolve(__dirname, 'themes'))
// 检测用户开启的多语言
const locales = (function () {
// 根据BLOG_NOTION_PAGE_ID 检查支持多少种语言数据.
// 支持如下格式配置多个语言的页面id xxx,zh:xxx,en:xxx
const langs = ['zh', 'en']
if (BLOG.NOTION_PAGE_ID.indexOf(',') > 0) {
const siteIds = BLOG.NOTION_PAGE_ID.split(',')
for (let index = 0; index < siteIds.length; index++) {
const siteId = siteIds[index]
const prefix = extractLangPrefix(siteId)
// 如果包含前缀 例如 zh , en 等
if (prefix) {
if (!langs.includes(prefix)) {
langs.push(prefix)
}
}
}
}
return langs
})()
/**
* 扫描指定目录下的文件夹名,用于获取所有主题
* @param {*} directory
@@ -27,8 +52,7 @@ function scanSubdirectories(directory) {
return subdirectories
}
// 扫描项目 /themes下的目录名
const themes = scanSubdirectories(path.resolve(__dirname, 'themes'))
module.exports = withBundleAnalyzer({
images: {
// 图片压缩
@@ -55,8 +79,52 @@ module.exports = withBundleAnalyzer({
}
]
},
// 多语言
i18n: {
defaultLocale: BLOG.LANG.slice(0, 2),
// 支持的所有多语言,按需填写即可
locales
},
// 重写url
async rewrites() {
// 处理多语言重定向
const langsRewrites = []
if (BLOG.NOTION_PAGE_ID.indexOf(',') > 0) {
const siteIds = BLOG.NOTION_PAGE_ID.split(',')
const langs = []
for (let index = 0; index < siteIds.length; index++) {
const siteId = siteIds[index]
const prefix = extractLangPrefix(siteId)
// 如果包含前缀 例如 zh , en 等
if (prefix) {
langs.push(prefix)
}
console.log('[Locales]', siteId)
}
// 映射多语言
// 示例: source: '/:locale(zh|en)/:path*' ; :locale() 会将语言放入重写后的 `?locale=` 中。
langsRewrites.push(
{
source: `/:locale(${langs.join('|')})/:path*`,
destination: '/:path*'
},
// 匹配没有路径的情况,例如 [domain]/zh 或 [domain]/en
{
source: `/:locale(${langs.join('|')})`,
destination: '/'
},
// 匹配没有路径的情况,例如 [domain]/zh/ 或 [domain]/en/
{
source: `/:locale(${langs.join('|')})/`,
destination: '/'
}
)
}
return [
...langsRewrites,
// 伪静态重写
{
source: '/:path*.html',
destination: '/:path*'
@@ -84,17 +152,9 @@ module.exports = withBundleAnalyzer({
]
},
webpack: (config, { dev, isServer }) => {
// Replace React with Preact only in client production build
// if (!dev && !isServer) {
// Object.assign(config.resolve.alias, {
// react: 'preact/compat',
// 'react-dom/test-utils': 'preact/test-utils',
// 'react-dom': 'preact/compat'
// })
// }
// 动态主题:添加 resolve.alias 配置,将动态路径映射到实际路径
if (!isServer) {
console.log('[加载主题]', path.resolve(__dirname, 'themes', THEME))
console.log('[默认主题]', path.resolve(__dirname, 'themes', THEME))
}
config.resolve.alias['@theme-components'] = path.resolve(
__dirname,

View File

@@ -1,7 +1,7 @@
import { getGlobalData } from '@/lib/db/getSiteData'
import { useRouter } from 'next/router'
import { getLayoutByTheme } from '@/themes/theme'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
import { getLayoutByTheme } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
* 404
@@ -10,12 +10,17 @@ import { siteConfig } from '@/lib/config'
*/
const NoFound = props => {
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
return <Layout {...props} />
}
export async function getStaticProps () {
const props = (await getGlobalData({ from: '404' })) || {}
export async function getStaticProps(req) {
const { locale } = req
const props = (await getGlobalData({ from: '404', locale })) || {}
return { props }
}

View File

@@ -35,7 +35,11 @@ export async function getStaticPaths() {
paths: allPages
?.filter(row => checkSlug(row))
.map(row => ({
params: { prefix: row.slug.split('/')[0], slug: row.slug.split('/')[1], suffix: row.slug.split('/').slice(1) }
params: {
prefix: row.slug.split('/')[0],
slug: row.slug.split('/')[1],
suffix: row.slug.split('/').slice(1)
}
})),
fallback: true
}
@@ -46,7 +50,10 @@ export async function getStaticPaths() {
* @param {*} param0
* @returns
*/
export async function getStaticProps({ params: { prefix, slug, suffix } }) {
export async function getStaticProps({
params: { prefix, slug, suffix },
locale
}) {
let fullSlug = prefix + '/' + slug + '/' + suffix.join('/')
if (JSON.parse(BLOG.PSEUDO_STATIC)) {
if (!fullSlug.endsWith('.html')) {
@@ -54,10 +61,13 @@ export async function getStaticProps({ params: { prefix, slug, suffix } }) {
}
}
const from = `slug-props-${fullSlug}`
const props = await getGlobalData({ from })
const props = await getGlobalData({ from, locale })
// 在列表内查找文章
props.post = props?.allPages?.find(p => {
return p.type.indexOf('Menu') < 0 && (p.slug === fullSlug || p.id === idToUuid(fullSlug))
return (
p.type.indexOf('Menu') < 0 &&
(p.slug === fullSlug || p.id === idToUuid(fullSlug))
)
})
// 处理非列表内文章的内信息
@@ -85,12 +95,18 @@ export async function getStaticProps({ params: { prefix, slug, suffix } }) {
}
// 推荐关联文章处理
const allPosts = props.allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
const allPosts = props.allPages?.filter(
page => page.type === 'Post' && page.status === 'Published'
)
if (allPosts && allPosts.length > 0) {
const index = allPosts.indexOf(props.post)
props.prev = allPosts.slice(index - 1, index)[0] ?? allPosts.slice(-1)[0]
props.next = allPosts.slice(index + 1, index + 2)[0] ?? allPosts[0]
props.recommendPosts = getRecommendPost(props.post, allPosts, siteConfig('POST_RECOMMEND_COUNT'))
props.recommendPosts = getRecommendPost(
props.post,
allPosts,
siteConfig('POST_RECOMMEND_COUNT')
)
} else {
props.prev = null
props.next = null
@@ -109,7 +125,11 @@ function checkSlug(row) {
if (slug.startsWith('/')) {
slug = slug.substring(1)
}
return (slug.match(/\//g) || []).length >= 2 && row.type.indexOf('Menu') < 0 && !checkContainHttp(slug)
return (
(slug.match(/\//g) || []).length >= 2 &&
row.type.indexOf('Menu') < 0 &&
!checkContainHttp(slug)
)
}
export default PrefixSlug

View File

@@ -28,14 +28,16 @@ export async function getStaticPaths() {
const { allPages } = await getGlobalData({ from })
const paths = allPages
?.filter(row => checkSlug(row))
.map(row => ({ params: { prefix: row.slug.split('/')[0], slug: row.slug.split('/')[1] } }))
.map(row => ({
params: { prefix: row.slug.split('/')[0], slug: row.slug.split('/')[1] }
}))
return {
paths: paths,
fallback: true
}
}
export async function getStaticProps({ params: { prefix, slug } }) {
export async function getStaticProps({ params: { prefix, slug }, locale }) {
let fullSlug = prefix + '/' + slug
if (JSON.parse(BLOG.PSEUDO_STATIC)) {
if (!fullSlug.endsWith('.html')) {
@@ -43,10 +45,13 @@ export async function getStaticProps({ params: { prefix, slug } }) {
}
}
const from = `slug-props-${fullSlug}`
const props = await getGlobalData({ from })
const props = await getGlobalData({ from, locale })
// 在列表内查找文章
props.post = props?.allPages?.find(p => {
return p.type.indexOf('Menu') < 0 && (p.slug === fullSlug || p.id === idToUuid(fullSlug))
return (
p.type.indexOf('Menu') < 0 &&
(p.slug === fullSlug || p.id === idToUuid(fullSlug))
)
})
// 处理非列表内文章的内信息
@@ -74,12 +79,18 @@ export async function getStaticProps({ params: { prefix, slug } }) {
}
// 推荐关联文章处理
const allPosts = props.allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
const allPosts = props.allPages?.filter(
page => page.type === 'Post' && page.status === 'Published'
)
if (allPosts && allPosts.length > 0) {
const index = allPosts.indexOf(props.post)
props.prev = allPosts.slice(index - 1, index)[0] ?? allPosts.slice(-1)[0]
props.next = allPosts.slice(index + 1, index + 2)[0] ?? allPosts[0]
props.recommendPosts = getRecommendPost(props.post, allPosts, siteConfig('POST_RECOMMEND_COUNT'))
props.recommendPosts = getRecommendPost(
props.post,
allPosts,
siteConfig('POST_RECOMMEND_COUNT')
)
} else {
props.prev = null
props.next = null
@@ -97,6 +108,10 @@ function checkSlug(row) {
if (slug.startsWith('/')) {
slug = slug.substring(1)
}
return (slug.match(/\//g) || []).length === 1 && !checkContainHttp(slug) && row.type.indexOf('Menu') < 0
return (
(slug.match(/\//g) || []).length === 1 &&
!checkContainHttp(slug) &&
row.type.indexOf('Menu') < 0
)
}
export default PrefixSlug

View File

@@ -53,7 +53,10 @@ const Slug = props => {
props = { ...props, lock, setLock, validPassword }
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
return <Layout {...props} />
}
@@ -67,14 +70,16 @@ export async function getStaticPaths() {
const from = 'slug-paths'
const { allPages } = await getGlobalData({ from })
const paths = allPages?.filter(row => checkSlug(row)).map(row => ({ params: { prefix: row.slug } }))
const paths = allPages
?.filter(row => checkSlug(row))
.map(row => ({ params: { prefix: row.slug } }))
return {
paths: paths,
fallback: true
}
}
export async function getStaticProps({ params: { prefix } }) {
export async function getStaticProps({ params: { prefix }, locale }) {
let fullSlug = prefix
if (JSON.parse(BLOG.PSEUDO_STATIC)) {
if (!fullSlug.endsWith('.html')) {
@@ -82,10 +87,13 @@ export async function getStaticProps({ params: { prefix } }) {
}
}
const from = `slug-props-${fullSlug}`
const props = await getGlobalData({ from })
const props = await getGlobalData({ from, locale })
// 在列表内查找文章
props.post = props?.allPages?.find(p => {
return p.type.indexOf('Menu') < 0 && (p.slug === fullSlug || p.id === idToUuid(fullSlug))
return (
p.type.indexOf('Menu') < 0 &&
(p.slug === fullSlug || p.id === idToUuid(fullSlug))
)
})
// 处理非列表内文章的内信息
@@ -113,12 +121,18 @@ export async function getStaticProps({ params: { prefix } }) {
}
// 推荐关联文章处理
const allPosts = props.allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
const allPosts = props.allPages?.filter(
page => page.type === 'Post' && page.status === 'Published'
)
if (allPosts && allPosts.length > 0) {
const index = allPosts.indexOf(props.post)
props.prev = allPosts.slice(index - 1, index)[0] ?? allPosts.slice(-1)[0]
props.next = allPosts.slice(index + 1, index + 2)[0] ?? allPosts[0]
props.recommendPosts = getRecommendPost(props.post, allPosts, siteConfig('POST_RECOMMEND_COUNT'))
props.recommendPosts = getRecommendPost(
props.post,
allPosts,
siteConfig('POST_RECOMMEND_COUNT')
)
} else {
props.prev = null
props.next = null
@@ -172,7 +186,11 @@ function checkSlug(row) {
if (slug.startsWith('/')) {
slug = slug.substring(1)
}
return (slug.match(/\//g) || []).length === 0 && !checkContainHttp(slug) && row.type.indexOf('Menu') < 0
return (
(slug.match(/\//g) || []).length === 0 &&
!checkContainHttp(slug) &&
row.type.indexOf('Menu') < 0
)
}
export default Slug

View File

@@ -1,15 +1,18 @@
import { getGlobalData } from '@/lib/db/getSiteData'
import { useEffect } from 'react'
import BLOG from '@/blog.config'
import { useRouter } from 'next/router'
import { getLayoutByTheme } from '@/themes/theme'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
import { isBrowser } from '@/lib/utils'
import { formatDateFmt } from '@/lib/utils/formatDate'
import { siteConfig } from '@/lib/config'
import { getLayoutByTheme } from '@/themes/theme'
import { useRouter } from 'next/router'
import { useEffect } from 'react'
const ArchiveIndex = props => {
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
useEffect(() => {
if (isBrowser) {
@@ -28,10 +31,12 @@ const ArchiveIndex = props => {
return <Layout {...props} />
}
export async function getStaticProps() {
const props = await getGlobalData({ from: 'archive-index' })
export async function getStaticProps({ locale }) {
const props = await getGlobalData({ from: 'archive-index', locale })
// 处理分页
props.posts = props.allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
props.posts = props.allPages?.filter(
page => page.type === 'Post' && page.status === 'Published'
)
delete props.allPages
const postsSortByDate = Object.create(props.posts)

View File

@@ -11,19 +11,26 @@ import { useRouter } from 'next/router'
*/
export default function Category(props) {
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
return <Layout {...props} />
}
export async function getStaticProps({ params: { category } }) {
export async function getStaticProps({ params: { category }, locale }) {
const from = 'category-props'
let props = await getGlobalData({ from })
let props = await getGlobalData({ from, locale })
// 过滤状态
props.posts = props.allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
props.posts = props.allPages?.filter(
page => page.type === 'Post' && page.status === 'Published'
)
// 处理过滤
props.posts = props.posts.filter(post => post && post.category && post.category.includes(category))
props.posts = props.posts.filter(
post => post && post.category && post.category.includes(category)
)
// 处理文章页数
props.postCount = props.posts.length
// 处理分页

View File

@@ -1,9 +1,8 @@
import { getGlobalData } from '@/lib/db/getSiteData'
import React from 'react'
import BLOG from '@/blog.config'
import { useRouter } from 'next/router'
import { getLayoutByTheme } from '@/themes/theme'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
import { getLayoutByTheme } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
* 分类首页
@@ -12,13 +11,16 @@ import { siteConfig } from '@/lib/config'
*/
export default function Category(props) {
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
return <Layout {...props} />
}
export async function getStaticProps() {
const props = await getGlobalData({ from: 'category-index-props' })
export async function getStaticProps({ locale }) {
const props = await getGlobalData({ from: 'category-index-props', locale })
delete props.allPages
return {
props,

View File

@@ -24,9 +24,10 @@ const Index = props => {
* SSG 获取数据
* @returns
*/
export async function getStaticProps() {
export async function getStaticProps(req) {
const { locale } = req
const from = 'index'
const props = await getGlobalData({ from })
const props = await getGlobalData({ from, locale })
props.posts = props.allPages?.filter(
page => page.type === 'Post' && page.status === 'Published'

View File

@@ -11,14 +11,17 @@ import { useRouter } from 'next/router'
*/
const Page = props => {
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
return <Layout {...props} />
}
export async function getStaticPaths() {
export async function getStaticPaths({ locale }) {
const from = 'page-paths'
const { postCount } = await getGlobalData({ from })
const { postCount } = await getGlobalData({ from, locale })
const totalPages = Math.ceil(postCount / siteConfig('POSTS_PER_PAGE'))
return {
// remove first page, we 're not gonna handle that.
@@ -33,9 +36,14 @@ export async function getStaticProps({ params: { page } }) {
const from = `page-${page}`
const props = await getGlobalData({ from })
const { allPages } = props
const allPosts = allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
const allPosts = allPages?.filter(
page => page.type === 'Post' && page.status === 'Published'
)
// 处理分页
props.posts = allPosts.slice(siteConfig('POSTS_PER_PAGE') * (page - 1), siteConfig('POSTS_PER_PAGE') * page)
props.posts = allPosts.slice(
siteConfig('POSTS_PER_PAGE') * (page - 1),
siteConfig('POSTS_PER_PAGE') * page
)
props.page = page
// 处理预览
@@ -45,7 +53,11 @@ export async function getStaticProps({ params: { page } }) {
if (post.password && post.password !== '') {
continue
}
post.blockMap = await getPostBlocks(post.id, 'slug', siteConfig('POST_PREVIEW_LINES'))
post.blockMap = await getPostBlocks(
post.id,
'slug',
siteConfig('POST_PREVIEW_LINES')
)
}
}

View File

@@ -7,7 +7,10 @@ import { useRouter } from 'next/router'
const Index = props => {
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
return <Layout {...props} />
}
@@ -17,13 +20,15 @@ const Index = props => {
* @param {*} param0
* @returns
*/
export async function getStaticProps({ params: { keyword } }) {
export async function getStaticProps({ params: { keyword }, locale }) {
const props = await getGlobalData({
from: 'search-props',
pageType: ['Post']
locale
})
const { allPages } = props
const allPosts = allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
const allPosts = allPages?.filter(
page => page.type === 'Post' && page.status === 'Published'
)
props.posts = await filterByMemCache(allPosts, keyword)
props.postCount = props.posts.length
// 处理分页
@@ -87,7 +92,8 @@ function getTextContent(textArray) {
* @param {*} obj
* @returns
*/
const isIterable = obj => obj != null && typeof obj[Symbol.iterator] === 'function'
const isIterable = obj =>
obj != null && typeof obj[Symbol.iterator] === 'function'
/**
* 在内存缓存中进行全文索引
@@ -103,8 +109,12 @@ async function filterByMemCache(allPosts, keyword) {
for (const post of allPosts) {
const cacheKey = 'page_block_' + post.id
const page = await getDataFromCache(cacheKey, true)
const tagContent = post?.tags && Array.isArray(post?.tags) ? post?.tags.join(' ') : ''
const categoryContent = post.category && Array.isArray(post.category) ? post.category.join(' ') : ''
const tagContent =
post?.tags && Array.isArray(post?.tags) ? post?.tags.join(' ') : ''
const categoryContent =
post.category && Array.isArray(post.category)
? post.category.join(' ')
: ''
const articleInfo = post.title + post.summary + tagContent + categoryContent
let hit = articleInfo.toLowerCase().indexOf(keyword) > -1
const indexContent = getPageContentText(post, page)

View File

@@ -8,7 +8,10 @@ import { useRouter } from 'next/router'
const Index = props => {
const { keyword } = props
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
props = { ...props, currentSearch: keyword }
return <Layout {...props} />
@@ -19,17 +22,23 @@ const Index = props => {
* @param {*} param0
* @returns
*/
export async function getStaticProps({ params: { keyword, page } }) {
export async function getStaticProps({ params: { keyword, page }, locale }) {
const props = await getGlobalData({
from: 'search-props',
pageType: ['Post']
pageType: ['Post'],
locale
})
const { allPages } = props
const allPosts = allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
const allPosts = allPages?.filter(
page => page.type === 'Post' && page.status === 'Published'
)
props.posts = await filterByMemCache(allPosts, keyword)
props.postCount = props.posts.length
// 处理分页
props.posts = props.posts.slice(siteConfig('POSTS_PER_PAGE') * (page - 1), siteConfig('POSTS_PER_PAGE') * page)
props.posts = props.posts.slice(
siteConfig('POSTS_PER_PAGE') * (page - 1),
siteConfig('POSTS_PER_PAGE') * page
)
props.keyword = keyword
props.page = page
delete props.allPages
@@ -87,7 +96,8 @@ function getTextContent(textArray) {
* @param {*} obj
* @returns
*/
const isIterable = obj => obj != null && typeof obj[Symbol.iterator] === 'function'
const isIterable = obj =>
obj != null && typeof obj[Symbol.iterator] === 'function'
/**
* 在内存缓存中进行全文索引
@@ -103,8 +113,12 @@ async function filterByMemCache(allPosts, keyword) {
for (const post of allPosts) {
const cacheKey = 'page_block_' + post.id
const page = await getDataFromCache(cacheKey, true)
const tagContent = post?.tags && Array.isArray(post?.tags) ? post?.tags.join(' ') : ''
const categoryContent = post.category && Array.isArray(post.category) ? post.category.join(' ') : ''
const tagContent =
post?.tags && Array.isArray(post?.tags) ? post?.tags.join(' ') : ''
const categoryContent =
post.category && Array.isArray(post.category)
? post.category.join(' ')
: ''
const articleInfo = post.title + post.summary + tagContent + categoryContent
let hit = articleInfo.indexOf(keyword) > -1
let indexContent = [post.summary]

View File

@@ -1,8 +1,8 @@
import { getGlobalData } from '@/lib/db/getSiteData'
import { useRouter } from 'next/router'
import BLOG from '@/blog.config'
import { getLayoutByTheme } from '@/themes/theme'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
import { getLayoutByTheme } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
* 搜索路由
@@ -13,7 +13,10 @@ const Search = props => {
const { posts } = props
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
const router = useRouter()
const keyword = router?.query?.s
@@ -25,7 +28,7 @@ const Search = props => {
const tagContent = post?.tags ? post?.tags.join(' ') : ''
const categoryContent = post.category ? post.category.join(' ') : ''
const searchContent =
post.title + post.summary + tagContent + categoryContent
post.title + post.summary + tagContent + categoryContent
return searchContent.toLowerCase().includes(keyword.toLowerCase())
})
} else {
@@ -40,13 +43,15 @@ const Search = props => {
/**
* 浏览器前端搜索
*/
export async function getStaticProps() {
export async function getStaticProps({ locale }) {
const props = await getGlobalData({
from: 'search-props',
pageType: ['Post']
locale
})
const { allPages } = props
props.posts = allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
props.posts = allPages?.filter(
page => page.type === 'Post' && page.status === 'Published'
)
return {
props,
revalidate: parseInt(BLOG.NEXT_REVALIDATE_SECOND)

View File

@@ -1,8 +1,8 @@
import BLOG from '@/blog.config'
import { getGlobalData } from '@/lib/db/getSiteData'
import { useRouter } from 'next/router'
import { getLayoutByTheme } from '@/themes/theme'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
import { getLayoutByTheme } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
* 登录
@@ -11,13 +11,18 @@ import { siteConfig } from '@/lib/config'
*/
const SignIn = props => {
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
return <Layout {...props} />
}
export async function getStaticProps() {
export async function getStaticProps(req) {
const { locale } = req
const from = 'SignIn'
const props = await getGlobalData({ from })
const props = await getGlobalData({ from, locale })
delete props.allPages
return {

View File

@@ -1,8 +1,8 @@
import BLOG from '@/blog.config'
import { getGlobalData } from '@/lib/db/getSiteData'
import { useRouter } from 'next/router'
import { getLayoutByTheme } from '@/themes/theme'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
import { getLayoutByTheme } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
* 注册
@@ -11,13 +11,18 @@ import { siteConfig } from '@/lib/config'
*/
const SignUp = props => {
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
return <Layout {...props} />
}
export async function getStaticProps() {
export async function getStaticProps(req) {
const { locale } = req
const from = 'SignIn'
const props = await getGlobalData({ from })
const props = await getGlobalData({ from, locale })
delete props.allPages
return {

View File

@@ -11,14 +11,17 @@ import { useRouter } from 'next/router'
*/
const Tag = props => {
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
return <Layout {...props} />
}
export async function getStaticProps({ params: { tag } }) {
export async function getStaticProps({ params: { tag }, locale }) {
const from = 'tag-props'
const props = await getGlobalData({ from })
const props = await getGlobalData({ from, locale })
// 过滤状态
props.posts = props.allPages

View File

@@ -6,13 +6,16 @@ import { useRouter } from 'next/router'
const Tag = props => {
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
return <Layout {...props} />
}
export async function getStaticProps({ params: { tag, page } }) {
export async function getStaticProps({ params: { tag, page }, locale }) {
const from = 'tag-page-props'
const props = await getGlobalData({ from })
const props = await getGlobalData({ from, locale })
// 过滤状态、标签
props.posts = props.allPages
?.filter(page => page.type === 'Post' && page.status === 'Published')
@@ -20,7 +23,10 @@ export async function getStaticProps({ params: { tag, page } }) {
// 处理文章数
props.postCount = props.posts.length
// 处理分页
props.posts = props.posts.slice(siteConfig('POSTS_PER_PAGE') * (page - 1), siteConfig('POSTS_PER_PAGE') * page)
props.posts = props.posts.slice(
siteConfig('POSTS_PER_PAGE') * (page - 1),
siteConfig('POSTS_PER_PAGE') * page
)
props.tag = tag
props.page = page

View File

@@ -1,8 +1,8 @@
import { getGlobalData } from '@/lib/db/getSiteData'
import BLOG from '@/blog.config'
import { useRouter } from 'next/router'
import { getLayoutByTheme } from '@/themes/theme'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
import { getLayoutByTheme } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
* 标签首页
@@ -11,13 +11,18 @@ import { siteConfig } from '@/lib/config'
*/
const TagIndex = props => {
// 根据页面路径加载不同Layout文件
const Layout = getLayoutByTheme({ theme: siteConfig('THEME'), router: useRouter() })
const Layout = getLayoutByTheme({
theme: siteConfig('THEME'),
router: useRouter()
})
return <Layout {...props} />
}
export async function getStaticProps() {
export async function getStaticProps(req) {
const { locale } = req
const from = 'tag-index-props'
const props = await getGlobalData({ from })
const props = await getGlobalData({ from, locale })
delete props.allPages
return {
props,