diff --git a/.env.local b/.env.local index 8a0dbf80..cfc0b2cd 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.1.2 +NEXT_PUBLIC_VERSION=4.2.0 # 可在此添加环境变量,去掉最左边的(# )注释即可 diff --git a/blog.config.js b/blog.config.js index 11a7cf52..8f35f94d 100644 --- a/blog.config.js +++ b/blog.config.js @@ -90,6 +90,7 @@ const BLOG = { // END ************网站字体***************** 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_THEME_SWITCH: process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH || true, // 自定义外部脚本,外部样式 CUSTOM_EXTERNAL_JS: [''], // e.g. ['http://xx.com/script.js','http://xx.com/script.js'] @@ -184,13 +185,20 @@ const BLOG = { STARRY_SKY: process.env.NEXT_PUBLIC_STARRY_SKY || false, // 开关 // ********挂件组件相关******** + // AI 文章摘要生成 @see https://docs_s.tianli0.top/ + TianliGPT_CSS: 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', + 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_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 || '', + DIFY_CHATBOT_TOKEN: process.env.NEXT_PUBLIC_DIFY_CHATBOT_TOKEN || '', // 悬浮挂件 WIDGET_PET: process.env.NEXT_PUBLIC_WIDGET_PET || true, // 是否显示宠物挂件 WIDGET_PET_LINK: @@ -236,6 +244,8 @@ const BLOG = { // ********挂件组件相关******** // ----> 评论互动 可同时开启多个支持 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. 只有一个评论组件时是否隐藏切换组件的标签页 + // 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 @@ -342,6 +352,9 @@ const BLOG = { 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是一个十位的英文数字组合 + // <---- 站点统计 // START---->营收相关 diff --git a/components/Artalk.js b/components/Artalk.js index a53f18f7..e44edaab 100644 --- a/components/Artalk.js +++ b/components/Artalk.js @@ -1,11 +1,9 @@ import { siteConfig } from '@/lib/config' import { loadExternalResource } from '@/lib/utils' -// import { loadExternalResource } from '@/lib/utils' import { useEffect } from 'react' /** - * Giscus评论 @see https://giscus.app/zh-CN - * Contribute by @txs https://github.com/txs/NotionNext/commit/1bf7179d0af21fb433e4c7773504f244998678cb + * Artalk 自托管评论系统 @see https://artalk.js.org/ * @returns {JSX.Element} * @constructor */ diff --git a/components/Busuanzi.js b/components/Busuanzi.js index fec41e5f..cbeb54da 100644 --- a/components/Busuanzi.js +++ b/components/Busuanzi.js @@ -2,14 +2,14 @@ import busuanzi from '@/lib/busuanzi' import { useRouter } from 'next/router' import { useGlobal } from '@/lib/global' // import { useRouter } from 'next/router' -import React from 'react' +import { useEffect } from 'react' let path = '' export default function Busuanzi () { const { theme } = useGlobal() - const Router = useRouter() - Router.events.on('routeChangeComplete', (url, option) => { + const router = useRouter() + router.events.on('routeChangeComplete', (url, option) => { if (url !== path) { path = url busuanzi.fetch() @@ -17,7 +17,7 @@ export default function Busuanzi () { }) // 更换主题时更新 - React.useEffect(() => { + useEffect(() => { if (theme) { busuanzi.fetch() } diff --git a/components/CustomContextMenu.js b/components/CustomContextMenu.js index 3a6d2d4a..bf396d39 100644 --- a/components/CustomContextMenu.js +++ b/components/CustomContextMenu.js @@ -162,10 +162,12 @@ export default function CustomContextMenu(props) { {isDarkMode ? : }
{isDarkMode ? locale.MENU.LIGHT_MODE : locale.MENU.DARK_MODE}
+ {siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH') && (
{locale.MENU.THEME_SWITCH}
+ )} diff --git a/components/DifyChatbot.js b/components/DifyChatbot.js new file mode 100644 index 00000000..c954a872 --- /dev/null +++ b/components/DifyChatbot.js @@ -0,0 +1,32 @@ +import { useEffect } from 'react'; +import { siteConfig } from '@/lib/config'; + +export default function DifyChatbot() { + useEffect(() => { + // 这里使用 siteConfig() 函数调用来获取配置值 + if (!siteConfig('DIFY_CHATBOT_ENABLED')) { + return; + } + + // 配置 DifyChatbot,同样需要调用 siteConfig() 获取相应的配置值 + window.difyChatbotConfig = { + token: siteConfig('DIFY_CHATBOT_TOKEN'), + baseUrl: siteConfig('DIFY_CHATBOT_BASE_URL') + }; + + // 加载 DifyChatbot 脚本 + const script = document.createElement('script'); + script.src = `${siteConfig('DIFY_CHATBOT_BASE_URL')}/embed.min.js`; // 注意调用 siteConfig() + script.id = siteConfig('DIFY_CHATBOT_TOKEN'); // 注意调用 siteConfig() + script.defer = true; + document.body.appendChild(script); + + return () => { + // 在组件卸载时清理 script 标签 + const existingScript = document.getElementById(siteConfig('DIFY_CHATBOT_TOKEN')); // 注意调用 siteConfig() + if (existingScript) document.body.removeChild(existingScript); + }; + }, []); // 注意依赖数组为空,意味着脚本将仅在加载页面时执行一次 + + return null; +} diff --git a/components/ExternalPlugins.js b/components/ExternalPlugins.js index 260e66b8..768cc384 100644 --- a/components/ExternalPlugins.js +++ b/components/ExternalPlugins.js @@ -2,6 +2,11 @@ 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 { CUSTOM_EXTERNAL_CSS, CUSTOM_EXTERNAL_JS, IMG_SHADOW } from '@/blog.config' +import { isBrowser, loadExternalResource } from '@/lib/utils' const TwikooCommentCounter = dynamic(() => import('@/components/TwikooCommentCounter'), { ssr: false }) const DebugPanel = dynamic(() => import('@/components/DebugPanel'), { ssr: false }) @@ -12,6 +17,7 @@ const FlutteringRibbon = dynamic(() => import('@/components/FlutteringRibbon'), 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 MusicPlayer = dynamic(() => import('@/components/Player'), { ssr: false }) const Ackee = dynamic(() => import('@/components/Ackee'), { ssr: false }) @@ -69,12 +75,47 @@ const ExternalPlugin = (props) => { const MATOMO_SITE_ID = siteConfig('MATOMO_SITE_ID') const ANALYTICS_51LA_ID = siteConfig('ANALYTICS_51LA_ID') const ANALYTICS_51LA_CK = siteConfig('ANALYTICS_51LA_CK') + const DIFY_CHATBOT_ENABLED = siteConfig('DIFY_CHATBOT_ENABLED') + const TIANLI_KEY = siteConfig('TianliGPT_KEY') + const GLOBAL_JS = siteConfig('GLOBAL_JS') + const CLARITY_ID = siteConfig('CLARITY_ID') + + // 自定义样式css和js引入 + if (isBrowser) { + // 初始化AOS动画 + // 静态导入本地自定义样式 + loadExternalResource('/css/custom.css', 'css') + loadExternalResource('/js/custom.js', 'js') + + // 自动添加图片阴影 + if (IMG_SHADOW) { + loadExternalResource('/css/img-shadow.css', 'css') + } + + // 导入外部自定义脚本 + if (CUSTOM_EXTERNAL_JS && CUSTOM_EXTERNAL_JS.length > 0) { + for (const url of CUSTOM_EXTERNAL_JS) { + loadExternalResource(url, 'js') + } + } + + // 导入外部自定义样式 + if (CUSTOM_EXTERNAL_CSS && CUSTOM_EXTERNAL_CSS.length > 0) { + for (const url of CUSTOM_EXTERNAL_CSS) { + loadExternalResource(url, 'css') + } + } + } if (DISABLE_PLUGIN) { return null } return <> + + {/* 全局样式嵌入 */} + + {THEME_SWITCH && } {DEBUG && } {ANALYTICS_ACKEE_TRACKER && } @@ -91,10 +132,12 @@ const ExternalPlugin = (props) => { {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 && } @@ -109,6 +152,11 @@ const ExternalPlugin = (props) => { }} /> */} )} + {/* 注入JS脚本 */} + {GLOBAL_JS &&