diff --git a/.env.local b/.env.local index 5c68a5c9..fd53e2f4 100644 --- a/.env.local +++ b/.env.local @@ -1,2 +1,2 @@ # 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables -NEXT_PUBLIC_VERSION=3.12.4 +NEXT_PUBLIC_VERSION=3.13.4 \ No newline at end of file diff --git a/README.md b/README.md index 87a96423..dd0aa30e 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,12 @@ ## 我要如何开始? -只需几分钟即可搭建您的个人站点,欢迎移步[我的博客](https://tangly1024.com/article/notion-next) 查看教程 +只需几分钟即可搭建您的个人站点,查看教程 [教程说明](https://tangly1024.com/article/notion-next) ## 致谢 感谢Craig Hart发起的Nobelium项目 +
Craig Hart
Craig Hart
@@ -41,62 +42,123 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + +
tangly1024
tangly1024

🎫 🔧 🎨 🐛
+ tangly1024
tangly1024

🎫 🔧 🐛 +
uWayLu
uWayLu

🔧 🐛
+ uWayLu
uWayLu

🔧 🐛 +
txs
txs

🔧 🐛
+ txs
txs

🔧 🐛 +
yuzhanglong
yuzhanglong

🔧 🐛
+ yuzhanglong
yuzhanglong

🔧 🐛 +
Hscpro
Hscpro

🔧 🐛
+ Hscpro
Hscpro

🔧 🐛 +
JensonMiao
JensonMiao

🔧 🐛
+ JensonMiao
JensonMiao

🔧 🐛 +
haixin1225
haixin1225

🔧 🐛
+ haixin1225
haixin1225

🔧 🐛 +
mouyase
mouyase

🔧 🐛
+ mouyase
mouyase

🔧 🐛 +
qfdk
qfdk

🔧 🐛
+ qfdk
qfdk

🔧 🐛 +
ifyz
ifyz

🔧 🐛
+ ifyz
ifyz

🔧 🐛 +
SwwweetOrange
SwwweetOrange

🔧 🐛
+ Liqun Zhao
Liqun Zhao

🔧 🐛 +
Ylarod
Ylarod

🔧 🐛
+ Ylarod
Ylarod

🔧 🐛 +
Etherrreal.
Etherrreal.

🔧 🐛
+ Etherrreal.
Etherrreal.

🔧 🐛 +
Joshua Astray
Joshua Astray

🔧 🐛
+ Joshua Astray
Joshua Astray

🔧 🐛 +
Vixcity
Vixcity

🔧 🐛
+ Vixcity
Vixcity

🔧 🐛 +
ipatpat
ipatpat

🔧 🐛
+ ipatpat
ipatpat

🔧 🐛 +
xloong
xloong

🔧 🐛
+ xloong
xloong

🔧 🐛 +
expoli
expoli

🔧 🐛
+ expoli
expoli

🔧 🐛 +
SuperHuangXu
bUBBLE

🔧 🐛
+ SuperHuangXu
bUBBLE

🔧 🐛 +
Pylogmon
派了个萌

🔧 🐛
+ Pylogmon
派了个萌

🔧 🐛 +
SkysCrystal
Simon Shi

🔧 🐛
+ SkysCrystal
Simon Shi

🔧 🐛 +
S.Y. Lee
S.Y. Lee

🔧 🐛
+ S.Y. Lee
S.Y. Lee

🔧 🐛 +
fighting-buf
fighting-buf

🔧 🐛
+ fighting-buf
fighting-buf

🔧 🐛 +
+ cliouo
cliouo

🔧 🐛 +
+ Sude Akgün
Sude Akgün

🔧 🐛 +
+ Ray
Ray

🔧 🐛 +
+ Hongzzz
Hongzzz

