diff --git a/blog.config.js b/blog.config.js index df30298b..abfc4cd2 100644 --- a/blog.config.js +++ b/blog.config.js @@ -1,7 +1,9 @@ // 注: process.env.XX是Vercel的环境变量,配置方式见:https://docs.tangly1024.com/article/how-to-config-notion-next#c4768010ae7d44609b744e79e2f9959a const BLOG = { // Important page_id!!!Duplicate 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 | 0(0:禁用 lrc 歌词,1:lrc 格式的字符串,3:lrc 文件 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 | 0(0:禁用 lrc 歌词,1:lrc 格式的字符串,3:lrc 文件 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 | 0(0:禁用 lrc 歌词,1:lrc 格式的字符串,3:lrc 文件 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后端地址 腾讯云环境填envId;Vercel环境填域名,教程: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 diff --git a/lib/db/getSiteData.js b/lib/db/getSiteData.js index e7771025..c4d4931d 100755 --- a/lib/db/getSiteData.js +++ b/lib/db/getSiteData.js @@ -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} + */ +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} - */ -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', diff --git a/lib/lang.js b/lib/lang.js index 60b80882..e05ac5e3 100644 --- a/lib/lang.js +++ b/lib/lang.js @@ -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) } diff --git a/lib/notion/mapImage.js b/lib/notion/mapImage.js index 615ed5c9..e0d92f83 100644 --- a/lib/notion/mapImage.js +++ b/lib/notion/mapImage.js @@ -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 } diff --git a/lib/utils/pageId.js b/lib/utils/pageId.js new file mode 100644 index 00000000..e3c648e1 --- /dev/null +++ b/lib/utils/pageId.js @@ -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 } diff --git a/next.config.js b/next.config.js index c4e9d8e4..cf4fa85f 100644 --- a/next.config.js +++ b/next.config.js @@ -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, diff --git a/pages/404.js b/pages/404.js index a4746405..78278918 100644 --- a/pages/404.js +++ b/pages/404.js @@ -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 } -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 } } diff --git a/pages/[prefix]/[slug]/[...suffix].js b/pages/[prefix]/[slug]/[...suffix].js index 3ce0b105..84591ca5 100644 --- a/pages/[prefix]/[slug]/[...suffix].js +++ b/pages/[prefix]/[slug]/[...suffix].js @@ -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 diff --git a/pages/[prefix]/[slug]/index.js b/pages/[prefix]/[slug]/index.js index 147d9ecb..0af41678 100644 --- a/pages/[prefix]/[slug]/index.js +++ b/pages/[prefix]/[slug]/index.js @@ -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 diff --git a/pages/[prefix]/index.js b/pages/[prefix]/index.js index 567f0244..a0de57bd 100644 --- a/pages/[prefix]/index.js +++ b/pages/[prefix]/index.js @@ -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 } @@ -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 diff --git a/pages/archive/index.js b/pages/archive/index.js index 13bc905b..43eb7d27 100644 --- a/pages/archive/index.js +++ b/pages/archive/index.js @@ -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 } -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) diff --git a/pages/category/[category]/index.js b/pages/category/[category]/index.js index 718d2b42..3c7caf62 100644 --- a/pages/category/[category]/index.js +++ b/pages/category/[category]/index.js @@ -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 } -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 // 处理分页 diff --git a/pages/category/index.js b/pages/category/index.js index e4532cbc..e3af2bda 100644 --- a/pages/category/index.js +++ b/pages/category/index.js @@ -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 } -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, diff --git a/pages/index.js b/pages/index.js index 9f2dfb91..b6cb5014 100644 --- a/pages/index.js +++ b/pages/index.js @@ -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' diff --git a/pages/page/[page].js b/pages/page/[page].js index 9b1278b6..34ce91c7 100644 --- a/pages/page/[page].js +++ b/pages/page/[page].js @@ -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 } -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') + ) } } diff --git a/pages/search/[keyword]/index.js b/pages/search/[keyword]/index.js index 0038c9f8..b1d8f6c2 100644 --- a/pages/search/[keyword]/index.js +++ b/pages/search/[keyword]/index.js @@ -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 } @@ -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) diff --git a/pages/search/[keyword]/page/[page].js b/pages/search/[keyword]/page/[page].js index 43291b0b..2f01ec24 100644 --- a/pages/search/[keyword]/page/[page].js +++ b/pages/search/[keyword]/page/[page].js @@ -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 @@ -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] diff --git a/pages/search/index.js b/pages/search/index.js index e41da00b..3b637cd1 100644 --- a/pages/search/index.js +++ b/pages/search/index.js @@ -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) diff --git a/pages/signin.js b/pages/signin.js index 0fc037bc..42977ffe 100644 --- a/pages/signin.js +++ b/pages/signin.js @@ -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 } -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 { diff --git a/pages/signup.js b/pages/signup.js index 1fccbe8b..033b7796 100644 --- a/pages/signup.js +++ b/pages/signup.js @@ -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 } -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 { diff --git a/pages/tag/[tag]/index.js b/pages/tag/[tag]/index.js index ea4ffe6a..153cf415 100644 --- a/pages/tag/[tag]/index.js +++ b/pages/tag/[tag]/index.js @@ -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 } -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 diff --git a/pages/tag/[tag]/page/[page].js b/pages/tag/[tag]/page/[page].js index 4566b059..519f9146 100644 --- a/pages/tag/[tag]/page/[page].js +++ b/pages/tag/[tag]/page/[page].js @@ -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 } -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 diff --git a/pages/tag/index.js b/pages/tag/index.js index 2141242d..24b3b148 100644 --- a/pages/tag/index.js +++ b/pages/tag/index.js @@ -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 } -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,