diff --git a/.env.local b/.env.local index cfe09402..db9decf2 100644 --- a/.env.local +++ b/.env.local @@ -1,5 +1,5 @@ # 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables -NEXT_PUBLIC_VERSION=4.4.2 +NEXT_PUBLIC_VERSION=4.4.3 # 可在此添加环境变量,去掉最左边的(# )注释即可 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index c063ca6c..4a5e7e3f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -12,16 +12,13 @@ assignees: tangly1024 --> **描述bug** -【此项必填】简单说明bug的现象、相关的错误提示、日志等 - -**复现步骤** -【此项必填】出现这个bug的操作步骤 +【此项必填】简单说明目前出现的现象、相关的错误提示、日志等、截图 **期望的正常结果** -【此项必填】希望按这个步骤,正常操作结果是什么 +【此项必填】按这个步骤,预期出现的现象应该是什么 -**截图** -【可选】相关的页面,应该的结果 +**复现步骤** +【此项必填】你的操作步骤,按此步骤理应在我的开发环境出现一样的bug。 **环境** @@ -32,4 +29,4 @@ assignees: tangly1024 - 【可选】浏览器 [例如. chrome, safari, firefox] **补充说明** -【可选】与问题相关的其它说明 \ No newline at end of file +【可选】与问题相关的其它说明 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/components/AOSAnimation.js b/components/AOSAnimation.js index c5dd4d92..076ab379 100644 --- a/components/AOSAnimation.js +++ b/components/AOSAnimation.js @@ -1,12 +1,30 @@ -import AOS from 'aos' -import { isBrowser } from 'react-notion-x' +import { loadExternalResource } from '@/lib/utils' +import { useEffect } from 'react' +// import AOS from 'aos' /** * 加载滚动动画 + * 改从外部CDN读取 * https://michalsnik.github.io/aos/ */ export default function AOSAnimation() { - if (isBrowser) { - AOS.init() + const initAOS = async () => { + Promise.all([ + loadExternalResource( + 'https://cdn.bootcdn.net/ajax/libs/aos/2.3.4/aos.js', + 'js' + ), + loadExternalResource( + 'https://cdn.bootcdn.net/ajax/libs/aos/2.3.4/aos.css', + 'css' + ) + ]).then(() => { + if (window.AOS) { + window.AOS.init() + } + }) } + useEffect(() => { + initAOS() + }, []) } diff --git a/components/ExternalPlugins.js b/components/ExternalPlugins.js index 3df09e6c..477bdce3 100644 --- a/components/ExternalPlugins.js +++ b/components/ExternalPlugins.js @@ -1,43 +1,79 @@ import { siteConfig } from '@/lib/config' import dynamic from 'next/dynamic' -import LA51 from './LA51' -import WebWhiz from './Webwhiz' -import TianLiGPT from './TianliGPT' import { GlobalStyle } from './GlobalStyle' +import LA51 from './LA51' +import TianLiGPT from './TianliGPT' +import WebWhiz from './Webwhiz' import { CUSTOM_EXTERNAL_CSS, CUSTOM_EXTERNAL_JS } from '@/blog.config' import { isBrowser, loadExternalResource } from '@/lib/utils' +import { useEffect } from 'react' +import { initGoogleAdsense } from './GoogleAdsense' -const TwikooCommentCounter = dynamic(() => import('@/components/TwikooCommentCounter'), { ssr: false }) -const DebugPanel = dynamic(() => import('@/components/DebugPanel'), { ssr: false }) -const ThemeSwitch = dynamic(() => import('@/components/ThemeSwitch'), { ssr: false }) -const Fireworks = dynamic(() => import('@/components/Fireworks'), { ssr: false }) +const TwikooCommentCounter = dynamic( + () => import('@/components/TwikooCommentCounter'), + { ssr: false } +) +const DebugPanel = dynamic(() => import('@/components/DebugPanel'), { + ssr: false +}) +const ThemeSwitch = dynamic(() => import('@/components/ThemeSwitch'), { + ssr: false +}) +const Fireworks = dynamic(() => import('@/components/Fireworks'), { + ssr: false +}) const Nest = dynamic(() => import('@/components/Nest'), { ssr: false }) -const FlutteringRibbon = dynamic(() => import('@/components/FlutteringRibbon'), { ssr: false }) +const FlutteringRibbon = dynamic( + () => import('@/components/FlutteringRibbon'), + { ssr: false } +) const Ribbon = dynamic(() => import('@/components/Ribbon'), { ssr: false }) const Sakura = dynamic(() => import('@/components/Sakura'), { ssr: false }) -const StarrySky = dynamic(() => import('@/components/StarrySky'), { ssr: false }) -const DifyChatbot = dynamic(() => import('@/components/DifyChatbot'), { ssr: false }); -const Analytics = dynamic(() => import('@vercel/analytics/react').then(async (m) => { return m.Analytics }), { ssr: false }) +const StarrySky = dynamic(() => import('@/components/StarrySky'), { + ssr: false +}) +const DifyChatbot = dynamic(() => import('@/components/DifyChatbot'), { + ssr: false +}) +const Analytics = dynamic( + () => + import('@vercel/analytics/react').then(async m => { + return m.Analytics + }), + { ssr: false } +) const MusicPlayer = dynamic(() => import('@/components/Player'), { ssr: false }) const Ackee = dynamic(() => import('@/components/Ackee'), { ssr: false }) const Gtag = dynamic(() => import('@/components/Gtag'), { ssr: false }) const Busuanzi = dynamic(() => import('@/components/Busuanzi'), { ssr: false }) -const GoogleAdsense = dynamic(() => import('@/components/GoogleAdsense'), { ssr: false }) -const Messenger = dynamic(() => import('@/components/FacebookMessenger'), { ssr: false }) +const Messenger = dynamic(() => import('@/components/FacebookMessenger'), { + ssr: false +}) const VConsole = dynamic(() => import('@/components/VConsole'), { ssr: false }) -const CustomContextMenu = dynamic(() => import('@/components/CustomContextMenu'), { ssr: false }) -const DisableCopy = dynamic(() => import('@/components/DisableCopy'), { ssr: false }) -const AdBlockDetect = dynamic(() => import('@/components/AdBlockDetect'), { ssr: false }) -const LoadingProgress = dynamic(() => import('@/components/LoadingProgress'), { ssr: false }) -const AosAnimation = dynamic(() => import('@/components/AOSAnimation'), { ssr: false }) +const CustomContextMenu = dynamic( + () => import('@/components/CustomContextMenu'), + { ssr: false } +) +const DisableCopy = dynamic(() => import('@/components/DisableCopy'), { + ssr: false +}) +const AdBlockDetect = dynamic(() => import('@/components/AdBlockDetect'), { + ssr: false +}) +const LoadingProgress = dynamic(() => import('@/components/LoadingProgress'), { + ssr: false +}) +const AosAnimation = dynamic(() => import('@/components/AOSAnimation'), { + ssr: false +}) /** * 各种插件脚本 * @param {*} props * @returns */ -const ExternalPlugin = (props) => { +const ExternalPlugin = props => { const DISABLE_PLUGIN = siteConfig('DISABLE_PLUGIN') const THEME_SWITCH = siteConfig('THEME_SWITCH') const DEBUG = siteConfig('DEBUG') @@ -55,7 +91,9 @@ const ExternalPlugin = (props) => { const FLUTTERINGRIBBON = siteConfig('FLUTTERINGRIBBON') const COMMENT_TWIKOO_COUNT_ENABLE = siteConfig('COMMENT_TWIKOO_COUNT_ENABLE') const RIBBON = siteConfig('RIBBON') - const CUSTOM_RIGHT_CLICK_CONTEXT_MENU = siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU') + const CUSTOM_RIGHT_CLICK_CONTEXT_MENU = siteConfig( + 'CUSTOM_RIGHT_CLICK_CONTEXT_MENU' + ) const CAN_COPY = siteConfig('CAN_COPY') const WEB_WHIZ_ENABLED = siteConfig('WEB_WHIZ_ENABLED') const AD_WWADS_BLOCK_DETECT = siteConfig('AD_WWADS_BLOCK_DETECT') @@ -113,88 +151,122 @@ const ExternalPlugin = (props) => { } } + useEffect(() => { + if (ADSENSE_GOOGLE_ID) { + setTimeout(() => { + // 异步渲染谷歌广告 + initGoogleAdsense() + }, 1000) + } + }, []) + if (DISABLE_PLUGIN) { return null } - return <> + return ( + <> + {/* 全局样式嵌入 */} + - {/* 全局样式嵌入 */} - + {THEME_SWITCH && } + {DEBUG && } + {ANALYTICS_ACKEE_TRACKER && } + {ANALYTICS_GOOGLE_ID && } + {ANALYTICS_VERCEL && } + {ANALYTICS_BUSUANZI_ENABLE && } + {FACEBOOK_APP_ID && FACEBOOK_PAGE_ID && } + {FIREWORKS && } + {SAKURA && } + {STARRY_SKY && } + {MUSIC_PLAYER && } + {NEST && } + {FLUTTERINGRIBBON && } + {COMMENT_TWIKOO_COUNT_ENABLE && } + {RIBBON && } + {DIFY_CHATBOT_ENABLED && } + {CUSTOM_RIGHT_CLICK_CONTEXT_MENU && } + {!CAN_COPY && } + {WEB_WHIZ_ENABLED && } + {AD_WWADS_BLOCK_DETECT && } + {TIANLI_KEY && } + + + + {ANALYTICS_51LA_ID && ANALYTICS_51LA_CK && } - {THEME_SWITCH && } - {DEBUG && } - {ANALYTICS_ACKEE_TRACKER && } - {ANALYTICS_GOOGLE_ID && } - {ANALYTICS_VERCEL && } - {ANALYTICS_BUSUANZI_ENABLE && } - {ADSENSE_GOOGLE_ID && } - {FACEBOOK_APP_ID && FACEBOOK_PAGE_ID && } - {FIREWORKS && } - {SAKURA && } - {STARRY_SKY && } - {MUSIC_PLAYER && } - {NEST && } - {FLUTTERINGRIBBON && } - {COMMENT_TWIKOO_COUNT_ENABLE && } - {RIBBON && } - {DIFY_CHATBOT_ENABLED && } - {CUSTOM_RIGHT_CLICK_CONTEXT_MENU && } - {!CAN_COPY && } - {WEB_WHIZ_ENABLED && } - {AD_WWADS_BLOCK_DETECT && } - {TIANLI_KEY && } - - - - {ANALYTICS_51LA_ID && ANALYTICS_51LA_CK && } - - {ANALYTICS_51LA_ID && ANALYTICS_51LA_CK && (<> - } + {AD_WWADS_ID && ( + + )} - {COMMENT_TWIKOO_ENV_ID && - - - - - \ No newline at end of file + + diff --git a/public/js/giscus.js b/public/js/giscus.js new file mode 100644 index 00000000..373454c4 --- /dev/null +++ b/public/js/giscus.js @@ -0,0 +1,209 @@ +/* eslint-disable */ +;(function () { + var baseUrl = 'https://giscus.app' + var giscusIframe = null + + // 错误日志 + function handleError(a) { + return '[giscus] An error occurred. Error message: "'.concat(a, '".') + } + // 站点元信息 + function getMetaContent(name, includeProperty) { + void 0 === includeProperty && (includeProperty = !1) + includeProperty = includeProperty + ? "meta[property='og:".concat(name, "'],") + : '' + return (name = document.querySelector( + includeProperty + "meta[name='".concat(name, "']") + )) + ? name.content + : '' + } + + // 渲染 + function render(querySelector) { + // const giscusContainer = document.currentScript + const giscusContainer = document.querySelector(querySelector) + // var k = new URL(m.src).origin + let dataset = new URL(location.href) + let paramsSession = dataset.searchParams.get('giscus') || '' + const localStorageSession = localStorage.getItem('giscus-session') + dataset.searchParams.delete('giscus') + dataset.hash = '' + let url = dataset.toString() + if (paramsSession) + localStorage.setItem('giscus-session', JSON.stringify(paramsSession)), + history.replaceState(void 0, document.title, url) + else if (localStorageSession) { + try { + paramsSession = JSON.parse(localStorageSession) + } catch (a) { + localStorage.removeItem('giscus-session'), + console.warn( + ''.concat( + handleError(a === null || void 0 === a ? void 0 : a.message), + ' Session has been cleared.' + ) + ) + } + } + + dataset = giscusContainer.dataset + var params = {} + params.origin = url + params.session = paramsSession + params.theme = dataset.theme + params.reactionsEnabled = dataset.reactionsEnabled || '1' + params.emitMetadata = dataset.emitMetadata || '0' + params.inputPosition = dataset.inputPosition || 'bottom' + params.repo = dataset.repo + params.repoId = dataset.repoId + params.category = dataset.category || '' + params.categoryId = dataset.categoryId + params.strict = dataset.strict || '0' + params.description = getMetaContent('description', !0) + params.backLink = getMetaContent('giscus:backlink') || url + switch (dataset.mapping) { + case 'url': + params.term = url + break + case 'title': + params.term = document.title + break + case 'og:title': + params.term = getMetaContent('title', !0) + break + case 'specific': + params.term = dataset.term + break + case 'number': + params.number = dataset.term + break + default: + params.term = + location.pathname.length < 2 + ? 'index' + : location.pathname.substring(1).replace(/\.\w+$/, '') + } + const q = + (paramsSession = document.querySelector('.giscus')) && paramsSession.id + q && (params.origin = ''.concat(url, '#').concat(q)) + url = dataset.lang ? '/'.concat(dataset.lang) : '' + url = '' + .concat(baseUrl) + .concat(url, '/widget?') + .concat(new URLSearchParams(params)) + dataset = dataset.loading === 'lazy' ? 'lazy' : void 0 + + // 创建iframe + giscusIframe = document.createElement('iframe') + Object.entries({ + class: 'giscus-frame giscus-frame--loading', + title: 'Comments', + scrolling: 'no', + allow: 'clipboard-write', + src: url, + loading: dataset + }).forEach(function (a) { + const g = a[0] + return (a = a[1]) && giscusIframe.setAttribute(g, a) + }) + giscusIframe.style.opacity = '0' + giscusIframe.addEventListener('load', function () { + giscusIframe.style.removeProperty('opacity') + giscusIframe.classList.remove('giscus-frame--loading') + }) + dataset = + document.getElementById('giscus-css') || document.createElement('link') + dataset.id = 'giscus-css' + dataset.rel = 'stylesheet' + dataset.href = ''.concat(baseUrl, '/default.css') + document.head.prepend(dataset) + if (paramsSession) { + for (; paramsSession.firstChild; ) paramsSession.firstChild.remove() + paramsSession.appendChild(giscusIframe) + } else + (paramsSession = document.createElement('div')), + paramsSession.setAttribute('class', 'giscus'), + paramsSession.appendChild(giscusIframe), + giscusContainer.insertAdjacentElement('afterend', paramsSession) + } + + // 处理接收消息 + function handdleMessage(event) { + if (!giscusIframe) { + return + } + event.origin === baseUrl && + ((event = event.data), + typeof event === 'object' && + event.giscus && + (event.giscus.resizeHeight && + (giscusIframe.style.height = ''.concat( + event.giscus.resizeHeight, + 'px' + )), + event.giscus.signOut + ? (localStorage.removeItem('giscus-session'), + console.log( + '[giscus] User has logged out. Session has been cleared.' + ), + p()) + : event.giscus.error && + ((event = event.giscus.error), + event.includes('Bad credentials') || + event.includes('Invalid state value') || + event.includes('State has expired') + ? localStorage.getItem('giscus-session') !== null + ? (localStorage.removeItem('giscus-session'), + console.warn( + ''.concat(handleError(event), ' Session has been cleared.') + ), + p()) + : localStorageSession || + console.error( + '' + .concat( + handleError(event), + ' No session is stored initially. ' + ) + .concat( + 'Please consider reporting this error at https://github.com/giscus/giscus/issues/new.' + ) + ) + : event.includes('Discussion not found') + ? console.warn( + '[giscus] '.concat( + event, + '. A new discussion will be created if a comment/reaction is submitted.' + ) + ) + : event.includes('API rate limit exceeded') + ? console.warn(handleError(event)) + : console.error( + '' + .concat(handleError(event), ' ') + .concat( + 'Please consider reporting this error at https://github.com/giscus/giscus/issues/new.' + ) + )))) + } + + // 初始化 + function initializeGiscus(querySelector) { + render(querySelector) + window.addEventListener('message', handdleMessage) + } + + // 销毁 + function destroyGiscus() { + giscusIframe?.remove() + giscusIframe = null + } + + // 暴露接口 + window.Giscus = { + init: initializeGiscus, + destroy: destroyGiscus + } +})() diff --git a/styles/nprogress.css b/styles/nprogress.css deleted file mode 100644 index 2b405742..00000000 --- a/styles/nprogress.css +++ /dev/null @@ -1,84 +0,0 @@ -/* Make clicks pass-through */ -#nprogress { - pointer-events: none; -} - -#nprogress .bar { - background: #29d; - - position: fixed; - z-index: 1031; - top: 0; - left: 0; - - width: 100%; - height: 2px; -} - -/* Fancy blur effect */ -#nprogress .peg { - display: block; - position: absolute; - right: 0px; - width: 100px; - height: 100%; - box-shadow: 0 0 10px #29d, 0 0 5px #29d; - opacity: 1; - - -webkit-transform: rotate(3deg) translate(0px, -4px); - -ms-transform: rotate(3deg) translate(0px, -4px); - transform: rotate(3deg) translate(0px, -4px); -} - -/* Remove these to get rid of the spinner */ -#nprogress .spinner { - display: block; - position: fixed; - z-index: 1031; - top: 15px; - right: 15px; -} - -#nprogress .spinner-icon { - width: 18px; - height: 18px; - box-sizing: border-box; - - border: solid 2px transparent; - border-top-color: #29d; - border-left-color: #29d; - border-radius: 50%; - - -webkit-animation: nprogress-spinner 400ms linear infinite; - animation: nprogress-spinner 400ms linear infinite; -} - -.nprogress-custom-parent { - overflow: hidden; - position: relative; -} - -.nprogress-custom-parent #nprogress .spinner, -.nprogress-custom-parent #nprogress .bar { - position: absolute; -} - -@-webkit-keyframes nprogress-spinner { - 0% { - -webkit-transform: rotate(0deg); - } - - 100% { - -webkit-transform: rotate(360deg); - } -} - -@keyframes nprogress-spinner { - 0% { - transform: rotate(0deg); - } - - 100% { - transform: rotate(360deg); - } -} diff --git a/themes/commerce/components/MenuGroupCard.js b/themes/commerce/components/MenuGroupCard.js index 5e4d84a4..99c94626 100644 --- a/themes/commerce/components/MenuGroupCard.js +++ b/themes/commerce/components/MenuGroupCard.js @@ -1,18 +1,35 @@ -import Link from 'next/link' import { useGlobal } from '@/lib/global' +import Link from 'next/link' import CONFIG from '../config' -const MenuGroupCard = (props) => { +const MenuGroupCard = props => { const { postCount, categoryOptions, tagOptions } = props const { locale } = useGlobal() const archiveSlot =
{postCount}
- const categorySlot =
{categoryOptions?.length}
+ const categorySlot = ( +
{categoryOptions?.length}
+ ) const tagSlot =
{tagOptions?.length}
const links = [ - { name: locale.COMMON.ARTICLE, to: '/archive', slot: archiveSlot, show: CONFIG.MENU_ARCHIVE }, - { name: locale.COMMON.CATEGORY, to: '/category', slot: categorySlot, show: CONFIG.MENU_CATEGORY }, - { name: locale.COMMON.TAGS, to: '/tag', slot: tagSlot, show: CONFIG.MENU_TAG } + { + name: locale.COMMON.ARTICLE, + to: '/archive', + slot: archiveSlot, + show: CONFIG.MENU_ARCHIVE + }, + { + name: locale.COMMON.CATEGORY, + to: '/category', + slot: categorySlot, + show: CONFIG.MENU_CATEGORY + }, + { + name: locale.COMMON.TAGS, + to: '/tag', + slot: tagSlot, + show: CONFIG.MENU_TAG + } ] for (let i = 0; i < links.length; i++) { @@ -22,29 +39,31 @@ const MenuGroupCard = (props) => { } return ( - + ) } export default MenuGroupCard diff --git a/themes/commerce/components/MenuItemCollapse.js b/themes/commerce/components/MenuItemCollapse.js index 1ce6d59d..3251b9fb 100644 --- a/themes/commerce/components/MenuItemCollapse.js +++ b/themes/commerce/components/MenuItemCollapse.js @@ -7,7 +7,7 @@ import { useState } from 'react' * @param {*} param0 * @returns */ -export const MenuItemCollapse = (props) => { +export const MenuItemCollapse = props => { const { link } = props const [show, changeShow] = useState(false) const hasSubMenu = link?.subMenus?.length > 0 @@ -26,30 +26,55 @@ export const MenuItemCollapse = (props) => { return null } - return <> -
- {!hasSubMenu && - {link?.icon && }{link?.name} - } - {hasSubMenu &&
- {link?.icon && }{link?.name} - -
} -
+ return ( + <> +
+ {!hasSubMenu && ( + + + {link?.icon && } + {link?.name} + + + )} + {hasSubMenu && ( +
+ + {link?.icon && } + {link?.name} + + +
+ )} +
- {/* 折叠子菜单 */} - {hasSubMenu && - {link.subMenus.map((sLink, index) => { - return
- - {link?.icon && } {sLink.title} - -
- })} -
} + {/* 折叠子菜单 */} + {hasSubMenu && ( + + {link.subMenus.map((sLink, index) => { + return ( +
+ + + {link?.icon && }{' '} + {sLink.title} + + +
+ ) + })} +
+ )} + ) } diff --git a/themes/commerce/components/MenuItemDrop.js b/themes/commerce/components/MenuItemDrop.js index e83f46f7..fabd6c10 100644 --- a/themes/commerce/components/MenuItemDrop.js +++ b/themes/commerce/components/MenuItemDrop.js @@ -11,33 +11,51 @@ export const MenuItemDrop = ({ link }) => { return null } - return
changeShow(true)} onMouseOut={() => changeShow(false)} className='h-full'> + return ( +
changeShow(true)} + onMouseOut={() => changeShow(false)} + className='h-full'> + {!hasSubMenu && ( + + {link?.icon && }
{link?.name}
+ {/* {hasSubMenu && } */} + + )} - {!hasSubMenu && - - {link?.icon && }
{link?.name}
- {/* {hasSubMenu && } */} - } - - {hasSubMenu && <> -
- {link?.icon && }
{link?.name}
- {/* */} -
- } - - {/* 子菜单 */} - {hasSubMenu &&
    - {link.subMenus.map((sLink, index) => { - return
  • - - {link?.icon &&   }{sLink.title} - -
  • - })} -
} + {hasSubMenu && ( + <> +
+ {link?.icon && }
{link?.name}
+ {/* */} +
+ + )} + {/* 子菜单 */} + {hasSubMenu && ( +
    + {link.subMenus.map((sLink, index) => { + return ( +
  • + + + {link?.icon &&   } + {sLink.title} + + +
  • + ) + })} +
+ )}
+ ) } diff --git a/themes/example/components/MenuItemDrop.js b/themes/example/components/MenuItemDrop.js index 73e63ac7..94d70605 100644 --- a/themes/example/components/MenuItemDrop.js +++ b/themes/example/components/MenuItemDrop.js @@ -5,34 +5,48 @@ export const MenuItemDrop = ({ link }) => { const [show, changeShow] = useState(false) const hasSubMenu = link?.subMenus?.length > 0 - return
  • changeShow(true)} onMouseOut={() => changeShow(false)} > + return ( +
  • changeShow(true)} + onMouseOut={() => changeShow(false)}> + {!hasSubMenu && ( +
    + + {link?.icon && } {link?.name} + {hasSubMenu && } + +
    + )} - {!hasSubMenu && -
    - - {link?.icon && } {link?.name} - {hasSubMenu && } + {hasSubMenu && ( +
    + {link?.icon && } {link?.name} + +
    + )} + + {/* 子菜单 */} + {hasSubMenu && ( +
      + {link.subMenus.map((sLink, index) => { + return ( +
    • + + + {link?.icon &&   } + {sLink.title} + -
    - } - - {hasSubMenu && -
    - {link?.icon && } {link?.name} - -
    - } - - {/* 子菜单 */} - {hasSubMenu &&
      - {link.subMenus.map((sLink, index) => { - return
    • - - {link?.icon &&   }{sLink.title} - -
    • - })} -
    } - +
  • + ) + })} + + )} + ) } diff --git a/themes/fukasawa/components/MenuItemCollapse.js b/themes/fukasawa/components/MenuItemCollapse.js index f854c16f..2d36242c 100644 --- a/themes/fukasawa/components/MenuItemCollapse.js +++ b/themes/fukasawa/components/MenuItemCollapse.js @@ -8,7 +8,7 @@ import { useState } from 'react' * @param {*} param0 * @returns */ -export const MenuItemCollapse = (props) => { +export const MenuItemCollapse = props => { const { link } = props const [show, changeShow] = useState(false) const hasSubMenu = link?.subMenus?.length > 0 @@ -21,7 +21,7 @@ export const MenuItemCollapse = (props) => { return null } - const selected = (router.pathname === link.to) || (router.asPath === link.to) + const selected = router.pathname === link.to || router.asPath === link.to const toggleShow = () => { changeShow(!show) @@ -31,32 +31,67 @@ export const MenuItemCollapse = (props) => { changeIsOpen(!isOpen) } - return <> -
    + return ( + <> +
    + {!hasSubMenu && ( + +
    +
    + {link.name} +
    + + )} - {!hasSubMenu && -
    {link.name}
    - } + {hasSubMenu && ( +
    +
    +
    + {link.name} +
    +
    + +
    +
    + )} +
    - {hasSubMenu &&
    -
    {link.name}
    -
    -
    } -
    - - {/* 折叠子菜单 */} - {hasSubMenu && - {link.subMenus.map((sLink, index) => { - return
    - -
    {sLink.title}
    - -
    - })} - } + +
    +
    + {sLink.title} +
    + +
    + ) + })} + + )} + ) } diff --git a/themes/fukasawa/components/MenuItemDrop.js b/themes/fukasawa/components/MenuItemDrop.js index 7a79c5c3..b6224347 100644 --- a/themes/fukasawa/components/MenuItemDrop.js +++ b/themes/fukasawa/components/MenuItemDrop.js @@ -5,34 +5,62 @@ export const MenuItemDrop = ({ link }) => { const [show, changeShow] = useState(false) const hasSubMenu = link?.subMenus?.length > 0 - return
  • changeShow(true)} onMouseOut={() => changeShow(false)} - className='relative py-1 duration-500 justify-between text-gray-500 dark:text-gray-300 hover:text-black hover:underline cursor-pointer flex flex-nowrap items-center '> + return ( +
  • changeShow(true)} + onMouseOut={() => changeShow(false)} + className='relative py-1 duration-500 justify-between text-gray-500 dark:text-gray-300 hover:text-black hover:underline cursor-pointer flex flex-nowrap items-center '> + {!hasSubMenu && ( + +
    +
    + {link.name} +
    + {link.slot} + + )} - {!hasSubMenu && - -
    {link.name}
    - {link.slot} - } - - {hasSubMenu && -
    -
    {link.name}
    - {link.slot} - {hasSubMenu &&
    } -
    } - - {/* 子菜单 */} - {hasSubMenu &&
      - {link?.subMenus?.map((sLink, index) => { - return
    • - - {sLink.icon && } -
      {sLink.name}
      - {sLink.slot} - -
    • - })} -
    } + {hasSubMenu && ( +
    +
    +
    + {link.name} +
    + {link.slot} + {hasSubMenu && ( +
    + +
    + )} +
    + )} + {/* 子菜单 */} + {hasSubMenu && ( +
      + {link?.subMenus?.map((sLink, index) => { + return ( +
    • + + {sLink.icon && ( + + )} +
      {sLink.name}
      + {sLink.slot} + +
    • + ) + })} +
    + )}
  • + ) } diff --git a/themes/game/components/Footer.js b/themes/game/components/Footer.js index 3f90a843..7f894638 100644 --- a/themes/game/components/Footer.js +++ b/themes/game/components/Footer.js @@ -9,8 +9,8 @@ export const Footer = props => { return (