🔧 🐛 +
+ ## 引用技术 - **框架**: [Next.js](https://nextjs.org) -- **样式**: [Tailwind CSS](https://www.tailwindcss.cn/) 和 `@tailwindcss/jit` compiler +- **样式**: [Tailwind CSS](https://www.tailwindcss.cn/) - **渲染**: [React-notion-x](https://github.com/NotionX/react-notion-x) -- **评论**: [Giscus](https://giscus.app/zh-CN), [Gitalk](https://gitalk.github.io), [Cusdis](https://cusdis.com), [Utterances](https://utteranc.es) +- **评论**: [Twikoo](https://github.com/imaegoo/twikoo), [Giscus](https://giscus.app/zh-CN), [Gitalk](https://gitalk.github.io), [Cusdis](https://cusdis.com), [Utterances](https://utteranc.es) - **图标**: [Fontawesome](https://fontawesome.com/v6/icons/) diff --git a/blog.config.js b/blog.config.js index 50084390..999ecb77 100644 --- a/blog.config.js +++ b/blog.config.js @@ -1,7 +1,8 @@ // 注: process.env.XX是Vercel的环境变量,配置方式见:https://docs.tangly1024.com/zh/features/personality const BLOG = { // Important page_id!!!Duplicate Template from https://www.notion.so/tanghh/02ab3b8678004aa69e9e415905ef32a5 - NOTION_PAGE_ID: process.env.NOTION_PAGE_ID || 'fb7bf0cd0563410e862e5ee67b8a8d33', + NOTION_PAGE_ID: + process.env.NOTION_PAGE_ID || 'fb7bf0cd0563410e862e5ee67b8a8d33', PSEUDO_STATIC: false, // 伪静态路径,开启后所有文章URL都以 .html 结尾。 NEXT_REVALIDATE_SECOND: process.env.NEXT_PUBLIC_REVALIDATE_SECOND || 5, // 更新内容缓存间隔 单位(秒);即每个页面有5秒的纯静态期、此期间无论多少次访问都不会抓取notion数据;调大该值有助于节省Vercel资源、同时提升访问速率,但也会使文章更新有延迟。 THEME: process.env.NEXT_PUBLIC_THEME || 'hexo', // 主题, 支持 ['next','hexo',"fukasawa','medium','example'] @see https://preview.tangly1024.com @@ -9,7 +10,7 @@ const BLOG = { LANG: process.env.NEXT_PUBLIC_LANG || 'zh-CN', // e.g 'zh-CN','en-US' see /lib/lang.js for more. SINCE: 2022, // e.g if leave this empty, current year will be used. APPEARANCE: process.env.NEXT_PUBLIC_APPEARANCE || 'auto', // ['light', 'dark', 'auto'], // light 日间模式 , dark夜间模式, auto根据时间和主题自动夜间模式 - + APPEARANCE_DARK_TIME: process.env.NEXT_PUBLIC_APPEARANCE_DARK_TIME || [18, 6], // 夜间模式起至时间,false时关闭根据时间自动切换夜间模式 CUSTOM_MENU: process.env.NEXT_PUBLIC_CUSTOM_MENU || false, // 支持Menu 类型,从3.12.0版本起,各主题将逐步支持灵活的二级菜单配置,替代了原来的Page类型,此配置是试验功能、默认关闭。 AUTHOR: process.env.NEXT_PUBLIC_AUTHOR || 'Vixcity', // 您的昵称 例如 tangly1024 @@ -26,19 +27,44 @@ const BLOG = { // 网站字体 FONT_STYLE: process.env.NEXT_PUBLIC_FONT_STYLE || 'font-serif', // ['font-serif','font-sans'] 两种可选,分别是衬线和无衬线: 参考 https://www.jianshu.com/p/55e410bd2115 - FONT_URL: [// 字体CSS 例如 https://npm.elemecdn.com/lxgw-wenkai-webfont@1.6.0/style.css + FONT_URL: [ + // 字体CSS 例如 https://npm.elemecdn.com/lxgw-wenkai-webfont@1.6.0/style.css 'https://fonts.googleapis.com/css?family=Bitter&display=swap', - 'https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@500&display=swap', - 'https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@500&display=swap' + 'https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300&display=swap', + 'https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@300&display=swap' + ], + FONT_SANS: [ + // 无衬线字体 例如'LXGW WenKai' + 'Bitter', + '"PingFang SC"', + '-apple-system', + 'BlinkMacSystemFont', + '"Hiragino Sans GB"', + '"Segoe UI Emoji"', + '"Segoe UI Symbol"', + '"Segoe UI"', + '"Noto Sans SC"', + 'HarmonyOS_Regular', + '"Microsoft YaHei"', + '"Helvetica Neue"', + 'Helvetica', + '"Source Han Sans SC"', + 'Arial', + 'sans-serif', + '"Apple Color Emoji"' + ], + FONT_SERIF: [ + // 衬线字体 例如'LXGW WenKai' + 'Bitter', + '"Noto Serif SC"', + 'SimSun', + '"Times New Roman"', + 'Times', + 'serif', + '"Segoe UI Emoji"', + '"Segoe UI Symbol"', + '"Apple Color Emoji"' ], - FONT_SANS: [// 无衬线字体 例如'LXGW WenKai' - 'Bitter', '"PingFang SC"', '-apple-system', 'BlinkMacSystemFont', '"Hiragino Sans GB"', - '"Segoe UI Emoji"', '"Segoe UI Symbol"', '"Segoe UI"', '"Noto Sans SC"', 'HarmonyOS_Regular', - '"Microsoft YaHei"', '"Helvetica Neue"', 'Helvetica', '"Source Han Sans SC"', - 'Arial', 'sans-serif', '"Apple Color Emoji"'], - FONT_SERIF: [// 衬线字体 例如'LXGW WenKai' - 'Bitter', '"Noto Serif SC"', 'SimSun', '"Times New Roman"', 'Times', 'serif', - '"Segoe UI Emoji"', '"Segoe UI Symbol"', '"Apple Color Emoji"'], FONT_AWESOME: '/css/all.min.css', // font-awesome 字体图标地址 // 自定义外部脚本,外部样式 @@ -57,9 +83,11 @@ const BLOG = { BEI_AN: process.env.NEXT_PUBLIC_BEI_AN || '', // 备案号 闽ICP备XXXXXXX // PrismJs 代码相关 - 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', PRISM_JS_PATH: 'https://npm.elemecdn.com/prismjs@1.29.0/components/', - PRISM_THEME_PATH: 'https://npm.elemecdn.com/prism-themes/themes/prism-a11y-dark.min.css', // 代码样式主题 更多参考 https://github.com/PrismJS/prism-themes + PRISM_THEME_PATH: + 'https://npm.elemecdn.com/prism-themes/themes/prism-a11y-dark.min.css', // 代码样式主题 更多参考 https://github.com/PrismJS/prism-themes CODE_MAC_BAR: true, // 代码左上角显示mac的红黄绿图标 CODE_LINE_NUMBERS: process.env.NEXT_PUBLIC_CODE_LINE_NUMBERS || 'false', // 是否显示行号 @@ -86,7 +114,12 @@ const BLOG = { // 鼠标点击烟花特效 FIREWORKS: process.env.NEXT_PUBLIC_FIREWORKS || true, // 开关 // 烟花色彩,感谢 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 || true, // 开关 @@ -104,7 +137,10 @@ const BLOG = { // 悬浮挂件 WIDGET_PET: process.env.NEXT_PUBLIC_WIDGET_PET || true, // 是否显示宠物挂件 - WIDGET_PET_LINK: process.env.NEXT_PUBLIC_WIDGET_PET_LINK || 'https://cdn.jsdelivr.net/npm/live2d-widget-model-unitychan@1.0.5/assets/unitychan.model.json', // 挂件模型地址 @see https://github.com/xiazeyu/live2d-widget-models + WIDGET_PET_LINK: + process.env.NEXT_PUBLIC_WIDGET_PET_LINK || + 'https://cdn.jsdelivr.net/npm/live2d-widget-model-unitychan@1.0.5/assets/unitychan.model.json', // 挂件模型地址 @see https://github.com/xiazeyu/live2d-widget-models + WIDGET_PET_SWITCH_THEME: false, // 点击宠物挂件切换博客主题 // 好看的主题 // https://cdn.jsdelivr.net/npm/live2d-widget-model-ni-j@1.0.5/assets/ni-j.model.json // https://cdn.jsdelivr.net/npm/live2d-widget-model-nipsilon@1.0.5/assets/nipsilon.model.json @@ -113,33 +149,41 @@ const BLOG = { // https://cdn.jsdelivr.net/npm/live2d-widget-model-unitychan@1.0.5/assets/unitychan.model.json // https://cdn.jsdelivr.net/npm/live2d-widget-model-koharu@1.0.5/assets/koharu.model.json // https://cdn.jsdelivr.net/npm/live2d-widget-model-haruto@1.0.5/assets/haruto.model.json - WIDGET_PET_SWITCH_THEME: false, // 点击宠物挂件切换博客主题 // 音乐播放插件 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_SHOW_LRC: process.env.NEXT_PUBLIC_MUSIC_PLAYER_SHOW_LRC || false, // 是否展示歌词(前提是有配置歌词路径,对 meting 无效) - MUSIC_PLAYER_CDN_URL: process.env.NEXT_PUBLIC_MUSIC_PLAYER_CDN_URL || 'https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/aplayer/1.10.1/APlayer.min.js', + 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 || + 'https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/aplayer/1.10.1/APlayer.min.js', MUSIC_PLAYER_ORDER: process.env.NEXT_PUBLIC_MUSIC_PLAYER_ORDER || 'list', // 默认播放方式,顺序 list,随机 random - MUSIC_PLAYER_AUDIO_LIST: [ // 示例音乐列表。除了以下配置外,还可配置歌词,具体配置项看此文档 https://aplayer.js.org/#/zh-Hans/ + MUSIC_PLAYER_AUDIO_LIST: [ + // 示例音乐列表。除了以下配置外,还可配置歌词,具体配置项看此文档 https://aplayer.js.org/#/zh-Hans/ { 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 @@ -147,30 +191,43 @@ const BLOG = { COMMENT_TWIKOO_ENV_ID: process.env.NEXT_PUBLIC_COMMENT_ENV_ID || '', // TWIKOO地址 腾讯云环境填 envId;Vercel 环境域名地址(https://xxx.vercel.app) // 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 || 'https://cusdis.com/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 || + 'https://cusdis.com/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_GITTER_ROOM: process.env.NEXT_PUBLIC_COMMENT_GITTER_ROOM || '', // gitter聊天室 see https://gitter.im/ 不需要则留空 @@ -180,11 +237,27 @@ const BLOG = { 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, // 最新评论 + // 此评论系统基于WebMention,细节可参考https://webmention.io + // 它是一个基于IndieWeb理念的开放式评论系统,下方COMMENT_WEBMENTION包含的属性皆需配置: + // ENABLE: 是否开启 + // AUTH: Webmention使用的IndieLogin,可使用Twitter或Github个人页面连结 + // HOSTNAME: Webmention绑定之网域,通常即为本站网址 + // TWITTER_USERNAME: 评论显示区域需要的资讯 + // TOKEN: Webmention的API token + COMMENT_WEBMENTION: { + ENABLE: process.env.NEXT_PUBLIC_WEBMENTION_ENABLE || false, + AUTH: process.env.NEXT_PUBLIC_WEBMENTION_AUTH || '', + HOSTNAME: process.env.NEXT_PUBLIC_WEBMENTION_HOSTNAME || '', + TWITTER_USERNAME: process.env.NEXT_PUBLIC_TWITTER_USERNAME || '', + TOKEN: process.env.NEXT_PUBLIC_WEBMENTION_TOKEN || '' + }, + // <---- 评论插件 // ----> 站点统计 @@ -193,11 +266,15 @@ const BLOG = { 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 - ANALYTICS_ACKEE_TRACKER: process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_TRACKER || '', // e.g 'https://ackee.tangly1024.net/tracker.js' - ANALYTICS_ACKEE_DATA_SERVER: process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_DATA_SERVER || '', // e.g https://ackee.tangly1024.net , don't end with a slash - ANALYTICS_ACKEE_DOMAIN_ID: process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_DOMAIN_ID || '', // e.g '0e2257a8-54d4-4847-91a1-0311ea48cc7b' + ANALYTICS_ACKEE_TRACKER: + process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_TRACKER || '', // e.g 'https://ackee.tangly1024.net/tracker.js' + ANALYTICS_ACKEE_DATA_SERVER: + process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_DATA_SERVER || '', // e.g https://ackee.tangly1024.net , don't end with a slash + ANALYTICS_ACKEE_DOMAIN_ID: + process.env.NEXT_PUBLIC_ANALYTICS_ACKEE_DOMAIN_ID || '', // e.g '0e2257a8-54d4-4847-91a1-0311ea48cc7b' - 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 // <---- 站点统计 @@ -210,11 +287,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状态值与此相同时为隐藏发布,可以为中文 , 除此之外其他页面状态不会显示在博客上 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', @@ -229,11 +312,13 @@ const BLOG = { // 作废配置 AVATAR: process.env.NEXT_PUBLIC_AVATAR || '/avatar.svg', // 作者头像,被notion中的ICON覆盖。若无ICON则取public目录下的avatar.png TITLE: process.env.NEXT_PUBLIC_TITLE || 'VIXCITY 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 || '我的小破博客', // 站点描述,被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 || '我的小破博客', // 站点描述,被notion中的页面描述覆盖 // 网站图片 - IMG_URL_TYPE: process.env.NEXT_PUBLIC_IMG_TYPE || 'Notion', // ['Notion','AMAZON'] 站点图片前缀 默认 Notion:(https://notion.so/images/xx) , AMAZON(https://s3.us-west-2.amazonaws.com/xxx) + IMG_URL_TYPE: process.env.NEXT_PUBLIC_IMG_TYPE || 'Notion', // 此配置已失效,请勿使用;AMAZON方案不再支持,仅支持Notion方案。 ['Notion','AMAZON'] 站点图片前缀 默认 Notion:(https://notion.so/images/xx) , AMAZON(https://s3.us-west-2.amazonaws.com/xxx) IMG_SHADOW: process.env.NEXT_PUBLIC_IMG_SHADOW || false, // 文章图片是否自动添加阴影 // 开发相关 diff --git a/components/Collapse.js b/components/Collapse.js index a787bfa2..99629604 100644 --- a/components/Collapse.js +++ b/components/Collapse.js @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useEffect, useImperativeHandle } from 'react' /** * 折叠面板组件,支持水平折叠、垂直折叠 @@ -6,12 +6,27 @@ import React from 'react' * @returns */ const Collapse = props => { - const collapseRef = React.useRef(null) + const { collapseRef } = props + const ref = React.useRef(null) const type = props.type || 'vertical' + + useImperativeHandle(collapseRef, () => { + return { + /** + * 当子元素高度变化时,可调用此方法更新折叠组件的高度 + * @param {*} param0 + */ + updateCollapseHeight: ({ height, increase }) => { + ref.current.style.height = ref.current.scrollHeight + ref.current.style.height = 'auto' + } + } + }) + /** - * 折叠 - * @param {*} element - */ + * 折叠 + * @param {*} element + */ const collapseSection = element => { const sectionHeight = element.scrollHeight const sectionWidth = element.scrollWidth @@ -34,9 +49,9 @@ const Collapse = props => { } /** - * 展开 - * @param {*} element - */ + * 展开 + * @param {*} element + */ const expandSection = element => { const sectionHeight = element.scrollHeight const sectionWidth = element.scrollWidth @@ -58,22 +73,20 @@ const Collapse = props => { clearTimeout(clearTime) } - const updateHeight = () => { - collapseRef.current.style.height = 'auto' - } - - React.useEffect(() => { + useEffect(() => { if (props.isOpen) { - expandSection(collapseRef.current) + expandSection(ref.current) } else { - collapseSection(collapseRef.current) + collapseSection(ref.current) } + // 通知父组件高度变化 + props?.onHeightChange && props.onHeightChange({ height: ref.current.scrollHeight, increase: props.isOpen }) }, [props.isOpen]) return ( -
- {props.children} -
+
+ {props.children} +
) } Collapse.defaultProps = { isOpen: false } diff --git a/components/Comment.js b/components/Comment.js index 570d122d..e1b1f6bb 100644 --- a/components/Comment.js +++ b/components/Comment.js @@ -43,6 +43,12 @@ const GiscusComponent = dynamic( }, { ssr: false } ) +const WebMentionComponent = dynamic( + () => { + return import('@/components/WebMention') + }, + { ssr: false } +) const ValineComponent = dynamic(() => import('@/components/ValineComponent'), { ssr: false @@ -100,6 +106,10 @@ const Comment = ({ frontMatter }) => { {BLOG.COMMENT_GITALK_CLIENT_ID && (
)} + + {BLOG.COMMENT_WEBMENTION.ENABLE && (
+ +
)} ) diff --git a/components/CommonHead.js b/components/CommonHead.js index 0f4e0555..8104ea80 100644 --- a/components/CommonHead.js +++ b/components/CommonHead.js @@ -44,6 +44,16 @@ const CommonHead = ({ meta, children }) => { + {BLOG.COMMENT_WEBMENTION.ENABLE && ( + <> + + + + )} + {BLOG.COMMENT_WEBMENTION.ENABLE && BLOG.COMMENT_WEBMENTION.AUTH !== '' && ( + + )} + {JSON.parse(BLOG.ANALYTICS_BUSUANZI_ENABLE) && } {meta?.type === 'Post' && ( <> diff --git a/components/DarkModeButton.js b/components/DarkModeButton.js index 869a36b3..f324ea5e 100644 --- a/components/DarkModeButton.js +++ b/components/DarkModeButton.js @@ -13,7 +13,7 @@ const DarkModeButton = (props) => { htmlElement.classList?.add(newStatus ? 'dark' : 'light') } - return
+ return
diff --git a/components/FlutteringRibbon.js b/components/FlutteringRibbon.js index a615d533..301fbd23 100644 --- a/components/FlutteringRibbon.js +++ b/components/FlutteringRibbon.js @@ -1,10 +1,21 @@ /* eslint-disable */ import React from 'react' - +const id = 'canvasFlutteringRibbon' export const FlutteringRibbon = () => { + const destroyRibbon = ()=>{ + const ribbon = document.getElementById(id) + if(ribbon && ribbon.parentNode){ + ribbon.parentNode.removeChild(ribbon) + } + } + React.useEffect(() => { createFlutteringRibbon() + return () => destroyRibbon() + }, []) + return <> + } /** @@ -125,6 +136,7 @@ function createFlutteringRibbon() { init: function () { try { ;(this._canvas = document.createElement('canvas')), + (this._canvas.id = id), (this._canvas.style.display = 'block'), (this._canvas.style.position = 'fixed'), (this._canvas.style.margin = '0'), diff --git a/components/Nest.js b/components/Nest.js index 781cb2bf..74fa85e3 100644 --- a/components/Nest.js +++ b/components/Nest.js @@ -1,10 +1,19 @@ /* eslint-disable */ -import React from 'react' - +import { useEffect } from 'react' +const id = 'canvasNestCreated' export const Nest = () => { - React.useEffect(() => { + const destroyNest = ()=>{ + const nest = document.getElementById(id) + if(nest && nest.parentNode){ + nest.parentNode.removeChild(nest) + } + } + + useEffect(() => { createNest() + return () => destroyNest() }, []) + return <> } /** @@ -65,7 +74,7 @@ function createNest() { m(o) } var i = document.createElement('canvas') - i.id = 'canvasNestCreated' + i.id = id var a = (function () { const t = e return { diff --git a/components/NotionIcon.js b/components/NotionIcon.js index d086fee0..79d1b270 100644 --- a/components/NotionIcon.js +++ b/components/NotionIcon.js @@ -8,10 +8,10 @@ const NotionIcon = ({ icon }) => { return <> } - if (icon.startsWith('http')) { + if (icon.startsWith('http') || icon.startsWith('data:')) { // return // eslint-disable-next-line @next/next/no-img-element - return + return } return {icon} diff --git a/components/NotionPage.js b/components/NotionPage.js index abb8586e..85b5573e 100644 --- a/components/NotionPage.js +++ b/components/NotionPage.js @@ -1,7 +1,7 @@ import { NotionRenderer } from 'react-notion-x' import dynamic from 'next/dynamic' -import mediumZoom from '@fisch0920/medium-zoom' -import React from 'react' +// import mediumZoom from '@fisch0920/medium-zoom' +import React, { useEffect } from 'react' import { isBrowser } from '@/lib/utils' import { Code } from 'react-notion-x/build/third-party/code' import TweetEmbed from 'react-tweet-embed' @@ -42,16 +42,16 @@ const Tweet = ({ id }) => { } const NotionPage = ({ post, className }) => { - const zoom = isBrowser() && mediumZoom({ - container: '.notion-viewport', - background: 'rgba(0, 0, 0, 0.2)', - scrollOffset: 200, - margin: getMediumZoomMargin() - }) +// const zoom = isBrowser() && mediumZoom({ +// container: '.notion-viewport', +// background: 'rgba(0, 0, 0, 0.2)', +// scrollOffset: 200, +// margin: getMediumZoomMargin() +// }) - const zoomRef = React.useRef(zoom ? zoom.clone() : null) + // const zoomRef = React.useRef(zoom ? zoom.clone() : null) - React.useEffect(() => { + useEffect(() => { setTimeout(() => { if (window.location.hash) { const tocNode = document.getElementById(window.location.hash.substring(1)) @@ -64,18 +64,18 @@ const NotionPage = ({ post, className }) => { setTimeout(() => { if (isBrowser()) { // 将相册gallery下的图片加入放大功能 - const imgList = document.querySelectorAll('.notion-collection-card-cover img') - if (imgList && zoomRef.current) { - for (let i = 0; i < imgList.length; i++) { - (zoomRef.current).attach(imgList[i]) - } - } + // const imgList = document.querySelectorAll('.notion-collection-card-cover img') + // if (imgList && zoomRef.current) { + // for (let i = 0; i < imgList.length; i++) { + // (zoomRef.current).attach(imgList[i]) + // } + // } - // 相册图片点击不跳转 - const cards = document.getElementsByClassName('notion-collection-card') - for (const e of cards) { - e.removeAttribute('href') - } + // 相册图片禁止跳转页面,改为放大图片功能功能 + // const cards = document.getElementsByClassName('notion-collection-card') + // for (const e of cards) { + // e.removeAttribute('href') + // } } }, 800) }, []) @@ -84,7 +84,7 @@ const NotionPage = ({ post, className }) => { return <>{post?.summary || ''} } - return
+ return
{ return '/' + id.replace(/-/g, '') } -function getMediumZoomMargin() { - const width = window.innerWidth +// function getMediumZoomMargin() { +// const width = window.innerWidth - if (width < 500) { - return 8 - } else if (width < 800) { - return 20 - } else if (width < 1280) { - return 30 - } else if (width < 1600) { - return 40 - } else if (width < 1920) { - return 48 - } else { - return 72 - } -} +// if (width < 500) { +// return 8 +// } else if (width < 800) { +// return 20 +// } else if (width < 1280) { +// return 30 +// } else if (width < 1600) { +// return 40 +// } else if (width < 1920) { +// return 48 +// } else { +// return 72 +// } +// } export default NotionPage diff --git a/components/Player.js b/components/Player.js index ec0ea461..98da72c3 100644 --- a/components/Player.js +++ b/components/Player.js @@ -5,7 +5,7 @@ const Player = () => { const [player, setPlayer] = React.useState() const ref = React.useRef(null) - const showLrc = JSON.parse(BLOG.MUSIC_PLAYER_SHOW_LRC) + const lrcType = JSON.parse(BLOG.MUSIC_PLAYER_LRC_TYPE) const playerVisible = JSON.parse(BLOG.MUSIC_PLAYER_VISIBLE) const autoPlay = JSON.parse(BLOG.MUSIC_PLAYER_AUTO_PLAY) @@ -16,7 +16,7 @@ const Player = () => { setPlayer(new window.APlayer({ container: ref.current, fixed: true, - showlrc: showLrc, + lrcType: lrcType, autoplay: autoPlay, order: BLOG.MUSIC_PLAYER_ORDER, audio: BLOG.MUSIC_PLAYER_AUDIO_LIST diff --git a/components/Ribbon.js b/components/Ribbon.js index d96e3591..2c6855fc 100644 --- a/components/Ribbon.js +++ b/components/Ribbon.js @@ -1,10 +1,20 @@ /* eslint-disable */ -import React from 'react' +import { useEffect } from 'react' +const id = 'canvasRibbon' export const Ribbon = () => { - React.useEffect(() => { + const destroyRibbon = ()=>{ + const ribbon = document.getElementById(id) + if(ribbon && ribbon.parentNode){ + ribbon.parentNode.removeChild(ribbon) + } + } + + useEffect(() => { createRibbon() + return () => destroyRibbon() }, []) + return <> } /** @@ -29,6 +39,7 @@ function createRibbon() { a = window.innerWidth, l = window.innerHeight, d = e.s + i.id= id let r, s const u = Math let h = 0 diff --git a/components/Sakura.js b/components/Sakura.js index 3f69cc25..7898b3cc 100644 --- a/components/Sakura.js +++ b/components/Sakura.js @@ -1,10 +1,19 @@ /* eslint-disable */ -import React from 'react' - +import { useEffect } from 'react' +const id = 'canvas_sakura' export const Sakura = () => { - React.useEffect(() => { + const destroySakura = ()=>{ + const sakura = document.getElementById(id) + if(sakura && sakura.parentNode){ + sakura.parentNode.removeChild(sakura) + } + } + + useEffect(() => { createSakura({}) + return () => destroySakura() }, []) + return <> } /** @@ -129,7 +138,7 @@ function createSakura() { 'style', 'position: fixed;left: 0;top: 0;pointer-events: none;' ) - canvas.setAttribute('id', 'canvas_sakura') + canvas.setAttribute('id', id) document.getElementsByTagName('body')[0].appendChild(canvas) cxt = canvas.getContext('2d') var sakuraList = new SakuraList() @@ -165,15 +174,12 @@ function createSakura() { stop = requestAnimationFrame(asd) } } - window.onresize = function () { - var canvasSnow = document.getElementById('canvas_snow') - } img.onload = function () { startSakura() } function stopp() { if (staticx) { - var child = document.getElementById('canvas_sakura') + var child = document.getElementById(id) child.parentNode.removeChild(child) window.cancelAnimationFrame(stop) staticx = false diff --git a/components/SideBarDrawer.js b/components/SideBarDrawer.js index 47052db9..0db865cb 100644 --- a/components/SideBarDrawer.js +++ b/components/SideBarDrawer.js @@ -1,5 +1,5 @@ import { useRouter } from 'next/router' -import React from 'react' +import { useEffect } from 'react' /** * 侧边栏抽屉面板,可以从侧面拉出 @@ -8,7 +8,7 @@ import React from 'react' */ const SideBarDrawer = ({ children, isOpen, onOpen, onClose, className }) => { const router = useRouter() - React.useEffect(() => { + useEffect(() => { const sideBarDrawerRouteListener = () => { switchSideDrawerVisible(false) } @@ -37,8 +37,8 @@ const SideBarDrawer = ({ children, isOpen, onOpen, onClose, className }) => { } } - return