From 74f22db892adfddd72be4305bd76fbc8501c6954 Mon Sep 17 00:00:00 2001 From: Sebastian <39752847+sebastian0619@users.noreply.github.com> Date: Thu, 27 Jul 2023 22:02:59 +0800 Subject: [PATCH 01/53] Add files via upload --- public/favicon.ico | Bin 15406 -> 67646 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/favicon.ico b/public/favicon.ico index 92e7de8ffce12527bfb75119df2c350a65f82959..691fefe23cfce796401c40a0b4cf97c460f68c7b 100644 GIT binary patch literal 67646 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

mcJ|NfR&-_zXTbuE-D}Ew&o*pS04L; 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 literal 15406 zcmeI350F(=9mnsoZ2v4JYIC5C-PT=LmR;Bd(UJ)qv?vsrnvt5ch6HTOsY#opp$1Yc zgrJPFloZOOX*6a+(W!)jOdOr@Pc@7)WHE^(iI|2HF`)JNzCGvlduQ*x@4UzQRvhol zZ-2jYe*eDb&pr3t^X?`|T~eQn7?HqRlD^?daz>IQEiL`!j<+Vsdg^+5oPKPQ>}*Vu z4s3A2qrVBw2OR<-{3=-KU_hl8;uE zUaFH$HfV-fZEtVybmDJ-KL+3IXsx%QzR%Y?n+=p_cs=qe;m=iM07%0E|5ezwSzGjen@*L_i(KZ?gy_5AI3@Be!o_m2&eFh*6~za>E;3R-7cptB*ZPlJ8Ac5Gn`wn!fA z_*wDXIIJP>UdDQ%$jNKUtYcXrW9v1KE>$l0YTeh~Q8IPkbh=BaFIfk@UA3IJ)1ilH z>z&Mdo+Rm)bh2@_;eC+qlv7KbX5#7I+ePeIIi@8l*~-WHHkT+P3izLd|JC^KgFcT7 zPtuC7;qoQUlknw=84;n5al8nhz0g0P#rQ4=iTZQGSYyYIeS2u9vSL8{Aa*_>^CLmB+v4gG0;Q)p+)_?#;rt@{!x>+AcA=$^@B40+<))RYrpa^pY^&`ytJ;A z@rj;);&#=GNR5=wC?5y_z^}@ zcS_cpn&XwSzGFvnRSei>*)I#ib)$Z7I%<+`97Y5q( zP7@X z51;MOzrpcqSH3QMhsrDC+n0r(J*v*)ZqM_#I&j}04DdVf(|GKl9cO06NB7sKnZUEyPJkIxe}Fy8CyLhkUdv-c-4F8A?bIAeTa z7}uAZo15PNh7B=sWCNb1-dFn*eAmU`S3h|_@GpwZCp*Tg_-^iFc}J%_lqT^<2)n>S^Da*m&SCuEo{jr~hZh=93-kL|*^vJBF2vLFRe3%>{maQ&YIA z#n1lXeKuw}S>xq%rf{7}>s&4hKW$y$V^oWu{?Gl*ENl<>=lYx}T<5FT)Dl1Q;q(w= zUKxCu>p$(${^#mi;-~*}&+NmtFlR4L>33h{@kjl(Fc|ZPdDjzS%qxSxxMq9MhU*;p zD*C@>_?geZ{r`7r%p(@NoscgRx$tg(dN{50Oq33&nww~)_na@-_pke zen;0p==VRy=RmnJ^!mY=|Lnh~`FOFMHt4hCcfW}W(wfMOgF9_pi zmBFfaF-&OJi67tfcf#m^j^pO?q# z$aw?n?Wwe5zpbxS#$Uhhex@*S+@IsXe_2d^avr0tiE+f7m7+jIB|V(YAPz}`4t{!uZHGS&?L*!JJ&61> zd@t8{8Gr3ld!W_mqt6e0PI1?cK5{%QBF=KK6!rtw&dI`^`)#tmV*}3!txq}|7T5UL zdrh(28P`>=jnC5dzHnS!&L~E|yo{|RLNv=j{6?yl< zAE!;1K<@zWfcrP44LXBpE{|trzs=WcqI#eR)Wn za<{dS%v{m`@%&0Qw0j5gRQZN>LsbTz&gVY|uE!uf|CWKXMe7&xQs^M`XW7{E`Juv_ kl^47x~eoCKjl8nA&KNi@(R(!1ohNK7n2PJxF%K!iX From 9909f38df4be26eaee28df163829d5b4cc25ac42 Mon Sep 17 00:00:00 2001 From: Sebastian <39752847+sebastian0619@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:55:15 +0800 Subject: [PATCH 02/53] Add files via upload --- components/DifyChatbot.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 components/DifyChatbot.js 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; +} From 794d7b41d85a6afa17a67eaa8b5a5a77b471bbaf Mon Sep 17 00:00:00 2001 From: Sebastian <39752847+sebastian0619@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:56:17 +0800 Subject: [PATCH 03/53] Update ExternalPlugins.js --- components/ExternalPlugins.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/ExternalPlugins.js b/components/ExternalPlugins.js index 3c274b55..01b3df20 100644 --- a/components/ExternalPlugins.js +++ b/components/ExternalPlugins.js @@ -11,6 +11,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('./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 }) @@ -41,6 +42,7 @@ const ExternalPlugin = (props) => { {JSON.parse(siteConfig('FIREWORKS')) && } {JSON.parse(siteConfig('SAKURA')) && } {JSON.parse(siteConfig('STARRY_SKY')) && } + {JSON.parse(siteConfig('DIFY_CHATBOT_ENABLED')) && } {JSON.parse(siteConfig('MUSIC_PLAYER')) && } {JSON.parse(siteConfig('NEST')) && } {JSON.parse(siteConfig('FLUTTERINGRIBBON')) && } From 73d439c328a88bd1055ecf43f8aada4ccc0bb6e0 Mon Sep 17 00:00:00 2001 From: Sebastian <39752847+sebastian0619@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:57:13 +0800 Subject: [PATCH 04/53] Update blog.config.js --- blog.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/blog.config.js b/blog.config.js index 7c0358d3..9d67998c 100644 --- a/blog.config.js +++ b/blog.config.js @@ -190,7 +190,9 @@ const BLOG = { 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: From 8bbaa2b30da5c80799104c070e24bcad66715cfd Mon Sep 17 00:00:00 2001 From: Sebastian <39752847+sebastian0619@users.noreply.github.com> Date: Fri, 24 Nov 2023 16:20:47 +0800 Subject: [PATCH 05/53] Add files via upload --- public/favicon.ico | Bin 67646 -> 15406 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/favicon.ico b/public/favicon.ico index 691fefe23cfce796401c40a0b4cf97c460f68c7b..92e7de8ffce12527bfb75119df2c350a65f82959 100644 GIT binary patch literal 15406 zcmeI350F(=9mnsoZ2v4JYIC5C-PT=LmR;Bd(UJ)qv?vsrnvt5ch6HTOsY#opp$1Yc zgrJPFloZOOX*6a+(W!)jOdOr@Pc@7)WHE^(iI|2HF`)JNzCGvlduQ*x@4UzQRvhol zZ-2jYe*eDb&pr3t^X?`|T~eQn7?HqRlD^?daz>IQEiL`!j<+Vsdg^+5oPKPQ>}*Vu z4s3A2qrVBw2OR<-{3=-KU_hl8;uE zUaFH$HfV-fZEtVybmDJ-KL+3IXsx%QzR%Y?n+=p_cs=qe;m=iM07%0E|5ezwSzGjen@*L_i(KZ?gy_5AI3@Be!o_m2&eFh*6~za>E;3R-7cptB*ZPlJ8Ac5Gn`wn!fA z_*wDXIIJP>UdDQ%$jNKUtYcXrW9v1KE>$l0YTeh~Q8IPkbh=BaFIfk@UA3IJ)1ilH z>z&Mdo+Rm)bh2@_;eC+qlv7KbX5#7I+ePeIIi@8l*~-WHHkT+P3izLd|JC^KgFcT7 zPtuC7;qoQUlknw=84;n5al8nhz0g0P#rQ4=iTZQGSYyYIeS2u9vSL8{Aa*_>^CLmB+v4gG0;Q)p+)_?#;rt@{!x>+AcA=$^@B40+<))RYrpa^pY^&`ytJ;A z@rj;);&#=GNR5=wC?5y_z^}@ zcS_cpn&XwSzGFvnRSei>*)I#ib)$Z7I%<+`97Y5q( zP7@X z51;MOzrpcqSH3QMhsrDC+n0r(J*v*)ZqM_#I&j}04DdVf(|GKl9cO06NB7sKnZUEyPJkIxe}Fy8CyLhkUdv-c-4F8A?bIAeTa z7}uAZo15PNh7B=sWCNb1-dFn*eAmU`S3h|_@GpwZCp*Tg_-^iFc}J%_lqT^<2)n>S^Da*m&SCuEo{jr~hZh=93-kL|*^vJBF2vLFRe3%>{maQ&YIA z#n1lXeKuw}S>xq%rf{7}>s&4hKW$y$V^oWu{?Gl*ENl<>=lYx}T<5FT)Dl1Q;q(w= zUKxCu>p$(${^#mi;-~*}&+NmtFlR4L>33h{@kjl(Fc|ZPdDjzS%qxSxxMq9MhU*;p zD*C@>_?geZ{r`7r%p(@NoscgRx$tg(dN{50Oq33&nww~)_na@-_pke zen;0p==VRy=RmnJ^!mY=|Lnh~`FOFMHt4hCcfW}W(wfMOgF9_pi zmBFfaF-&OJi67tfcf#m^j^pO?q# z$aw?n?Wwe5zpbxS#$Uhhex@*S+@IsXe_2d^avr0tiE+f7m7+jIB|V(YAPz}`4t{!uZHGS&?L*!JJ&61> zd@t8{8Gr3ld!W_mqt6e0PI1?cK5{%QBF=KK6!rtw&dI`^`)#tmV*}3!txq}|7T5UL zdrh(28P`>=jnC5dzHnS!&L~E|yo{|RLNv=j{6?yl< zAE!;1K<@zWfcrP44LXBpE{|trzs=WcqI#eR)Wn za<{dS%v{m`@%&0Qw0j5gRQZN>LsbTz&gVY|uE!uf|CWKXMe7&xQs^M`XW7{E`Juv_ kl^47x~eoCKjl8nA&KNi@(R(!1ohNK7n2PJxF%K!iX literal 67646 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

mcJ|NfR&-_zXTbuE-D}Ew&o*pS04L; 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 From b970182403ff7cb5a31afdf7d34792a368131945 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Wed, 27 Dec 2023 19:26:52 +0800 Subject: [PATCH 06/53] v4.1.3 --- .env.local | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.local b/.env.local index 8a0dbf80..7e529e5c 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.1.3 # 可在此添加环境变量,去掉最左边的(# )注释即可 diff --git a/package.json b/package.json index bac192ad..cccc5a3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "notion-next", - "version": "4.1.2", + "version": "4.1.3", "homepage": "https://github.com/tangly1024/NotionNext.git", "license": "MIT", "repository": { From dfa6c72d4a6f0cfa67b50aa7bc30687026a874d2 Mon Sep 17 00:00:00 2001 From: ShH Y <74806550+1208nn@users.noreply.github.com> Date: Thu, 28 Dec 2023 10:52:44 +0000 Subject: [PATCH 07/53] update customcontextmenu --- components/CustomContextMenu.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/CustomContextMenu.js b/components/CustomContextMenu.js index 3a6d2d4a..06c5e7b8 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('THEME_SWITCH') && (
{locale.MENU.THEME_SWITCH}
+ )} From b15d5f7c2ccf0ffe48448b3d1cd0a70927f5c85c Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Sat, 30 Dec 2023 17:19:21 +0800 Subject: [PATCH 08/53] =?UTF-8?q?hexo=20=E4=B8=BB=E9=A2=98=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=85=A8=E5=B1=8F=E6=96=87=E7=AB=A0=EF=BC=8C=E9=9A=90?= =?UTF-8?q?=E8=97=8F=E4=BE=A7=E8=BE=B9=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/notion/getNotion.js | 3 +-- themes/hexo/components/PostHeader.js | 6 ++++++ themes/hexo/components/SideRight.js | 6 ++++++ themes/hexo/index.js | 5 +++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/notion/getNotion.js b/lib/notion/getNotion.js index 3da84ee8..aad65379 100644 --- a/lib/notion/getNotion.js +++ b/lib/notion/getNotion.js @@ -16,7 +16,6 @@ export async function getNotion(pageId) { } const postInfo = blockMap?.block?.[idToUuid(pageId)].value - return { id: pageId, type: postInfo, @@ -26,7 +25,7 @@ export async function getNotion(pageId) { status: 'Published', createdTime: formatDate(new Date(postInfo.created_time).toString(), BLOG.LANG), lastEditedDay: formatDate(new Date(postInfo?.last_edited_time).toString(), BLOG.LANG), - fullWidth: false, + fullWidth: postInfo?.fullWidth, page_cover: getPageCover(postInfo), date: { start_date: formatDate(new Date(postInfo?.last_edited_time).toString(), BLOG.LANG) }, blockMap diff --git a/themes/hexo/components/PostHeader.js b/themes/hexo/components/PostHeader.js index 8a69b9ef..fb051e8f 100644 --- a/themes/hexo/components/PostHeader.js +++ b/themes/hexo/components/PostHeader.js @@ -12,6 +12,12 @@ export default function PostHeader({ post, siteInfo }) { if (!post) { return <> } + + // 文章全屏隐藏标头 + if (post.fullWidth) { + return
+ } + const headerImage = post?.pageCover ? post.pageCover : siteInfo?.pageCover return ( diff --git a/themes/hexo/components/SideRight.js b/themes/hexo/components/SideRight.js index c5600eb4..497a7b2f 100644 --- a/themes/hexo/components/SideRight.js +++ b/themes/hexo/components/SideRight.js @@ -38,6 +38,12 @@ export default function SideRight(props) { } = props const { locale } = useGlobal() + + // 文章全屏处理 + if (post && post?.fullWidth) { + return null + } + return (
diff --git a/themes/hexo/index.js b/themes/hexo/index.js index 7e770dc5..4f8dbe92 100644 --- a/themes/hexo/index.js +++ b/themes/hexo/index.js @@ -40,8 +40,9 @@ import { siteConfig } from '@/lib/config' * @constructor */ const LayoutBase = props => { - const { children, headerSlot, floatSlot, slotTop, meta, className } = props + const { post, children, headerSlot, floatSlot, slotTop, meta, className } = props const { onLoading } = useGlobal() + const fullWidth = post?.fullWidth ?? false return (
@@ -70,7 +71,7 @@ const LayoutBase = props => { {/* 主区块 */}
-
+
Date: Sat, 30 Dec 2023 17:24:03 +0800 Subject: [PATCH 09/53] =?UTF-8?q?example=E4=B8=BB=E9=A2=98=E6=94=AF?= =?UTF-8?q?=E6=8C=81fullwidth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/global.js | 6 +++++- themes/example/index.js | 8 ++++---- themes/hexo/components/PostHeader.js | 4 ++-- themes/hexo/index.js | 5 ++--- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/global.js b/lib/global.js index 28b79be3..faecf989 100644 --- a/lib/global.js +++ b/lib/global.js @@ -12,7 +12,7 @@ const GlobalContext = createContext() * @constructor */ export function GlobalContextProvider(props) { - const { children, siteInfo, categoryOptions, tagOptions, NOTION_CONFIG } = props + const { post, children, siteInfo, categoryOptions, tagOptions, NOTION_CONFIG } = props const router = useRouter() const [lang, updateLang] = useState(NOTION_CONFIG?.LANG || LANG) // 默认语言 const [locale, updateLocale] = useState(generateLocaleDict(NOTION_CONFIG?.LANG || LANG)) // 默认语言 @@ -20,6 +20,9 @@ export function GlobalContextProvider(props) { const [isDarkMode, updateDarkMode] = useState(NOTION_CONFIG?.APPEARANCE || APPEARANCE === 'dark') // 默认深色模式 const [onLoading, setOnLoading] = useState(false) // 抓取文章数据 + // 是否全屏 + const fullWidth = post?.fullWidth ?? false + // 切换主题 function switchTheme() { const currentIndex = THEMES.indexOf(theme) @@ -82,6 +85,7 @@ export function GlobalContextProvider(props) { return ( { const { children, slotTop, meta } = props - const { onLoading } = useGlobal() + const { onLoading, fullWidth } = useGlobal() // 增加一个状态以触发 Transition 组件的动画 // const [showTransition, setShowTransition] = useState(true) @@ -65,12 +65,12 @@ const LayoutBase = props => {
{/* 标题栏 */} - + {fullWidth ? null : <Title {...props} />} <div id='container-wrapper' className={(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE')) ? 'flex-row-reverse' : '') + 'relative container mx-auto justify-center md:flex items-start py-8 px-2'}> {/* 内容 */} - <div className='w-full max-w-3xl xl:px-14 lg:px-4 '> + <div className={`w-full ${fullWidth ? '' : 'max-w-3xl'} xl:px-14 lg:px-4`}> <Transition show={!onLoading} appear={true} @@ -89,7 +89,7 @@ const LayoutBase = props => { </div> {/* 侧边栏 */} - <SideBar {...props} /> + {!fullWidth && <SideBar {...props} />} </div> diff --git a/themes/hexo/components/PostHeader.js b/themes/hexo/components/PostHeader.js index fb051e8f..9266f181 100644 --- a/themes/hexo/components/PostHeader.js +++ b/themes/hexo/components/PostHeader.js @@ -7,14 +7,14 @@ import { formatDateFmt } from '@/lib/formatDate' import { siteConfig } from '@/lib/config' export default function PostHeader({ post, siteInfo }) { - const { locale } = useGlobal() + const { locale, fullWidth } = useGlobal() if (!post) { return <></> } // 文章全屏隐藏标头 - if (post.fullWidth) { + if (fullWidth) { return <div className='my-8'/> } diff --git a/themes/hexo/index.js b/themes/hexo/index.js index 4f8dbe92..4fa0dd62 100644 --- a/themes/hexo/index.js +++ b/themes/hexo/index.js @@ -40,9 +40,8 @@ import { siteConfig } from '@/lib/config' * @constructor */ const LayoutBase = props => { - const { post, children, headerSlot, floatSlot, slotTop, meta, className } = props - const { onLoading } = useGlobal() - const fullWidth = post?.fullWidth ?? false + const { children, headerSlot, floatSlot, slotTop, meta, className } = props + const { onLoading, fullWidth } = useGlobal() return ( <div id='theme-hexo'> From f5e5957d2c2db54c52c174a88fbc5b0d04e78d23 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sat, 30 Dec 2023 17:27:31 +0800 Subject: [PATCH 10/53] =?UTF-8?q?fukasawa=20=E6=94=AF=E6=8C=81fullwidth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/fukasawa/components/ArticleDetail.js | 4 ++-- themes/fukasawa/index.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/themes/fukasawa/components/ArticleDetail.js b/themes/fukasawa/components/ArticleDetail.js index 31294304..1b9076a4 100644 --- a/themes/fukasawa/components/ArticleDetail.js +++ b/themes/fukasawa/components/ArticleDetail.js @@ -17,13 +17,13 @@ import WWAds from '@/components/WWAds' */ export default function ArticleDetail(props) { const { post, prev, next } = props - const { locale } = useGlobal() + const { locale, fullWidth } = useGlobal() if (!post) { return <></> } return ( - <div id="container" className="max-w-5xl overflow-x-auto flex-grow mx-auto w-screen md:w-full "> + <div id="container" className={`${fullWidth ? 'px-10' : 'max-w-5xl '} overflow-x-auto flex-grow mx-auto w-screen md:w-full`}> {post?.type && !post?.type !== 'Page' && post?.pageCover && ( <div className="w-full relative md:flex-shrink-0 overflow-hidden"> <LazyImage alt={post.title} src={post?.pageCover} className='object-center w-full' /> diff --git a/themes/fukasawa/index.js b/themes/fukasawa/index.js index 3786c20d..bf41b1a6 100644 --- a/themes/fukasawa/index.js +++ b/themes/fukasawa/index.js @@ -46,9 +46,9 @@ export const useFukasawaGlobal = () => useContext(ThemeGlobalFukasawa) const LayoutBase = (props) => { const { children, headerSlot, meta } = props const leftAreaSlot = <Live2D /> - const { onLoading } = useGlobal() + const { onLoading, fullWidth } = useGlobal() - const FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT = siteConfig('FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT', null, CONFIG) + const FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT = fullWidth || siteConfig('FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT', null, CONFIG) // 侧边栏折叠从 本地存储中获取 open 状态的初始值 const [isCollapsed, setIsCollapse] = useState(() => { @@ -80,7 +80,7 @@ const LayoutBase = (props) => { <AsideLeft {...props} slot={leftAreaSlot} /> <main id='wrapper' className='relative flex w-full py-8 justify-center bg-day dark:bg-night'> - <div id='container-inner' className='2xl:max-w-6xl md:max-w-4xl w-full relative z-10'> + <div id='container-inner' className={`${fullWidth ? '' : '2xl:max-w-6xl md:max-w-4xl'} w-full relative z-10`}> <Transition show={!onLoading} appear={true} From 3666ed48018d061a59f03b0183739585988bd998 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sat, 30 Dec 2023 17:31:28 +0800 Subject: [PATCH 11/53] =?UTF-8?q?gitbook=E4=B8=BB=E9=A2=98=E6=94=AF?= =?UTF-8?q?=E6=8C=81fullwidth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/gitbook/index.js | 48 ++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/themes/gitbook/index.js b/themes/gitbook/index.js index 2e42b314..4743199c 100644 --- a/themes/gitbook/index.js +++ b/themes/gitbook/index.js @@ -49,7 +49,7 @@ export const useGitBookGlobal = () => useContext(ThemeGlobalGitbook) */ const LayoutBase = (props) => { const { children, post, allNavPages, slotLeft, slotRight, slotTop, meta } = props - const { onLoading } = useGlobal() + const { onLoading, fullWidth } = useGlobal() const router = useRouter() const [tocVisible, changeTocVisible] = useState(false) const [pageNavVisible, changePageNavVisible] = useState(false) @@ -73,7 +73,9 @@ const LayoutBase = (props) => { <main id='wrapper' className={(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE')) ? 'flex-row-reverse' : '') + 'relative flex justify-between w-full h-full mx-auto'}> {/* 左侧推拉抽屉 */} - <div className={'font-sans hidden md:block border-r dark:border-transparent relative z-10 '}> + {fullWidth + ? null + : (<div className={'font-sans hidden md:block border-r dark:border-transparent relative z-10 '}> <div className='w-72 py-14 px-6 sticky top-0 overflow-y-scroll h-screen scroll-hidden'> {slotLeft} <SearchInput className='my-3 rounded-md' /> @@ -87,11 +89,11 @@ const LayoutBase = (props) => { <div className='w-72 fixed left-0 bottom-0 z-20 bg-white'> <Footer {...props} /> </div> - </div> + </div>) } <div id='center-wrapper' className='flex flex-col justify-between w-full relative z-10 pt-14 min-h-screen'> - <div id='container-inner' className='w-full px-7 max-w-3xl justify-center mx-auto'> + <div id='container-inner' className={`w-full px-7 ${fullWidth ? 'px-10' : 'max-w-3xl'} justify-center mx-auto`}> {slotTop} <WWAds className='w-full' orientation='horizontal'/> @@ -124,27 +126,29 @@ const LayoutBase = (props) => { </div> {/* 右侧侧推拉抽屉 */} - <div style={{ width: '32rem' }} className={'hidden xl:block dark:border-transparent relative z-10 '}> - <div className='py-14 px-6 sticky top-0'> - <ArticleInfo post={props?.post ? props?.post : props.notice} /> + {fullWidth + ? null + : <div style={{ width: '32rem' }} className={'hidden xl:block dark:border-transparent relative z-10 '}> + <div className='py-14 px-6 sticky top-0'> + <ArticleInfo post={props?.post ? props?.post : props.notice} /> - <div className='py-4'> - <Catalog {...props} /> - {slotRight} - {router.route === '/' && <> - <InfoCard {...props} /> - {siteConfig('GITBOOK_WIDGET_REVOLVER_MAPS', null, CONFIG) === 'true' && <RevolverMaps />} - <Live2D /> - </>} - {/* gitbook主题首页只显示公告 */} - <Announcement {...props} /> - </div> + <div className='py-4'> + <Catalog {...props} /> + {slotRight} + {router.route === '/' && <> + <InfoCard {...props} /> + {siteConfig('GITBOOK_WIDGET_REVOLVER_MAPS', null, CONFIG) === 'true' && <RevolverMaps />} + <Live2D /> + </>} + {/* gitbook主题首页只显示公告 */} + <Announcement {...props} /> + </div> - <AdSlot type='in-article' /> - <Live2D /> + <AdSlot type='in-article' /> + <Live2D /> - </div> - </div> + </div> + </div>} </main> From 4b060740264725449cfaac9b7d68df69c41cad00 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sat, 30 Dec 2023 17:36:51 +0800 Subject: [PATCH 12/53] =?UTF-8?q?heo=E4=B8=BB=E9=A2=98=E6=94=AF=E6=8C=81fu?= =?UTF-8?q?llwidth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/heo/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/themes/heo/index.js b/themes/heo/index.js index 4d289924..241c66ec 100644 --- a/themes/heo/index.js +++ b/themes/heo/index.js @@ -284,7 +284,7 @@ const LayoutArchive = props => { */ const LayoutSlug = props => { const { post, lock, validPassword } = props - const { locale } = useGlobal() + const { locale, fullWidth } = useGlobal() const [hasCode, setHasCode] = useState(false) @@ -294,7 +294,7 @@ const LayoutSlug = props => { }, []) // 右侧栏 - const slotRight = <SideRight {...props} /> + const slotRight = fullWidth ? null : <SideRight {...props} /> const headerSlot = ( <header data-aos="fade-up" @@ -307,7 +307,7 @@ const LayoutSlug = props => { <div id="nav-bar-wrapper"> <NavBar {...props} /> </div> - <PostHeader {...props} /> + {fullWidth ? null : <PostHeader {...props} />} </header> ) const commentEnable = siteConfig('COMMENT_TWIKOO_ENV_ID') || siteConfig('COMMENT_WALINE_SERVER_URL') || siteConfig('COMMENT_VALINE_APP_ID') || @@ -322,7 +322,7 @@ const LayoutSlug = props => { showTag={false} slotRight={slotRight} > - <div className={`w-full xl:max-w-5xl ${hasCode ? 'xl:w-[73.15vw]' : ''} lg:hover:shadow lg:border rounded-2xl lg:px-2 lg:py-4 bg-white dark:bg-[#18171d] dark:border-gray-600 article`}> + <div className={`w-full ${fullWidth ? '' : 'xl:max-w-5xl'} ${hasCode ? 'xl:w-[73.15vw]' : ''} lg:hover:shadow lg:border rounded-2xl lg:px-2 lg:py-4 bg-white dark:bg-[#18171d] dark:border-gray-600 article`}> {lock && <ArticleLock validPassword={validPassword} />} {!lock && ( From 4acc459c08633033e75e6eb1beea38e049f940d8 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sat, 30 Dec 2023 17:49:51 +0800 Subject: [PATCH 13/53] =?UTF-8?q?heo=20=E6=94=AF=E6=8C=81fullWidth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/heo/index.js | 70 ++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/themes/heo/index.js b/themes/heo/index.js index 241c66ec..91e8be07 100644 --- a/themes/heo/index.js +++ b/themes/heo/index.js @@ -57,6 +57,10 @@ const LayoutBase = props => { meta } = props + // 全屏模式下的最大宽度 + const { fullWidth } = useGlobal() + const maxWidth = fullWidth ? 'max-w-[86rem]' : 'max-w-[86rem]' // 最大宽度都是86rem,和顶部菜单栏对齐,设置成空则与网页对齐 + return ( <div id="theme-heo" @@ -72,7 +76,7 @@ const LayoutBase = props => { {/* 主区块 */} <main id="wrapper-outer" - className={'flex-grow w-full max-w-[86rem] mx-auto relative md:px-5'} + className={`flex-grow w-full ${maxWidth} mx-auto relative md:px-5`} > <div id="container-inner" @@ -131,10 +135,10 @@ const LayoutIndex = props => { <CategoryBar {...props} /> {siteConfig('POST_LIST_STYLE') === 'page' ? ( - <BlogPostListPage {...props} /> + <BlogPostListPage {...props} /> ) : ( - <BlogPostListScroll {...props} /> + <BlogPostListScroll {...props} /> )} </div> </LayoutBase> @@ -165,10 +169,10 @@ const LayoutPostList = props => { <CategoryBar {...props} /> {siteConfig('POST_LIST_STYLE') === 'page' ? ( - <BlogPostListPage {...props} /> + <BlogPostListPage {...props} /> ) : ( - <BlogPostListScroll {...props} /> + <BlogPostListScroll {...props} /> )} </div> </LayoutBase> @@ -218,18 +222,18 @@ const LayoutSearch = props => { <div id="post-outer-wrapper" className="px-5 md:px-0"> {!currentSearch ? ( - <SearchNav {...props} /> + <SearchNav {...props} /> ) : ( - <div id="posts-wrapper"> - {siteConfig('POST_LIST_STYLE') === 'page' - ? ( - <BlogPostListPage {...props} /> - ) - : ( - <BlogPostListScroll {...props} /> - )} - </div> + <div id="posts-wrapper"> + {siteConfig('POST_LIST_STYLE') === 'page' + ? ( + <BlogPostListPage {...props} /> + ) + : ( + <BlogPostListScroll {...props} /> + )} + </div> )} </div> </LayoutBase> @@ -311,8 +315,8 @@ const LayoutSlug = props => { </header> ) const commentEnable = siteConfig('COMMENT_TWIKOO_ENV_ID') || siteConfig('COMMENT_WALINE_SERVER_URL') || siteConfig('COMMENT_VALINE_APP_ID') || - siteConfig('COMMENT_GISCUS_REPO') || siteConfig('COMMENT_CUSDIS_APP_ID') || siteConfig('COMMENT_UTTERRANCES_REPO') || - siteConfig('COMMENT_GITALK_CLIENT_ID') || siteConfig('COMMENT_WEBMENTION_ENABLE') + siteConfig('COMMENT_GISCUS_REPO') || siteConfig('COMMENT_CUSDIS_APP_ID') || siteConfig('COMMENT_UTTERRANCES_REPO') || + siteConfig('COMMENT_GITALK_CLIENT_ID') || siteConfig('COMMENT_WEBMENTION_ENABLE') return ( <LayoutBase @@ -360,21 +364,23 @@ const LayoutSlug = props => { )} </article> - <div className={`${commentEnable && post ? '' : 'hidden'}`}> - <hr className="my-4 border-dashed" /> + {fullWidth + ? null + : <div className={`${commentEnable && post ? '' : 'hidden'}`}> + <hr className="my-4 border-dashed" /> - {/* 评论互动 */} - <div className="duration-200 overflow-x-auto px-5"> - <div className="text-2xl dark:text-white"> - <i className="fas fa-comment mr-1" /> - {locale.COMMON.COMMENTS} + {/* 评论互动 */} + <div className="duration-200 overflow-x-auto px-5"> + <div className="text-2xl dark:text-white"> + <i className="fas fa-comment mr-1" /> + {locale.COMMON.COMMENTS} + </div> + <Comment frontMatter={post} className="" /> + <div className="py-2"> + <AdSlot /> + </div> </div> - <Comment frontMatter={post} className="" /> - <div className="py-2"> - <AdSlot /> - </div> - </div> - </div> + </div>} </div> )} </div> @@ -390,7 +396,7 @@ const LayoutSlug = props => { */ const Layout404 = props => { const { meta, siteInfo } = props - const { onLoading } = useGlobal() + const { onLoading, fullWidth } = useGlobal() return ( <div id="theme-heo" @@ -411,7 +417,7 @@ const Layout404 = props => { {/* 主区块 */} <main id="wrapper-outer" - className={'flex-grow max-w-4xl w-screen mx-auto px-5'} + className={`flex-grow ${fullWidth ? '' : 'max-w-4xl'} w-screen mx-auto px-5`} > <div id="error-wrapper" className={'w-full mx-auto justify-center'}> <Transition From bb86edd3ba979c57f7a2414de0904f518afa3782 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sat, 30 Dec 2023 17:54:57 +0800 Subject: [PATCH 14/53] =?UTF-8?q?Matery=E6=94=AF=E6=8C=81FullWidth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/matery/index.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/themes/matery/index.js b/themes/matery/index.js index eee59b53..6ecb7dbf 100644 --- a/themes/matery/index.js +++ b/themes/matery/index.js @@ -41,7 +41,7 @@ import { siteConfig } from '@/lib/config' */ const LayoutBase = props => { const { children, headerSlot, meta, siteInfo, containerSlot, post } = props - const { onLoading } = useGlobal() + const { onLoading, fullWidth } = useGlobal() return ( <div id='theme-matery' className="min-h-screen flex flex-col justify-between bg-hexo-background-gray dark:bg-black w-full"> @@ -69,11 +69,11 @@ const LayoutBase = props => { <main id="wrapper" className={`${siteConfig('MATERY_HOME_BANNER_ENABLE', null, CONFIG) ? '' : 'pt-16'} flex-1 w-full py-8 md:px-8 lg:px-24 relative`}> {/* 嵌入区域 */} - <div id="container-slot" className={`w-full max-w-6xl ${post && ' lg:max-w-3xl 2xl:max-w-4xl '} mt-6 px-3 mx-auto lg:flex lg:space-x-4 justify-center relative z-10`}> + <div id="container-slot" className={`w-full ${fullWidth ? '' : 'max-w-6xl'} ${post && ' lg:max-w-3xl 2xl:max-w-4xl '} mt-6 px-3 mx-auto lg:flex lg:space-x-4 justify-center relative z-10`}> {containerSlot} </div> - <div id="container-inner" className="w-full min-h-fit max-w-6xl mx-auto lg:flex lg:space-x-4 justify-center relative z-10"> + <div id="container-inner" className={`w-full min-h-fit ${fullWidth ? '' : 'max-w-6xl'} mx-auto lg:flex lg:space-x-4 justify-center relative z-10`}> <Transition show={!onLoading} appear={true} @@ -191,13 +191,15 @@ const LayoutArchive = (props) => { */ const LayoutSlug = props => { const { post, lock, validPassword } = props + const { fullWidth } = useGlobal() + const headerSlot = fullWidth ? null : <PostHeader {...props} /> - return (<LayoutBase {...props} headerSlot={<PostHeader {...props} />} showCategory={false} showTag={false} floatRightBottom={<JumpToCommentButton />}> + return (<LayoutBase {...props} headerSlot={headerSlot} showCategory={false} showTag={false} floatRightBottom={<JumpToCommentButton />}> - <div id='inner-wrapper' className={'w-full lg:max-w-3xl 2xl:max-w-4xl'} > + <div id='inner-wrapper' className={`w-full ${fullWidth ? '' : 'lg:max-w-3xl 2xl:max-w-4xl'}`} > {/* 文章主体卡片 */} - <div className="-mt-32 transition-all duration-300 rounded-md mx-3 lg:border lg:rounded-xl lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black"> + <div className={`${fullWidth ? '' : '-mt-32'} transition-all duration-300 rounded-md mx-3 lg:border lg:rounded-xl lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black`}> {lock && <ArticleLock validPassword={validPassword} />} @@ -221,7 +223,7 @@ const LayoutSlug = props => { <article itemScope > {/* Notion文章主体 */} - <section className='justify-center mx-auto max-w-2xl lg:max-w-full'> + <section className={`justify-center mx-auto ${fullWidth ? '' : 'max-w-2xl lg:max-w-full'}`}> {post && <NotionPage post={post} />} </section> From 49c1c60e10e1cbe7634c4ce9e04a55002d3f679e Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sat, 30 Dec 2023 17:56:41 +0800 Subject: [PATCH 15/53] =?UTF-8?q?medium=20=E6=94=AF=E6=8C=81fullwidth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/medium/index.js | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/themes/medium/index.js b/themes/medium/index.js index fbbbfde5..433ed80b 100644 --- a/themes/medium/index.js +++ b/themes/medium/index.js @@ -51,14 +51,14 @@ const LayoutBase = props => { const { locale } = useGlobal() const router = useRouter() const [tocVisible, changeTocVisible] = useState(false) - const { onLoading } = useGlobal() + const { onLoading, fullWidth } = useGlobal() return ( <ThemeGlobalMedium.Provider value={{ tocVisible, changeTocVisible }}> {/* SEO相关 */} - <CommonHead meta={meta}/> + <CommonHead meta={meta} /> {/* CSS样式 */} - <Style/> + <Style /> <div id='theme-medium' className='bg-white dark:bg-hexo-black-gray w-full h-full min-h-screen justify-center dark:text-gray-300'> @@ -72,7 +72,7 @@ const LayoutBase = props => { {/* 顶部导航栏 */} <TopNavBar {...props} /> - <div id='container-inner' className='px-7 max-w-5xl justify-center mx-auto min-h-screen'> + <div id='container-inner' className={`px-7 ${fullWidth ? '' : 'max-w-5xl'} justify-center mx-auto min-h-screen`}> <Transition show={!onLoading} appear={true} @@ -96,20 +96,23 @@ const LayoutBase = props => { </div> {/* 桌面端右侧 */} - <div className={`hidden xl:block border-l dark:border-transparent w-96 relative z-10 ${siteConfig('MEDIUM_RIGHT_PANEL_DARK', null, CONFIG) ? 'bg-hexo-black-gray dark' : ''}`}> - <div className='py-14 px-6 sticky top-0'> - <Tabs> - {slotRight} - <div key={locale.NAV.ABOUT}> - {router.pathname !== '/search' && <SearchInput className='mt-6 mb-12' />} - {showInfoCard && <InfoCard {...props} />} - {siteConfig('MEDIUM_WIDGET_REVOLVER_MAPS', null, CONFIG) === 'true' && <RevolverMaps />} - </div> - </Tabs> - <Announcement post={notice} /> - <Live2D /> - </div> - </div> + {fullWidth + ? null + : <div className={`hidden xl:block border-l dark:border-transparent w-96 relative z-10 ${siteConfig('MEDIUM_RIGHT_PANEL_DARK', null, CONFIG) ? 'bg-hexo-black-gray dark' : ''}`}> + <div className='py-14 px-6 sticky top-0'> + <Tabs> + {slotRight} + <div key={locale.NAV.ABOUT}> + {router.pathname !== '/search' && <SearchInput className='mt-6 mb-12' />} + {showInfoCard && <InfoCard {...props} />} + {siteConfig('MEDIUM_WIDGET_REVOLVER_MAPS', null, CONFIG) === 'true' && <RevolverMaps />} + </div> + </Tabs> + <Announcement post={notice} /> + <Live2D /> + </div> + </div>} + </main> {/* 移动端底部导航栏 */} @@ -162,7 +165,7 @@ const LayoutSlug = props => { {!lock && <div id='article-wrapper'> {/* 文章信息 */} - <ArticleInfo {...props}/> + <ArticleInfo {...props} /> {/* Notion文章主体 */} <section className="px-1 max-w-4xl"> From 915891fb250fd9a4d6d45d094cf661f6e0c1d030 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sat, 30 Dec 2023 17:59:34 +0800 Subject: [PATCH 16/53] =?UTF-8?q?simple=20=E6=94=AF=E6=8C=81fullwidth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/simple/index.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/themes/simple/index.js b/themes/simple/index.js index 8295d621..7aab376c 100644 --- a/themes/simple/index.js +++ b/themes/simple/index.js @@ -39,7 +39,7 @@ const BlogListPage = dynamic(() => import('./components/BlogListPage'), { ssr: f */ const LayoutBase = props => { const { children, slotTop, meta } = props - const { onLoading } = useGlobal() + const { onLoading, fullWidth } = useGlobal() return ( <div id='theme-simple' className='min-h-screen flex flex-col dark:text-gray-300 bg-white dark:bg-black'> @@ -76,9 +76,11 @@ const LayoutBase = props => { <AdSlot type='native' /> </div> - <div id='right-sidebar' className="hidden xl:block flex-none sticky top-8 w-96 border-l dark:border-gray-800 pl-12 border-gray-100"> - <SideBar {...props} /> - </div> + {fullWidth + ? null + : <div id='right-sidebar' className="hidden xl:block flex-none sticky top-8 w-96 border-l dark:border-gray-800 pl-12 border-gray-100"> + <SideBar {...props} /> + </div>} </div> @@ -162,13 +164,14 @@ const LayoutArchive = props => { */ const LayoutSlug = props => { const { post, lock, validPassword, prev, next } = props + const { fullWidth } = useGlobal() return ( <LayoutBase {...props}> {lock && <ArticleLock validPassword={validPassword} />} - <div id="article-wrapper" className="px-2 xl:max-w-4xl 2xl:max-w-6xl "> + <div id="article-wrapper" className={`px-2 ${fullWidth ? '' : 'xl:max-w-4xl 2xl:max-w-6xl'}`}> {/* 文章信息 */} <ArticleInfo post={post} /> From bf58b739e033c66c51e464fdcc7c5b85fc5402c8 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sat, 30 Dec 2023 18:09:16 +0800 Subject: [PATCH 17/53] =?UTF-8?q?heo=20fullwidth=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/heo/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/heo/index.js b/themes/heo/index.js index 91e8be07..d127a021 100644 --- a/themes/heo/index.js +++ b/themes/heo/index.js @@ -59,7 +59,7 @@ const LayoutBase = props => { // 全屏模式下的最大宽度 const { fullWidth } = useGlobal() - const maxWidth = fullWidth ? 'max-w-[86rem]' : 'max-w-[86rem]' // 最大宽度都是86rem,和顶部菜单栏对齐,设置成空则与网页对齐 + const maxWidth = fullWidth ? 'max-w-[96rem] mx-auto' : 'max-w-[86rem]' // 普通最大宽度是86rem和顶部菜单栏对齐,留空则与窗口对齐 return ( <div From 9553961e3cd50f27dbaba51f19dc549deb5ccf74 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Tue, 9 Jan 2024 11:31:42 +0800 Subject: [PATCH 18/53] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=9F=B3=E9=A2=91?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E6=92=AD=E6=94=BE=E5=A4=B1=E8=B4=A5=E7=9A=84?= =?UTF-8?q?bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/notion/getPostBlocks.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/notion/getPostBlocks.js b/lib/notion/getPostBlocks.js index 809dfe7a..20c9acab 100644 --- a/lib/notion/getPostBlocks.js +++ b/lib/notion/getPostBlocks.js @@ -102,7 +102,10 @@ function filterPostBlocks(id, pageBlock, slice) { } // 如果是文件,或嵌入式PDF,需要重新加密签名 - if ((b?.value?.type === 'file' || b?.value?.type === 'pdf' || b?.value?.type === 'video') && b?.value?.properties?.source?.[0][0]) { + if ((b?.value?.type === 'file' || b?.value?.type === 'pdf' || b?.value?.type === 'video' || b?.value?.type === 'audio') && + b?.value?.properties?.source?.[0][0] && + b?.value?.properties?.source?.[0][0].indexOf('amazonaws.com') > 0 + ) { const oldUrl = b?.value?.properties?.source?.[0][0] const newUrl = `https://notion.so/signed/${encodeURIComponent(oldUrl)}?table=block&id=${b?.value?.id}` b.value.properties.source[0][0] = newUrl From b56dc81749b0e3f3247dbe1a4db0649bd47da37f Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Tue, 9 Jan 2024 11:32:27 +0800 Subject: [PATCH 19/53] 4.1.4 --- .env.local | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.local b/.env.local index 7e529e5c..8a1867eb 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.3 +NEXT_PUBLIC_VERSION=4.1.4 # 可在此添加环境变量,去掉最左边的(# )注释即可 diff --git a/package.json b/package.json index cccc5a3e..a521b97f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "notion-next", - "version": "4.1.3", + "version": "4.1.4", "homepage": "https://github.com/tangly1024/NotionNext.git", "license": "MIT", "repository": { From 4479f362d7ce751c4efb2072d55a6eed8b296859 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Tue, 9 Jan 2024 11:49:53 +0800 Subject: [PATCH 20/53] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=97=B6=E7=9A=84=E8=AF=AD=E8=A8=80=E5=88=87?= =?UTF-8?q?=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/global.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/global.js b/lib/global.js index faecf989..f6ffc1e8 100644 --- a/lib/global.js +++ b/lib/global.js @@ -1,4 +1,4 @@ -import { generateLocaleDict, initLocale } from './lang' +import { generateLocaleDict, initLocale, saveLangToCookies } from './lang' import { createContext, useContext, useEffect, useState } from 'react' import { useRouter } from 'next/router' import { THEMES, initDarkMode, saveDarkModeToCookies } from '@/themes/theme' @@ -49,6 +49,7 @@ export function GlobalContextProvider(props) { */ function changeLang(lang) { if (lang) { + saveLangToCookies(lang) updateLang(lang) updateLocale(generateLocaleDict(lang)) } From 88a99135dd0b858d987748c16d2685ecdc5b1de3 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Tue, 9 Jan 2024 18:06:27 +0800 Subject: [PATCH 21/53] =?UTF-8?q?Simple=E4=B8=BB=E9=A2=98=E6=94=AF?= =?UTF-8?q?=E6=8C=81Algolia=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/lang.js | 6 +++--- themes/simple/components/NavBar.js | 10 +++++++++- themes/simple/index.js | 18 +++++++++++++++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/lang.js b/lib/lang.js index 3e2307f7..5f81af18 100644 --- a/lib/lang.js +++ b/lib/lang.js @@ -89,9 +89,9 @@ export const loadLangFromCookies = () => { } /** - * 保存语言 - * @param newTheme - */ + * 保存语言 + * @param newTheme + */ export const saveLangToCookies = (lang) => { cookie.save('lang', lang, { path: '/' }) } diff --git a/themes/simple/components/NavBar.js b/themes/simple/components/NavBar.js index db3033ca..38df0736 100644 --- a/themes/simple/components/NavBar.js +++ b/themes/simple/components/NavBar.js @@ -1,5 +1,7 @@ +import { siteConfig } from '@/lib/config' import { useRouter } from 'next/router' import { useState } from 'react' +import { useSimpleGlobal } from '..' import { MenuList } from './MenuList' /** @@ -10,9 +12,15 @@ import { MenuList } from './MenuList' export default function NavBar (props) { const [showSearchInput, changeShowSearchInput] = useState(false) const router = useRouter() + const { searchModal } = useSimpleGlobal() + // 展示搜索框 const toggleShowSearchInput = () => { - changeShowSearchInput(!showSearchInput) + if (siteConfig('ALGOLIA_APP_ID')) { + searchModal.current.openSearch() + } else { + changeShowSearchInput(!showSearchInput) + } } const onKeyUp = (e) => { diff --git a/themes/simple/index.js b/themes/simple/index.js index 7aab376c..23373190 100644 --- a/themes/simple/index.js +++ b/themes/simple/index.js @@ -1,5 +1,5 @@ import CONFIG from './config' -import { useEffect } from 'react' +import { createContext, useContext, useEffect, useRef } from 'react' import { isBrowser } from '@/lib/utils' import { useGlobal } from '@/lib/global' import { AdSlot } from '@/components/GoogleAdsense' @@ -10,7 +10,7 @@ import { Style } from './style' import replaceSearchResult from '@/components/Mark' import dynamic from 'next/dynamic' import NotionPage from '@/components/NotionPage' -// const NotionPage = dynamic(() => import('@/components/NotionPage'), { ssr: false }); +import AlgoliaSearchModal from '@/components/AlgoliaSearchModal' // 主题组件 const BlogListScroll = dynamic(() => import('./components/BlogListScroll'), { ssr: false }); @@ -31,6 +31,10 @@ const CommonHead = dynamic(() => import('@/components/CommonHead'), { ssr: false const WWAds = dynamic(() => import('@/components/WWAds'), { ssr: false }); const BlogListPage = dynamic(() => import('./components/BlogListPage'), { ssr: false }) +// 主题全局状态 +const ThemeGlobalSimple = createContext() +export const useSimpleGlobal = () => useContext(ThemeGlobalSimple) + /** * 基础布局 * @@ -40,8 +44,10 @@ const BlogListPage = dynamic(() => import('./components/BlogListPage'), { ssr: f const LayoutBase = props => { const { children, slotTop, meta } = props const { onLoading, fullWidth } = useGlobal() + const searchModal = useRef(null) return ( + <ThemeGlobalSimple.Provider value={{ searchModal }}> <div id='theme-simple' className='min-h-screen flex flex-col dark:text-gray-300 bg-white dark:bg-black'> {/* SEO相关 */} <CommonHead meta={meta}/> @@ -88,9 +94,13 @@ const LayoutBase = props => { <JumpToTopButton /> </div> + {/* 搜索框 */} + <AlgoliaSearchModal cRef={searchModal} {...props}/> + <Footer {...props} /> </div> + </ThemeGlobalSimple.Provider> ) } @@ -138,7 +148,9 @@ const LayoutSearch = props => { } }, []) - return <LayoutPostList {...props} slotTop={<SearchInput {...props} />} /> + const slotTop = siteConfig('ALGOLIA_APP_ID') ? null : <SearchInput {...props} /> + + return <LayoutPostList {...props} slotTop={slotTop} /> } /** From c6370470b6f09be6d7d13a8185b20abd2b85884a Mon Sep 17 00:00:00 2001 From: Rylan <1217013295@qq.com> Date: Fri, 12 Jan 2024 05:37:11 +0800 Subject: [PATCH 22/53] =?UTF-8?q?=F0=9F=90=9B=20Twikoo=20+=20Utterances=20?= =?UTF-8?q?=E8=AF=84=E8=AE=BA=E6=8F=92=E4=BB=B6=E8=A1=A5=E4=B8=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Utterances.js | 61 +++++++++++++++++++++++++++------------- styles/globals.css | 5 ++++ 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/components/Utterances.js b/components/Utterances.js index 3524c646..34c4f09c 100644 --- a/components/Utterances.js +++ b/components/Utterances.js @@ -1,5 +1,6 @@ +import { useEffect, useState } from 'react' import { siteConfig } from '@/lib/config' -import { useEffect } from 'react' +import { useGlobal } from '@/lib/global' /** * 评论插件 @@ -9,28 +10,48 @@ import { useEffect } from 'react' * @constructor */ const Utterances = ({ issueTerm, layout }) => { + const { isDarkMode } = useGlobal() + + const [isLoading, setLoading] = useState(true); + useEffect(() => { - const theme = - siteConfig('APPEARANCE') === 'auto' - ? 'preferred-color-scheme' - : siteConfig('APPEARANCE') === 'light' - ? 'github-light' - : 'github-dark' - const script = document.createElement('script') - const anchor = document.getElementById('comments') - script.setAttribute('src', 'https://utteranc.es/client.js') - script.setAttribute('crossorigin', 'anonymous') - script.setAttribute('async', true) - script.setAttribute('repo', siteConfig('COMMENT_UTTERRANCES_REPO')) - script.setAttribute('issue-term', 'title') - script.setAttribute('theme', theme) - anchor.appendChild(script) + const script = document.createElement('script'); + const anchor = document.getElementById('comments'); + script.onload = () => setLoading(false); + script.setAttribute('src', 'https://utteranc.es/client.js'); + script.setAttribute('crossorigin', 'anonymous'); + script.setAttribute('async', true); + script.setAttribute('repo', siteConfig('COMMENT_UTTERRANCES_REPO')); + script.setAttribute('issue-term', 'title'); + // 初始主题 + script.setAttribute('theme', isDarkMode ? 'github-dark' : 'github-light'); + anchor.appendChild(script); + return () => { - anchor.innerHTML = '' + // anchor.innerHTML = '' + }; + }, []); + + useEffect(() => { + // 直接设置 iframe 的类来改变主题,不重新加载脚本 + const iframe = document.querySelector('iframe.utterances-frame'); + if (iframe) { + iframe.contentWindow.postMessage({ + type: 'set-theme', + theme: isDarkMode ? 'github-dark' : 'github-light' + }, 'https://utteranc.es'); } - }) - return <div id="comments" className='utterances' > - </div> + }, [isDarkMode]); + + return ( + <div id="comments" className='utterances'> + {isLoading && ( + <div className="flex justify-center items-center m-8"> + <div className="animate-spin rounded-full h-8 w-8 border-2 border-indigo-400 border-t-transparent"></div> + </div> + )} + </div> + ); } export default Utterances diff --git a/styles/globals.css b/styles/globals.css index 67644891..65057e3e 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -160,6 +160,11 @@ nav { @apply text-blue-700 } +/* twikoo 内置的 element-ui 加载样式 */ +.el-loading-spinner { + @apply flex justify-center items-center; +} + /* Webmention style */ .webmention-block { background: rgba(0, 116, 222, .2); From c541a838876899548e4100e2a0a94f7fbd7cbca5 Mon Sep 17 00:00:00 2001 From: Rylan <1217013295@qq.com> Date: Fri, 12 Jan 2024 08:20:49 +0800 Subject: [PATCH 23/53] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Tabs=20=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E4=BC=98=E5=8C=96=E8=A1=A5=E4=B8=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Tabs.js | 82 +++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 52 deletions(-) diff --git a/components/Tabs.js b/components/Tabs.js index 6f08aada..eb1e2e69 100644 --- a/components/Tabs.js +++ b/components/Tabs.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import { useState } from 'react'; /** * Tabs切换标签 @@ -6,59 +6,37 @@ import React, { useState } from 'react' * @returns */ const Tabs = ({ className, children }) => { - const [currentTab, setCurrentTab] = useState(0) + const [currentTab, setCurrentTab] = useState(0); - if (!children) { - return <></> + const validChildren = children.filter(c => c); + + if (validChildren.length === 0) { + return <></>; } - children = children.filter(c => c && c !== '') - - let count = 0 - children.forEach(e => { - if (e) { - count++ - } - }) - - if (count === 0) { - return <></> - } - - if (count === 1) { - return <section className={'duration-200 ' + className}> - {children} - </section> - } - - function tabClickHandle(i) { - setCurrentTab(i) - } - - return <div className={'mb-5 duration-200 ' + className}> - <ul className='flex justify-center space-x-5 pb-4 dark:text-gray-400 text-gray-600 overflow-auto'> - {children.map((item, index) => { - return <li key={index} - className={(currentTab === index ? 'font-black border-b-2 border-red-600 text-red-600 animate__animated animate__jello ' : 'font-extralight cursor-pointer') + ' text-sm font-sans '} - onClick={() => { - tabClickHandle(index) - }}> - {item?.key} - </li> - })} - </ul> - <div> - {children.map((item, index) => { - return <section key={index} - data-aos="fade-up" - data-aos-duration="300" - data-aos-once="true" - data-aos-anchor-placement="top-bottom"> - {currentTab === index && item} - </section> - })} - </div> + return ( + <div className={`mb-5 duration-200 ${className}`}> + <ul className="flex justify-center space-x-5 pb-4 dark:text-gray-400 text-gray-600 overflow-auto"> + {validChildren.map((item, index) => ( + <li key={index} + className={`${currentTab === index ? 'font-black border-b-2 border-red-600 text-red-600 animate__animated animate__jello' : 'font-extralight cursor-pointer'} text-sm font-sans`} + onClick={() => setCurrentTab(index)}> + {item.key} + </li> + ))} + </ul> + {/* 标签切换的时候不销毁 DOM 元素,使用 CSS 样式进行隐藏 */} + <div> + {validChildren.map((item, index) => ( + <section + key={index} + className={`${currentTab === index ? 'opacity-100 static h-auto' : 'opacity-0 absolute h-0'}`}> + {item} + </section> + ))} + </div> </div> -} + ); +}; -export default Tabs +export default Tabs; From daf57bcadff75240e3a454f396836e324d37c2cd Mon Sep 17 00:00:00 2001 From: ShH Y <74806550+1208nn@users.noreply.github.com> Date: Sat, 13 Jan 2024 09:21:22 +0800 Subject: [PATCH 24/53] =?UTF-8?q?=E5=8D=95=E7=8B=AC=E7=9A=84=E7=AB=99?= =?UTF-8?q?=E7=82=B9=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- blog.config.js | 1 + components/CustomContextMenu.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/blog.config.js b/blog.config.js index 11a7cf52..4e874cac 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'] diff --git a/components/CustomContextMenu.js b/components/CustomContextMenu.js index 06c5e7b8..bf396d39 100644 --- a/components/CustomContextMenu.js +++ b/components/CustomContextMenu.js @@ -162,7 +162,7 @@ export default function CustomContextMenu(props) { {isDarkMode ? <i className="fa-regular fa-sun mr-2" /> : <i className="fa-regular fa-moon mr-2" />} <div className='whitespace-nowrap'> {isDarkMode ? locale.MENU.LIGHT_MODE : locale.MENU.DARK_MODE}</div> </div> - {siteConfig('THEME_SWITCH') && ( + {siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH') && ( <div onClick={handeChangeTheme} title={locale.MENU.THEME_SWITCH} className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'> <i className="fa-solid fa-palette mr-2" /> <div className='whitespace-nowrap'>{locale.MENU.THEME_SWITCH}</div> From a0728015cc5645a94ed5f5223584ff8f9d236f6c Mon Sep 17 00:00:00 2001 From: Phillweston <2436559745@qq.com> Date: Sun, 14 Jan 2024 20:23:11 +0800 Subject: [PATCH 25/53] Correct Spelling --- themes/landing/components/Header.js | 4 ++-- themes/landing/components/MobileMenu.js | 4 ++-- themes/landing/config.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/themes/landing/components/Header.js b/themes/landing/components/Header.js index 897ae3a4..2b0540ff 100644 --- a/themes/landing/components/Header.js +++ b/themes/landing/components/Header.js @@ -36,12 +36,12 @@ export default function Header() { {/* Desktop sign in links */} <ul className="flex grow justify-end flex-wrap items-center"> <li> - <Link href={siteConfig('LANDING_HEDEAR_BUTTON_1_URL', null, CONFIG)} target='_blank' className="font-medium hover:font-bold text-gray-600 hover:text-gray-900 px-5 py-3 flex items-center transition duration-150 ease-in-out"> + <Link href={siteConfig('LANDING_HEADER_BUTTON_1_URL', null, CONFIG)} target='_blank' className="font-medium hover:font-bold text-gray-600 hover:text-gray-900 px-5 py-3 flex items-center transition duration-150 ease-in-out"> <div>{siteConfig('LANDING_HEADER_BUTTON_1_TITLE', null, CONFIG)}</div> </Link> </li> <li> - <Link href={siteConfig('LANDING_HEDEAR_BUTTON_2_URL', null, CONFIG)} target='_blank' className="btn-sm text-gray-200 bg-gray-900 hover:bg-gray-800 ml-3"> + <Link href={siteConfig('LANDING_HEADER_BUTTON_2_URL', null, CONFIG)} target='_blank' className="btn-sm text-gray-200 bg-gray-900 hover:bg-gray-800 ml-3"> <span>{siteConfig('LANDING_HEADER_BUTTON_2_TITLE', null, CONFIG)}</span> <svg className="w-3 h-3 fill-current text-gray-400 shrink-0 ml-2 -mr-1" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"> <path d="M11.707 5.293L7 .586 5.586 2l3 3H0v2h8.586l-3 3L7 11.414l4.707-4.707a1 1 0 000-1.414z" fillRule="nonzero" /> diff --git a/themes/landing/components/MobileMenu.js b/themes/landing/components/MobileMenu.js index 3384f6b0..c61e325b 100644 --- a/themes/landing/components/MobileMenu.js +++ b/themes/landing/components/MobileMenu.js @@ -67,12 +67,12 @@ export default function MobileMenu() { > <ul className="px-5 py-2"> <li> - <Link href={siteConfig('LANDING_HEDEAR_BUTTON_1_URL', null, CONFIG)} className="flex font-medium w-full text-gray-600 hover:text-gray-900 py-2 justify-center" onClick={() => setMobileNavOpen(false)}> + <Link href={siteConfig('LANDING_HEADER_BUTTON_1_URL', null, CONFIG)} className="flex font-medium w-full text-gray-600 hover:text-gray-900 py-2 justify-center" onClick={() => setMobileNavOpen(false)}> <div>{siteConfig('LANDING_HEADER_BUTTON_1_TITLE', null, CONFIG)}</div> </Link> </li> <li> - <Link href={siteConfig('LANDING_HEDEAR_BUTTON_2_URL', null, CONFIG)} className="btn-sm text-gray-200 bg-gray-900 hover:bg-gray-800 w-full my-2" onClick={() => setMobileNavOpen(false)}> + <Link href={siteConfig('LANDING_HEADER_BUTTON_2_URL', null, CONFIG)} className="btn-sm text-gray-200 bg-gray-900 hover:bg-gray-800 w-full my-2" onClick={() => setMobileNavOpen(false)}> <span>{siteConfig('LANDING_HEADER_BUTTON_2_TITLE', null, CONFIG)}</span> <svg className="w-3 h-3 fill-current text-gray-400 shrink-0 ml-2 -mr-1" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"> <path d="M11.707 5.293L7 .586 5.586 2l3 3H0v2h8.586l-3 3L7 11.414l4.707-4.707a1 1 0 000-1.414z" fill="#999" fillRule="nonzero" /> diff --git a/themes/landing/config.js b/themes/landing/config.js index 19569d66..09a20b26 100644 --- a/themes/landing/config.js +++ b/themes/landing/config.js @@ -1,10 +1,10 @@ const CONFIG = { LANDING_HEADER_BUTTON_1_TITLE: 'Github开源', - LANDING_HEDEAR_BUTTON_1_URL: 'https://github.com/tangly1024/NotionNext', + LANDING_HEADER_BUTTON_1_URL: 'https://github.com/tangly1024/NotionNext', LANDING_HEADER_BUTTON_2_TITLE: '作者博客', - LANDING_HEDEAR_BUTTON_2_URL: 'https://blog.tangly1024.com/', + LANDING_HEADER_BUTTON_2_URL: 'https://blog.tangly1024.com/', // 首页大图英雄板块 LANDING_HERO_TITLE_1: 'NotionNext', From a7442831c5761de8ec20e2c0b41364ab6ae311f9 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Wed, 17 Jan 2024 16:18:38 +0800 Subject: [PATCH 26/53] 4.1.5 --- .env.local | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.local b/.env.local index 8a1867eb..7e662cb0 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.4 +NEXT_PUBLIC_VERSION=4.1.5 # 可在此添加环境变量,去掉最左边的(# )注释即可 diff --git a/package.json b/package.json index a521b97f..d53f7c20 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "notion-next", - "version": "4.1.4", + "version": "4.1.5", "homepage": "https://github.com/tangly1024/NotionNext.git", "license": "MIT", "repository": { From efcb177b8d437c7005ed2cb289b9ba0180d62713 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Thu, 18 Jan 2024 19:08:54 +0800 Subject: [PATCH 27/53] =?UTF-8?q?heo=20=E4=B8=BB=E9=A2=98=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E9=85=8D=E7=BD=AE=E5=B7=A6=E5=8F=B3=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E9=A2=A0=E5=80=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/heo/components/Hero.js | 8 +++++++- themes/heo/config.js | 5 +++++ themes/heo/index.js | 7 ++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/themes/heo/components/Hero.js b/themes/heo/components/Hero.js index 3f2ddbf1..23edfc8b 100644 --- a/themes/heo/components/Hero.js +++ b/themes/heo/components/Hero.js @@ -15,6 +15,7 @@ import CONFIG from '../config' * @returns */ const Hero = props => { + const HEO_HERO_REVERSE = siteConfig('HEO_HERO_REVERSE', false, CONFIG) return ( <div id="hero-wrapper" @@ -24,12 +25,17 @@ const Hero = props => { id="hero" style={{ zIndex: 1 }} className={ - 'animate__animated animate__fadeIn animate__fast recent-post-top rounded-[12px] 2xl:px-5 recent-top-post-group max-w-[86rem] overflow-x-scroll w-full mx-auto flex-row flex-nowrap flex xl:space-x-3 relative' + `animate__animated animate__fadeIn animate__fast + ${HEO_HERO_REVERSE ? 'xl:flex-row-reverse' : ''} + recent-post-top rounded-[12px] 2xl:px-5 recent-top-post-group max-w-[86rem] overflow-x-scroll w-full mx-auto flex-row flex-nowrap flex relative` } > {/* 左侧banner组 */} <BannerGroup {...props} /> + {/* 中间留白 */} + <div className='px-1.5 h-full'></div> + {/* 右侧置顶文章组 */} <TopGroup {...props} /> </div> diff --git a/themes/heo/config.js b/themes/heo/config.js index ee24656c..c8e730ea 100644 --- a/themes/heo/config.js +++ b/themes/heo/config.js @@ -9,6 +9,11 @@ const CONFIG = { { title: '访问文档中心获取更多帮助', url: 'https://docs.tangly1024.com' } ], + // 英雄区左右侧组件颠倒位置 + HEO_HERO_REVERSE: false, + // 博客主体区左右侧组件颠倒位置 + HEO_HERO_BODY_REVERSE: false, + // 英雄区(首页顶部大卡) HEO_HERO_TITLE_1: '分享编程', HEO_HERO_TITLE_2: '与思维认知', diff --git a/themes/heo/index.js b/themes/heo/index.js index d127a021..30a7eef1 100644 --- a/themes/heo/index.js +++ b/themes/heo/index.js @@ -61,6 +61,8 @@ const LayoutBase = props => { const { fullWidth } = useGlobal() const maxWidth = fullWidth ? 'max-w-[96rem] mx-auto' : 'max-w-[86rem]' // 普通最大宽度是86rem和顶部菜单栏对齐,留空则与窗口对齐 + const HEO_HERO_BODY_REVERSE = siteConfig('HEO_HERO_BODY_REVERSE', false, CONFIG) + return ( <div id="theme-heo" @@ -81,7 +83,7 @@ const LayoutBase = props => { <div id="container-inner" className={ - 'w-full mx-auto lg:flex lg:space-x-4 justify-center relative z-10' + `${HEO_HERO_BODY_REVERSE ? 'flex-row-reverse' : ''} w-full mx-auto lg:flex justify-center relative z-10` } > <div className={`w-full h-auto ${className || ''}`}> @@ -90,11 +92,14 @@ const LayoutBase = props => { {children} </div> + <div className='lg:px-2'></div> + <div className="hidden xl:block"> {/* 主区快右侧 */} {slotRight} </div> </div> + </main> {/* 页脚 */} From a7d901ac17d0f4c3aa16d9e71afc9493add8e7cd Mon Sep 17 00:00:00 2001 From: ShH Y <74806550+1208nn@users.noreply.github.com> Date: Sat, 20 Jan 2024 21:12:53 +0800 Subject: [PATCH 28/53] =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=9A=90=E8=97=8F?= =?UTF-8?q?=E5=8D=95=E7=8B=AC=E7=9A=84=E8=AF=84=E8=AE=BA=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- blog.config.js | 2 ++ components/Tabs.js | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/blog.config.js b/blog.config.js index 699e0962..d0b99cc8 100644 --- a/blog.config.js +++ b/blog.config.js @@ -239,6 +239,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 diff --git a/components/Tabs.js b/components/Tabs.js index eb1e2e69..08b86099 100644 --- a/components/Tabs.js +++ b/components/Tabs.js @@ -16,15 +16,17 @@ const Tabs = ({ className, children }) => { return ( <div className={`mb-5 duration-200 ${className}`}> - <ul className="flex justify-center space-x-5 pb-4 dark:text-gray-400 text-gray-600 overflow-auto"> - {validChildren.map((item, index) => ( - <li key={index} - className={`${currentTab === index ? 'font-black border-b-2 border-red-600 text-red-600 animate__animated animate__jello' : 'font-extralight cursor-pointer'} text-sm font-sans`} - onClick={() => setCurrentTab(index)}> - {item.key} - </li> - ))} - </ul> + {(validChildren.length === 1 && siteConfig('COMMENT_HIDE_SINGLE_TAB')) && ( + <ul className="flex justify-center space-x-5 pb-4 dark:text-gray-400 text-gray-600 overflow-auto"> + {validChildren.map((item, index) => ( + <li key={index} + className={`${currentTab === index ? 'font-black border-b-2 border-red-600 text-red-600 animate__animated animate__jello' : 'font-extralight cursor-pointer'} text-sm font-sans`} + onClick={() => setCurrentTab(index)}> + {item.key} + </li> + ))} + </ul> + )} {/* 标签切换的时候不销毁 DOM 元素,使用 CSS 样式进行隐藏 */} <div> {validChildren.map((item, index) => ( From 94d90890c54bc4ffdf47cc72ac91e3a46b562d27 Mon Sep 17 00:00:00 2001 From: ShH Y <74806550+1208nn@users.noreply.github.com> Date: Sat, 20 Jan 2024 21:18:31 +0800 Subject: [PATCH 29/53] fix dependency --- components/Tabs.js | 1 + 1 file changed, 1 insertion(+) diff --git a/components/Tabs.js b/components/Tabs.js index 08b86099..acebf7e5 100644 --- a/components/Tabs.js +++ b/components/Tabs.js @@ -1,4 +1,5 @@ import { useState } from 'react'; +import { siteConfig } from '@/lib/config' /** * Tabs切换标签 From 55e6619113b4554323913726a5671406648dd6b2 Mon Sep 17 00:00:00 2001 From: ShH Y <74806550+1208nn@users.noreply.github.com> Date: Sat, 20 Jan 2024 21:38:50 +0800 Subject: [PATCH 30/53] =?UTF-8?q?fix=20=E5=8F=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Tabs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Tabs.js b/components/Tabs.js index acebf7e5..37766c24 100644 --- a/components/Tabs.js +++ b/components/Tabs.js @@ -17,7 +17,7 @@ const Tabs = ({ className, children }) => { return ( <div className={`mb-5 duration-200 ${className}`}> - {(validChildren.length === 1 && siteConfig('COMMENT_HIDE_SINGLE_TAB')) && ( + {!(validChildren.length === 1 && siteConfig('COMMENT_HIDE_SINGLE_TAB')) && ( <ul className="flex justify-center space-x-5 pb-4 dark:text-gray-400 text-gray-600 overflow-auto"> {validChildren.map((item, index) => ( <li key={index} From e7453b054ed3887993d3c4e634e6df68ff38c344 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sun, 21 Jan 2024 11:56:38 +0800 Subject: [PATCH 31/53] TianliGPT --- blog.config.js | 5 +++++ components/Artalk.js | 4 +--- components/ExternalPlugins.js | 3 +++ components/TianliGPT.js | 41 +++++++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 components/TianliGPT.js diff --git a/blog.config.js b/blog.config.js index 699e0962..29bc46f6 100644 --- a/blog.config.js +++ b/blog.config.js @@ -185,6 +185,11 @@ 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 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/ExternalPlugins.js b/components/ExternalPlugins.js index bbfba4f3..0ec4e0d9 100644 --- a/components/ExternalPlugins.js +++ b/components/ExternalPlugins.js @@ -2,6 +2,7 @@ import { siteConfig } from '@/lib/config' import dynamic from 'next/dynamic' import LA51 from './LA51' import WebWhiz from './Webwhiz' +import TianLiGPT from './TianliGPT' const TwikooCommentCounter = dynamic(() => import('@/components/TwikooCommentCounter'), { ssr: false }) const DebugPanel = dynamic(() => import('@/components/DebugPanel'), { ssr: false }) @@ -71,6 +72,7 @@ const ExternalPlugin = (props) => { 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') if (DISABLE_PLUGIN) { return null @@ -98,6 +100,7 @@ const ExternalPlugin = (props) => { {!CAN_COPY && <DisableCopy />} {WEB_WHIZ_ENABLED && <WebWhiz />} {AD_WWADS_BLOCK_DETECT && <AdBlockDetect />} + {TIANLI_KEY && <TianLiGPT/>} <VConsole /> <LoadingProgress /> <AosAnimation /> diff --git a/components/TianliGPT.js b/components/TianliGPT.js new file mode 100644 index 00000000..e90259a2 --- /dev/null +++ b/components/TianliGPT.js @@ -0,0 +1,41 @@ +/* eslint-disable no-unused-vars */ +/* eslint-disable camelcase */ +import { siteConfig } from '@/lib/config' +import { loadExternalResource } from '@/lib/utils' +import { useEffect } from 'react' +/** + * TianliGpt AI文章摘要生成工具 @see https://docs_s.tianli0.top/ + * @returns {JSX.Element} + * @constructor + */ + +const TianLiGPT = () => { + const tianliKey = siteConfig('TianliGPT_KEY') + const tianliCss = siteConfig('TianliGPT_CSS') + const tianliJs = siteConfig('TianliGPT_JS') + + useEffect(() => { + initArtalk() + }, []) + + if (!tianliKey) { + return null + } + + const initArtalk = async () => { + console.log('loading tianliGPT', tianliKey, tianliCss, tianliJs) + + if (!tianliKey) { + return + } + await loadExternalResource(tianliCss, 'css') + + window.tianliGPT_postSelector = '#notion-article'; + window.tianliGPT_key = 'f50e6b018a094fbb0d7c'; + + await loadExternalResource(tianliJs, 'js') + } + return <></> +} + +export default TianLiGPT From 1d7a4342eb1f2c9d885c1d40cd9cc1a387261db3 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sun, 21 Jan 2024 12:05:26 +0800 Subject: [PATCH 32/53] fix --- components/TianliGPT.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/TianliGPT.js b/components/TianliGPT.js index e90259a2..07aa2db6 100644 --- a/components/TianliGPT.js +++ b/components/TianliGPT.js @@ -31,7 +31,7 @@ const TianLiGPT = () => { await loadExternalResource(tianliCss, 'css') window.tianliGPT_postSelector = '#notion-article'; - window.tianliGPT_key = 'f50e6b018a094fbb0d7c'; + window.tianliGPT_key = tianliKey; await loadExternalResource(tianliJs, 'js') } From 93be76e00838962eb5bb5ba58378ab217628d2e0 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sun, 21 Jan 2024 20:12:57 +0800 Subject: [PATCH 33/53] =?UTF-8?q?GlobalJS=EF=BC=8CGlobalStyle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/ExternalPlugins.js | 41 +++++++++++++++++++++++++++++++++++ components/GlobalStyle.js | 20 +++++++++++++++++ lib/cache/cache_manager.js | 4 ++-- pages/_app.js | 30 +------------------------ 4 files changed, 64 insertions(+), 31 deletions(-) create mode 100644 components/GlobalStyle.js diff --git a/components/ExternalPlugins.js b/components/ExternalPlugins.js index 0ec4e0d9..77433f97 100644 --- a/components/ExternalPlugins.js +++ b/components/ExternalPlugins.js @@ -3,6 +3,10 @@ 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 }) @@ -73,12 +77,44 @@ const ExternalPlugin = (props) => { 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') + + // 自定义样式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 <> + + {/* 全局样式嵌入 */} + <GlobalStyle/> + {THEME_SWITCH && <ThemeSwitch />} {DEBUG && <DebugPanel />} {ANALYTICS_ACKEE_TRACKER && <Ackee />} @@ -115,6 +151,11 @@ const ExternalPlugin = (props) => { }} /> */} </>)} + {/* 注入JS脚本 */} + {GLOBAL_JS && <script async dangerouslySetInnerHTML={{ + __html: GLOBAL_JS + }} />} + {CHATBASE_ID && (<> <script id={CHATBASE_ID} src="https://www.chatbase.co/embed.min.js" defer /> <script async dangerouslySetInnerHTML={{ diff --git a/components/GlobalStyle.js b/components/GlobalStyle.js new file mode 100644 index 00000000..2bb80746 --- /dev/null +++ b/components/GlobalStyle.js @@ -0,0 +1,20 @@ +/* eslint-disable react/no-unknown-property */ + +import { siteConfig } from '@/lib/config' + +/** + * 这里的css样式对全局生效 + * 主题客制化css + * @returns + */ +const GlobalStyle = () => { + // 从NotionConfig中读取样式 + const GLOBAL_CSS = siteConfig('GLOBAL_CSS') + return (<style jsx global>{` + + ${GLOBAL_CSS} + + `}</style>) +} + +export { GlobalStyle } diff --git a/lib/cache/cache_manager.js b/lib/cache/cache_manager.js index 4928bca9..9103b4b1 100644 --- a/lib/cache/cache_manager.js +++ b/lib/cache/cache_manager.js @@ -9,7 +9,7 @@ import BLOG from '@/blog.config' * @returns */ export async function getDataFromCache(key, force) { - if (BLOG.ENABLE_CACHE || force) { + if (JSON.parse(BLOG.ENABLE_CACHE) || force) { const dataFromCache = await getApi().getCache(key) if (JSON.stringify(dataFromCache) === '[]') { return null @@ -28,7 +28,7 @@ export async function setDataToCache(key, data) { } export async function delCacheData(key) { - if (!BLOG.ENABLE_CACHE) { + if (!JSON.parse(BLOG.ENABLE_CACHE)) { return } await getApi().delCache(key) diff --git a/pages/_app.js b/pages/_app.js index 711f10f6..da9b3efc 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -9,43 +9,15 @@ import '@/styles/notion.css' // 重写部分样式 import 'aos/dist/aos.css' // You can also use <link> for styles import { GlobalContextProvider } from '@/lib/global' -import { isBrowser, loadExternalResource } from '@/lib/utils' // 各种扩展插件 这个要阻塞引入 import ExternalPlugins from '@/components/ExternalPlugins' -import { CUSTOM_EXTERNAL_CSS, CUSTOM_EXTERNAL_JS, IMG_SHADOW } from '@/blog.config' const MyApp = ({ Component, pageProps }) => { - // 自定义样式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') - } - } - } - return ( <GlobalContextProvider {...pageProps}> <Component {...pageProps} /> + {/* 全局插件 , 自定义样式、组件等在这里统一引入 */} <ExternalPlugins {...pageProps} /> </GlobalContextProvider> ) From 9278519b50124a4f580aafebcfc0327943860d08 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sun, 21 Jan 2024 20:56:01 +0800 Subject: [PATCH 34/53] compress-article-image --- lib/notion/getPostBlocks.js | 6 ++- lib/notion/mapImage.js | 88 +++++++++++++++++++------------------ 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/lib/notion/getPostBlocks.js b/lib/notion/getPostBlocks.js index 20c9acab..167f0b0e 100644 --- a/lib/notion/getPostBlocks.js +++ b/lib/notion/getPostBlocks.js @@ -62,8 +62,10 @@ export async function getPageWithRetry(id, from, retryAttempts = 3) { } /** - * 获取到的blockMap删除不需要的字段 - * 并且对于页面内容进行特殊处理,比如文件url格式化 + * 获取到的页面BLOCK特殊处理 + * 1.删除冗余字段 + * 2.比如文件、视频、音频、url格式化 + * 3.代码块等元素兼容 * @param {*} id 页面ID * @param {*} pageBlock 页面元素 * @param {*} slice 截取数量 diff --git a/lib/notion/mapImage.js b/lib/notion/mapImage.js index 7b0e16c2..f03a88e1 100644 --- a/lib/notion/mapImage.js +++ b/lib/notion/mapImage.js @@ -1,45 +1,5 @@ import BLOG from '@/blog.config' -/** - * 压缩图片 - * 1. Notion图床可以通过指定url-query参数来压缩裁剪图片 例如 ?xx=xx&width=400 - * 2. UnPlash 图片可以通过api q=50 控制压缩质量 width=400 控制图片尺寸 - * @param {*} image - */ -const compressImage = (image, width = 800, quality = 50, fmt = 'webp') => { - if (!image) { - return null - } - if (image.indexOf(BLOG.NOTION_HOST) === 0 && image.indexOf('amazonaws.com') > 0) { - return `${image}&width=${width}` - } - // 压缩unsplash图片 - if (image.indexOf('https://images.unsplash.com/') === 0) { - // 将URL解析为一个对象 - const urlObj = new URL(image) - // 获取URL参数 - const params = new URLSearchParams(urlObj.search) - // 将q参数的值替换 - params.set('q', quality) - // 尺寸 - params.set('width', width) - // 格式 - params.set('fmt', fmt) - params.set('fm', fmt) - // 生成新的URL - urlObj.search = params.toString() - return urlObj.toString() - } - - // 此处还可以添加您的自定义图传的封面图压缩参数。 - // .e.g - if (image.indexOf('https://your_picture_bed') === 0) { - return 'do_somethin_here' - } - - return image -} - /** * 图片映射 * 1. 如果是 /xx.xx 相对路径格式,则转化为 完整notion域名图片 @@ -96,9 +56,11 @@ const mapImgUrl = (img, block, type = 'block', from) => { } } - // 文章封面 - if (from === 'pageCoverThumbnail') { - ret = compressImage(ret) + // 文章封面压缩 + if (from === 'pageCoverThumbnail' || block.type === 'image') { + // 统一压缩图片 + const width = block?.format?.block_width + ret = compressImage(ret, width) } return ret @@ -114,4 +76,44 @@ function isEmoji(str) { return emojiRegex.test(str); } +/** + * 压缩图片 + * 1. Notion图床可以通过指定url-query参数来压缩裁剪图片 例如 ?xx=xx&width=400 + * 2. UnPlash 图片可以通过api q=50 控制压缩质量 width=400 控制图片尺寸 + * @param {*} image + */ +const compressImage = (image, width = 800, quality = 50, fmt = 'webp') => { + if (!image) { + return null + } + if (image.indexOf(BLOG.NOTION_HOST) === 0 && image.indexOf('amazonaws.com') > 0) { + return `${image}&width=${width}` + } + // 压缩unsplash图片 + if (image.indexOf('https://images.unsplash.com/') === 0) { + // 将URL解析为一个对象 + const urlObj = new URL(image) + // 获取URL参数 + const params = new URLSearchParams(urlObj.search) + // 将q参数的值替换 + params.set('q', quality) + // 尺寸 + params.set('width', width) + // 格式 + params.set('fmt', fmt) + params.set('fm', fmt) + // 生成新的URL + urlObj.search = params.toString() + return urlObj.toString() + } + + // 此处还可以添加您的自定义图传的封面图压缩参数。 + // .e.g + if (image.indexOf('https://your_picture_bed') === 0) { + return 'do_somethin_here' + } + + return image +} + export { mapImgUrl, compressImage } From 5eddf37be8c6d6dbbf3c70237a8dba1363128bba Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sun, 21 Jan 2024 21:01:18 +0800 Subject: [PATCH 35/53] img-cache --- lib/notion/mapImage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/notion/mapImage.js b/lib/notion/mapImage.js index f03a88e1..c0711e6a 100644 --- a/lib/notion/mapImage.js +++ b/lib/notion/mapImage.js @@ -87,7 +87,7 @@ const compressImage = (image, width = 800, quality = 50, fmt = 'webp') => { return null } if (image.indexOf(BLOG.NOTION_HOST) === 0 && image.indexOf('amazonaws.com') > 0) { - return `${image}&width=${width}` + return `${image}&width=${width}&cache=v2` } // 压缩unsplash图片 if (image.indexOf('https://images.unsplash.com/') === 0) { From 259410480fba55b50dc995109844b5d75e9639f7 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sun, 21 Jan 2024 21:03:13 +0800 Subject: [PATCH 36/53] 4.2.0 --- .env.local | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.local b/.env.local index 7e662cb0..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.5 +NEXT_PUBLIC_VERSION=4.2.0 # 可在此添加环境变量,去掉最左边的(# )注释即可 diff --git a/package.json b/package.json index d53f7c20..776d6932 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "notion-next", - "version": "4.1.5", + "version": "4.2.0", "homepage": "https://github.com/tangly1024/NotionNext.git", "license": "MIT", "repository": { From ccf861bb67800e3105e2f0f39bda3af537a5bb1c Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Mon, 22 Jan 2024 21:00:12 +0800 Subject: [PATCH 37/53] =?UTF-8?q?next=E4=B8=BB=E9=A2=98=EF=BC=8C=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E6=A0=87=E7=AD=BE=E6=95=B0=E9=87=8F=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/next/components/CategoryGroup.js | 7 +++++-- themes/next/components/TagGroups.js | 8 ++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/themes/next/components/CategoryGroup.js b/themes/next/components/CategoryGroup.js index 872c4a28..c00b5d1c 100644 --- a/themes/next/components/CategoryGroup.js +++ b/themes/next/components/CategoryGroup.js @@ -1,10 +1,13 @@ +import { siteConfig } from '@/lib/config' import Link from 'next/link' const CategoryGroup = ({ currentCategory, categories }) => { - if (!categories) return <></> + if (!categories || categories.length === 0) return <></> + const categoryCount = siteConfig('PREVIEW_CATEGORY_COUNT') + const categoryOptions = categories.slice(0, categoryCount) return <> <div id='category-list' className='dark:border-gray-600 flex flex-wrap'> - {categories.map(category => { + {categoryOptions.map(category => { const selected = currentCategory === category.name return ( <Link diff --git a/themes/next/components/TagGroups.js b/themes/next/components/TagGroups.js index 1a406ed3..42efafab 100644 --- a/themes/next/components/TagGroups.js +++ b/themes/next/components/TagGroups.js @@ -1,3 +1,4 @@ +import { siteConfig } from '@/lib/config' import TagItemMini from './TagItemMini' /** @@ -8,11 +9,14 @@ import TagItemMini from './TagItemMini' * @constructor */ const TagGroups = ({ tags, currentTag }) => { - if (!tags) return <></> + if (!tags || tags.length === 0) return <></> + + const tagsCount = siteConfig('PREVIEW_TAG_COUNT') + const tagOptions = tags.slice(0, tagsCount) return ( <div id='tags-group' className='dark:border-gray-600 w-66 space-y-2'> { - tags.map(tag => { + tagOptions.map(tag => { const selected = tag.name === currentTag return <TagItemMini key={tag.name} tag={tag} selected={selected} /> }) From fc7d14db74cc1d03de9ba1c25ce3dc3835dfed54 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Wed, 24 Jan 2024 17:36:26 +0800 Subject: [PATCH 38/53] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B9=A6=E7=AD=BE?= =?UTF-8?q?=E9=A2=84=E8=A7=88=E5=9B=BE=E6=97=A0=E6=B3=95=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/notion/mapImage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/notion/mapImage.js b/lib/notion/mapImage.js index c0711e6a..dbb785e1 100644 --- a/lib/notion/mapImage.js +++ b/lib/notion/mapImage.js @@ -21,9 +21,9 @@ const mapImgUrl = (img, block, type = 'block', from) => { } // Notion 图床转换为永久地址 - const isNotionImg = ret.indexOf('secure.notion-static.com') > 0 || ret.indexOf('prod-files-secure') > 0 + const isNotionSignImg = ret.indexOf('https://www.notion.so/image') !== 0 && (ret.indexOf('secure.notion-static.com') > 0 || ret.indexOf('prod-files-secure') > 0) const isImgBlock = BLOG.IMG_URL_TYPE === 'Notion' || type !== 'block' - if (isNotionImg && isImgBlock) { + if (isNotionSignImg && isImgBlock) { ret = BLOG.NOTION_HOST + '/image/' + encodeURIComponent(ret) + '?table=' + type + '&id=' + block.id } From e8c5f9be206aa3f32d5377b86a0bf1ed736c2a2b Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Fri, 26 Jan 2024 15:26:20 +0800 Subject: [PATCH 39/53] =?UTF-8?q?hexo=E4=B8=BB=E9=A2=98=E6=94=AF=E6=8C=81A?= =?UTF-8?q?lgolia=E5=85=A8=E6=96=87=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/hexo/components/SearchButton.js | 30 ++++++++++++++++++++++++++ themes/hexo/components/TopNav.js | 7 +++++- themes/hexo/index.js | 16 +++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 themes/hexo/components/SearchButton.js diff --git a/themes/hexo/components/SearchButton.js b/themes/hexo/components/SearchButton.js new file mode 100644 index 00000000..47d1da6f --- /dev/null +++ b/themes/hexo/components/SearchButton.js @@ -0,0 +1,30 @@ +import { siteConfig } from '@/lib/config' +import { useGlobal } from '@/lib/global' +import { useRouter } from 'next/router' +import AlgoliaSearchModal from '@/components/AlgoliaSearchModal' +import { useRef } from 'react' +import { useHexoGlobal } from '..' + +/** + * 搜索按钮 + * @returns + */ +export default function SearchButton(props) { + const { locale } = useGlobal() + const router = useRouter() + const { searchModal} = useHexoGlobal() + + function handleSearch() { + if (siteConfig('ALGOLIA_APP_ID')) { + searchModal.current.openSearch() + } else { + router.push('/search') + } + } + + return <> + <div onClick={handleSearch} title={locale.NAV.SEARCH} alt={locale.NAV.SEARCH} className='cursor-pointer hover:bg-black hover:bg-opacity-10 rounded-full w-10 h-10 flex justify-center items-center duration-200 transition-all'> + <i title={locale.NAV.SEARCH} className="fa-solid fa-magnifying-glass" /> + </div> + </> +} diff --git a/themes/hexo/components/TopNav.js b/themes/hexo/components/TopNav.js index 252ce8a0..8966aa51 100644 --- a/themes/hexo/components/TopNav.js +++ b/themes/hexo/components/TopNav.js @@ -10,6 +10,9 @@ import { useRouter } from 'next/router' import throttle from 'lodash.throttle' import SideBar from './SideBar' import SideBarDrawer from './SideBarDrawer' +import { siteConfig } from '@/lib/config' +import SearchButton from './SearchButton' +import CONFIG from '../config' let windowTop = 0 @@ -26,6 +29,7 @@ const TopNav = props => { const router = useRouter() const [isOpen, changeShow] = useState(false) + const showSearchButton = siteConfig('HEXO_MENU_SEARCH',false,CONFIG) const toggleMenuOpen = () => { changeShow(!isOpen) @@ -140,11 +144,12 @@ const TopNav = props => { </div> {/* 右侧功能 */} - <div className='mr-1 justify-end items-center '> + <div className='mr-1 flex justify-end items-center '> <div className='hidden lg:flex'> <MenuListTop {...props} /></div> <div onClick={toggleMenuOpen} className='w-8 justify-center items-center h-8 cursor-pointer flex lg:hidden'> {isOpen ? <i className='fas fa-times' /> : <i className='fas fa-bars' />} </div> + {showSearchButton && <SearchButton />} </div> </div> </div> diff --git a/themes/hexo/index.js b/themes/hexo/index.js index 4fa0dd62..fc3dace7 100644 --- a/themes/hexo/index.js +++ b/themes/hexo/index.js @@ -1,6 +1,6 @@ import CONFIG from './config' import CommonHead from '@/components/CommonHead' -import { useEffect, useRef } from 'react' +import { createContext, useContext, useEffect, useRef } from 'react' import Footer from './components/Footer' import SideRight from './components/SideRight' import TopNav from './components/TopNav' @@ -32,6 +32,12 @@ import { Transition } from '@headlessui/react' import { Style } from './style' import replaceSearchResult from '@/components/Mark' import { siteConfig } from '@/lib/config' +import AlgoliaSearchModal from '@/components/AlgoliaSearchModal' + + +// 主题全局状态 +const ThemeGlobalHexo = createContext() +export const useHexoGlobal = () => useContext(ThemeGlobalHexo) /** * 基础布局 采用左右两侧布局,移动端使用顶部导航栏 @@ -42,8 +48,12 @@ import { siteConfig } from '@/lib/config' const LayoutBase = props => { const { children, headerSlot, floatSlot, slotTop, meta, className } = props const { onLoading, fullWidth } = useGlobal() + + // Algolia搜索框 + const searchModal = useRef(null) return ( + <ThemeGlobalHexo.Provider value={{ searchModal }}> <div id='theme-hexo'> {/* 网页SEO */} <CommonHead meta={meta}/> @@ -98,9 +108,13 @@ const LayoutBase = props => { {/* 悬浮菜单 */} <RightFloatArea floatSlot={floatSlot} /> + {/* 全文搜索 */} + <AlgoliaSearchModal cRef={searchModal} {...props}/> + {/* 页脚 */} <Footer title={siteConfig('TITLE') } /> </div> + </ThemeGlobalHexo.Provider> ) } From ac661b23d5afb9093f573e694a0814f6ba9ba1cd Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Fri, 26 Jan 2024 15:27:29 +0800 Subject: [PATCH 40/53] =?UTF-8?q?Tabs=E7=BB=84=E4=BB=B6=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E7=9A=84=E9=A1=B5=E9=9D=A2=E5=87=BA=E7=8E=B0=E9=9A=90=E8=97=8F?= =?UTF-8?q?=E7=9A=84=E5=8F=AF=E7=82=B9=E5=87=BB=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Tabs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Tabs.js b/components/Tabs.js index 37766c24..b7f4590b 100644 --- a/components/Tabs.js +++ b/components/Tabs.js @@ -33,7 +33,7 @@ const Tabs = ({ className, children }) => { {validChildren.map((item, index) => ( <section key={index} - className={`${currentTab === index ? 'opacity-100 static h-auto' : 'opacity-0 absolute h-0'}`}> + className={`${currentTab === index ? 'opacity-100 static h-auto' : 'opacity-0 absolute h-0 pointer-events-none'}`}> {item} </section> ))} From 849e0431030791c43fa30bf2ecd6ae12add2140e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=91=89=E4=BF=AE=E9=BD=8A?= <54578647+siuze@users.noreply.github.com> Date: Fri, 26 Jan 2024 21:59:33 +0800 Subject: [PATCH 41/53] =?UTF-8?q?fix=20bug:=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93type=E5=AD=97=E6=AE=B5=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E5=90=8E=E6=97=A0=E6=B3=95=E6=AD=A3=E7=A1=AE=E7=94=9F?= =?UTF-8?q?=E6=88=90=E6=9C=AA=E6=98=BE=E5=BC=8F=E5=AE=9A=E4=B9=89slug?= =?UTF-8?q?=E7=9A=84=E6=96=87=E7=AB=A0=E7=9A=84=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 处理URL之前已经调用过mapProperties(properties),使得字段属性值恢复到标准的英文了,不应当再与自定义配置值进行比对 --- lib/notion/getPageProperties.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js index 3ea1ce28..aca92b25 100644 --- a/lib/notion/getPageProperties.js +++ b/lib/notion/getPageProperties.js @@ -101,11 +101,11 @@ export default async function getPageProperties(id, block, schema, authToken, ta delete properties.content // 处理URL - if (properties.type === BLOG.NOTION_PROPERTY_NAME.type_post) { + if (properties.type === 'Post') { properties.slug = (BLOG.POST_URL_PREFIX) ? generateCustomizeUrl(properties) : (properties.slug ?? properties.id) - } else if (properties.type === BLOG.NOTION_PROPERTY_NAME.type_page) { + } else if (properties.type === 'Page') { properties.slug = properties.slug ?? properties.id - } else if (properties.type === BLOG.NOTION_PROPERTY_NAME.type_menu || properties.type === BLOG.NOTION_PROPERTY_NAME.type_sub_menu) { + } else if (properties.type === 'Menu' || properties.type === 'SubMenu') { // 菜单路径为空、作为可展开菜单使用 properties.to = properties.slug ?? '#' properties.name = properties.title ?? '' From bc93ccc50f1f6c648609c57827c86fc153cc71e8 Mon Sep 17 00:00:00 2001 From: tangly1024 <mail@tangly1024.com> Date: Sat, 27 Jan 2024 09:42:40 +0800 Subject: [PATCH 42/53] =?UTF-8?q?Tabs=20=E7=BB=84=E4=BB=B6=E5=BE=AE?= =?UTF-8?q?=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Tabs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Tabs.js b/components/Tabs.js index b7f4590b..ef951228 100644 --- a/components/Tabs.js +++ b/components/Tabs.js @@ -33,7 +33,7 @@ const Tabs = ({ className, children }) => { {validChildren.map((item, index) => ( <section key={index} - className={`${currentTab === index ? 'opacity-100 static h-auto' : 'opacity-0 absolute h-0 pointer-events-none'}`}> + className={`${currentTab === index ? 'opacity-100 static h-auto' : 'opacity-0 absolute h-0 pointer-events-none overflow-hidden'}`}> {item} </section> ))} From 9001edd693076babdd7efdf4cf7f89d1767711a9 Mon Sep 17 00:00:00 2001 From: velor2012 <38395332+velor2012@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:09:27 +0800 Subject: [PATCH 43/53] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/_app.js | 63 ++++++++++++++++++++++++++--- themes/next/index.js | 36 +++++++++-------- themes/simple/components/SideBar.js | 5 +++ themes/simple/index.js | 27 +++++++------ themes/theme.js | 18 +++++++++ 5 files changed, 115 insertions(+), 34 deletions(-) diff --git a/pages/_app.js b/pages/_app.js index da9b3efc..463aa454 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -9,17 +9,70 @@ import '@/styles/notion.css' // 重写部分样式 import 'aos/dist/aos.css' // You can also use <link> for styles import { GlobalContextProvider } from '@/lib/global' +import { isBrowser, loadExternalResource } from '@/lib/utils' +import { getGlobalLayoutByTheme } from '@/themes/theme' +import { useRouter } from 'next/router' +import { useCallback, useMemo } from 'react' +import { getQueryParam } from '../lib/utils' // 各种扩展插件 这个要阻塞引入 import ExternalPlugins from '@/components/ExternalPlugins' +import { CUSTOM_EXTERNAL_CSS, CUSTOM_EXTERNAL_JS, IMG_SHADOW, THEME } from '@/blog.config' const MyApp = ({ Component, pageProps }) => { + /** + * 首页布局 + * @param {*} props + * @returns + */ + const route = useRouter() + const queryParam = useMemo(() => { + return getQueryParam(route.asPath, 'theme') || THEME + }, [route]) + + const GLayout = useCallback( + props => { + // 根据页面路径加载不同Layout文件 + const Layout = getGlobalLayoutByTheme(queryParam) + return <Layout {...props} /> + }, + [queryParam] + ) + + // 自定义样式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') + } + } + } + return ( - <GlobalContextProvider {...pageProps}> - <Component {...pageProps} /> - {/* 全局插件 , 自定义样式、组件等在这里统一引入 */} - <ExternalPlugins {...pageProps} /> - </GlobalContextProvider> + <GlobalContextProvider {...pageProps}> + <GLayout {...pageProps}> + <Component {...pageProps} /> + </GLayout> + <ExternalPlugins {...pageProps} /> + </GlobalContextProvider> ) } diff --git a/themes/next/index.js b/themes/next/index.js index cb702903..9e0b1c4a 100644 --- a/themes/next/index.js +++ b/themes/next/index.js @@ -32,6 +32,7 @@ import { siteConfig } from '@/lib/config' * @returns {JSX.Element} * @constructor */ +let counter = 0 const LayoutBase = (props) => { const { children, headerSlot, floatSlot, rightAreaSlot, meta } = props const { onLoading } = useGlobal() @@ -39,7 +40,9 @@ const LayoutBase = (props) => { const floatButtonGroup = useRef(null) const [showRightFloat, switchShow] = useState(false) const [percent, changePercent] = useState(0) // 页面阅读百分比 - + useEffect(()=>{ + console.log('sidebar 渲染次数: ', counter++) + }, []) const scrollListener = () => { const targetRef = document.getElementById('wrapper') const clientHeight = targetRef?.clientHeight @@ -140,7 +143,7 @@ const LayoutIndex = (props) => { * @returns */ const LayoutPostList = (props) => { - return <LayoutBase {...props} > + return <div {...props} > <BlogListBar {...props} /> @@ -148,7 +151,7 @@ const LayoutPostList = (props) => { ? <BlogPostListScroll {...props} showSummary={true} /> : <BlogPostListPage {...props} /> } - </LayoutBase> + </div> } /** @@ -174,7 +177,7 @@ const LayoutSearch = (props) => { }, []) return ( - <LayoutBase {...props} > + <div {...props} > <StickyBar> <div className="p-4 dark:text-gray-200"> <i className="mr-1 fas fa-search" />{' '} @@ -187,7 +190,7 @@ const LayoutSearch = (props) => { : <BlogPostListPage {...props} /> } </div> - </LayoutBase> + </div> ) } @@ -210,7 +213,7 @@ const Layout404 = props => { }, 3000) }, []) - return <LayoutBase {...props}> + return <div {...props}> <div className='md:-mt-20 text-black w-full h-screen text-center justify-center content-center items-center flex flex-col'> <div className='dark:text-gray-200'> <h2 className='inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top'><i className='mr-2 fas fa-spinner animate-spin' />404</h2> @@ -219,7 +222,7 @@ const Layout404 = props => { </div> </div> </div> - </LayoutBase> + </div> } /** @@ -231,7 +234,7 @@ const LayoutArchive = (props) => { const { archivePosts } = props return ( - <LayoutBase {...props}> + <div {...props}> <div className="mb-10 pb-20 bg-white md:p-12 p-3 dark:bg-hexo-black-gray shadow-md min-h-full"> {Object.keys(archivePosts).map(archiveTitle => ( <BlogPostArchive @@ -241,7 +244,7 @@ const LayoutArchive = (props) => { /> ))} </div> - </LayoutBase> + </div> ) } @@ -261,7 +264,7 @@ const LayoutSlug = (props) => { </div> return ( - <LayoutBase {...props} floatSlot={floatSlot}> + <div {...props} floatSlot={floatSlot}> {post && !lock && <ArticleDetail {...props} />} @@ -272,7 +275,7 @@ const LayoutSlug = (props) => { <TocDrawer post={post} cRef={drawerRight} targetRef={targetRef} /> </div>} - </LayoutBase> + </div> ) } @@ -285,7 +288,7 @@ const LayoutCategoryIndex = (props) => { const { allPosts, categoryOptions } = props const { locale } = useGlobal() return ( - <LayoutBase totalPosts={allPosts} {...props}> + <div totalPosts={allPosts} {...props}> <div className='bg-white dark:bg-hexo-black-gray px-10 py-10 shadow h-full'> <div className='dark:text-gray-200 mb-5'> <i className='mr-4 fas faTh' />{locale.COMMON.CATEGORY}: @@ -307,7 +310,7 @@ const LayoutCategoryIndex = (props) => { })} </div> </div> - </LayoutBase> + </div> ) } @@ -319,7 +322,7 @@ const LayoutCategoryIndex = (props) => { const LayoutTagIndex = (props) => { const { tagOptions } = props const { locale } = useGlobal() - return <LayoutBase {...props}> + return <div {...props}> <div className='bg-white dark:bg-hexo-black-gray px-10 py-10 shadow h-full'> <div className='dark:text-gray-200 mb-5'><i className='fas fa-tags mr-4' />{locale.COMMON.TAGS}:</div> <div id='tags-list' className='duration-200 flex flex-wrap'> @@ -328,11 +331,12 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </LayoutBase> + </div> } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutSearch, LayoutArchive, @@ -340,5 +344,5 @@ export { Layout404, LayoutCategoryIndex, LayoutPostList, - LayoutTagIndex + LayoutTagIndex, } diff --git a/themes/simple/components/SideBar.js b/themes/simple/components/SideBar.js index 6ff2075c..0d17afec 100644 --- a/themes/simple/components/SideBar.js +++ b/themes/simple/components/SideBar.js @@ -2,14 +2,19 @@ import { AdSlot } from '@/components/GoogleAdsense' import Live2D from '@/components/Live2D' import Announcement from './Announcement' import Catalog from './Catalog' +import { useEffect } from 'react' /** * 侧边栏 * @param {*} props * @returns */ +let counter = 0; export default function SideBar (props) { const { notice } = props + useEffect(()=>{ + console.log('sidebar 渲染次数: ', counter++) +}, []) return (<> <aside> diff --git a/themes/simple/index.js b/themes/simple/index.js index 23373190..36e48586 100644 --- a/themes/simple/index.js +++ b/themes/simple/index.js @@ -120,9 +120,9 @@ const LayoutIndex = props => { */ const LayoutPostList = props => { return ( - <LayoutBase {...props}> + <div {...props}> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />} - </LayoutBase> + </div> ) } @@ -161,11 +161,11 @@ const LayoutSearch = props => { const LayoutArchive = props => { const { archivePosts } = props return ( - <LayoutBase {...props}> + <div {...props}> <div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full"> {Object.keys(archivePosts).map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} </div> - </LayoutBase> + </div> ) } @@ -179,7 +179,7 @@ const LayoutSlug = props => { const { fullWidth } = useGlobal() return ( - <LayoutBase {...props}> + <div {...props}> {lock && <ArticleLock validPassword={validPassword} />} @@ -208,7 +208,7 @@ const LayoutSlug = props => { </div> - </LayoutBase> + </div> ) } @@ -218,9 +218,9 @@ const LayoutSlug = props => { * @returns */ const Layout404 = (props) => { - return <LayoutBase {...props}> + return <div {...props}> 404 Not found. - </LayoutBase> + </div> } /** @@ -231,7 +231,7 @@ const Layout404 = (props) => { const LayoutCategoryIndex = props => { const { categoryOptions } = props return ( - <LayoutBase {...props}> + <div {...props}> <div id='category-list' className='duration-200 flex flex-wrap'> {categoryOptions?.map(category => { return ( @@ -248,7 +248,7 @@ const LayoutCategoryIndex = props => { ) })} </div> - </LayoutBase> + </div> ) } @@ -260,7 +260,7 @@ const LayoutCategoryIndex = props => { const LayoutTagIndex = (props) => { const { tagOptions } = props return ( - <LayoutBase {...props}> + <div {...props}> <div id='tags-list' className='duration-200 flex flex-wrap'> {tagOptions.map(tag => { return ( @@ -276,12 +276,13 @@ const LayoutTagIndex = (props) => { ) })} </div> - </LayoutBase> + </div> ) } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutSearch, LayoutArchive, @@ -289,5 +290,5 @@ export { Layout404, LayoutCategoryIndex, LayoutPostList, - LayoutTagIndex + LayoutTagIndex, } diff --git a/themes/theme.js b/themes/theme.js index 360e59a2..9261749e 100644 --- a/themes/theme.js +++ b/themes/theme.js @@ -6,6 +6,22 @@ import getConfig from 'next/config' import * as ThemeComponents from '@theme-components' // 所有主题在next.config.js中扫描 export const { THEMES = [] } = getConfig().publicRuntimeConfig + +/** + * 加载全局布局 + * 如果是 + * @param {*} themeQuery + * @returns + */ +export const getGlobalLayoutByTheme = (themeQuery) => { + const layout = getLayoutNameByPath(-1) + if (themeQuery !== BLOG.THEME) { + return dynamic(() => import(`@/themes/${themeQuery}`).then(m => m[layout]), { ssr: true }) + } else { + return ThemeComponents[layout] + } + } + /** * 加载主题文件 * 如果是 @@ -54,6 +70,8 @@ const checkThemeDOM = () => { */ export const getLayoutNameByPath = (path) => { switch (path) { + case -1: + return 'LayoutBase' case '/': return 'LayoutIndex' case '/archive': From 05d6f0b0655e8bb27975cd1a78aa6615661204b2 Mon Sep 17 00:00:00 2001 From: velor2012 <38395332+velor2012@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:41:04 +0800 Subject: [PATCH 44/53] Update Twikoo.js --- components/Twikoo.js | 55 +++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/components/Twikoo.js b/components/Twikoo.js index 6899cfaa..3d3a08ff 100644 --- a/components/Twikoo.js +++ b/components/Twikoo.js @@ -1,6 +1,6 @@ import { siteConfig } from '@/lib/config' -// import { loadExternalResource } from '@/lib/utils' -import { useEffect } from 'react' +import { loadExternalResource } from '@/lib/utils' +import { useEffect, useRef, useState } from 'react' /** * Giscus评论 @see https://giscus.app/zh-CN @@ -12,23 +12,46 @@ import { useEffect } from 'react' const Twikoo = ({ isDarkMode }) => { const envId = siteConfig('COMMENT_TWIKOO_ENV_ID') const el = siteConfig('COMMENT_TWIKOO_ELEMENT_ID', '#twikoo') - + const twikooCDNURL = siteConfig('COMMENT_TWIKOO_CDN_URL') const lang = siteConfig('LANG') - useEffect(() => { - const twikoo = window?.twikoo - if (typeof twikoo !== 'undefined' && twikoo && typeof twikoo.init === 'function') { - twikoo.init({ - envId: envId, // 腾讯云环境填 envId;Vercel 环境填地址(https://xxx.vercel.app) - el: el, // 容器元素 - lang: lang // 用于手动设定评论区语言,支持的语言列表 https://github.com/imaegoo/twikoo/blob/main/src/client/utils/i18n/index.js - // region: 'ap-guangzhou', // 环境地域,默认为 ap-shanghai,腾讯云环境填 ap-shanghai 或 ap-guangzhou;Vercel 环境不填 - // path: location.pathname, // 用于区分不同文章的自定义 js 路径,如果您的文章路径不是 location.pathname,需传此参数 - }) + const [isInit] = useState(useRef(false)) + + const loadTwikoo = async () => { + try { + await loadExternalResource(twikooCDNURL, 'js') + const twikoo = window?.twikoo + if ( + typeof twikoo !== 'undefined' && + twikoo && + typeof twikoo.init === 'function' + ) { + twikoo.init({ + envId: envId, // 腾讯云环境填 envId;Vercel 环境填地址(https://xxx.vercel.app) + el: el, // 容器元素 + lang: lang // 用于手动设定评论区语言,支持的语言列表 https://github.com/imaegoo/twikoo/blob/main/src/client/utils/i18n/index.js + // region: 'ap-guangzhou', // 环境地域,默认为 ap-shanghai,腾讯云环境填 ap-shanghai 或 ap-guangzhou;Vercel 环境不填 + // path: location.pathname, // 用于区分不同文章的自定义 js 路径,如果您的文章路径不是 location.pathname,需传此参数 + }) + console.log('twikoo init', twikoo) + isInit.current = true + } + } catch (error) { + console.error('twikoo 加载失败', error) } + } + + useEffect(() => { + const interval = setInterval(() => { + if (isInit.current) { + console.log('twioo init! clear interval') + clearInterval(interval) + } else { + loadTwikoo() + } + }, 1000) + return () => clearInterval(interval) }, [isDarkMode]) - return ( - <div id="twikoo"></div> - ) + return <div id="twikoo"></div> } export default Twikoo From b9db8bc813bce485661f7ec080d252e53512147e Mon Sep 17 00:00:00 2001 From: velor2012 <38395332+velor2012@users.noreply.github.com> Date: Mon, 29 Jan 2024 17:06:55 +0800 Subject: [PATCH 45/53] Update _app.js --- pages/_app.js | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/pages/_app.js b/pages/_app.js index 463aa454..2d9699e5 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -9,7 +9,6 @@ import '@/styles/notion.css' // 重写部分样式 import 'aos/dist/aos.css' // You can also use <link> for styles import { GlobalContextProvider } from '@/lib/global' -import { isBrowser, loadExternalResource } from '@/lib/utils' import { getGlobalLayoutByTheme } from '@/themes/theme' import { useRouter } from 'next/router' import { useCallback, useMemo } from 'react' @@ -17,7 +16,7 @@ import { getQueryParam } from '../lib/utils' // 各种扩展插件 这个要阻塞引入 import ExternalPlugins from '@/components/ExternalPlugins' -import { CUSTOM_EXTERNAL_CSS, CUSTOM_EXTERNAL_JS, IMG_SHADOW, THEME } from '@/blog.config' +import { THEME } from '@/blog.config' const MyApp = ({ Component, pageProps }) => { /** @@ -39,33 +38,6 @@ const MyApp = ({ Component, pageProps }) => { [queryParam] ) - // 自定义样式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') - } - } - } - return ( <GlobalContextProvider {...pageProps}> <GLayout {...pageProps}> From f89e3a66bf0798a41abb01c2df40f5475efefa07 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Mon, 29 Jan 2024 19:04:45 +0800 Subject: [PATCH 46/53] Next Theme - WWAds --- themes/next/components/ArticleDetail.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/themes/next/components/ArticleDetail.js b/themes/next/components/ArticleDetail.js index 6ba1c48e..efb20983 100644 --- a/themes/next/components/ArticleDetail.js +++ b/themes/next/components/ArticleDetail.js @@ -14,6 +14,7 @@ import NotionIcon from '@/components/NotionIcon' import LazyImage from '@/components/LazyImage' import { formatDateFmt } from '@/lib/formatDate' import { siteConfig } from '@/lib/config' +import WWAds from '@/components/WWAds' /** * @@ -79,7 +80,9 @@ export default function ArticleDetail(props) { {/* Notion内容主体 */} <article className='mx-auto'> + <WWAds className="w-full" orientation="horizontal" /> {post && (<NotionPage post={post} />)} + <WWAds className="w-full" orientation="horizontal" /> </article> {showArticleInfo && <> From e19e775c9f28c20af4ec5160beac3a37ca1bab9c Mon Sep 17 00:00:00 2001 From: Rylan <1217013295@qq.com> Date: Mon, 29 Jan 2024 21:06:15 +0800 Subject: [PATCH 47/53] =?UTF-8?q?=F0=9F=90=9B=20=E4=BF=AE=E5=A4=8D=20callo?= =?UTF-8?q?ut=20=E5=9B=BE=E7=89=87=E6=BA=A2=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hooks/useAdjustStyle.js | 33 +++++++++++++++++++++++++++++++++ pages/_app.js | 3 +++ 2 files changed, 36 insertions(+) create mode 100644 hooks/useAdjustStyle.js diff --git a/hooks/useAdjustStyle.js b/hooks/useAdjustStyle.js new file mode 100644 index 00000000..e3177d38 --- /dev/null +++ b/hooks/useAdjustStyle.js @@ -0,0 +1,33 @@ +import { isBrowser } from '@/lib/utils'; +import { useEffect } from 'react'; + +const useAdjustStyle = () => { + /** + * 避免 callout 含有图片时溢出撑开父容器 + */ + const adjustCalloutImg = () => { + const callouts = document.querySelectorAll('.notion-callout-text'); + callouts.forEach((callout) => { + const images = callout.querySelectorAll('figure.notion-asset-wrapper.notion-asset-wrapper-image > div'); + const calloutWidth = callout.offsetWidth; + images.forEach((container) => { + const imageWidth = container.offsetWidth; + if (imageWidth + 50 > calloutWidth) { + container.style.setProperty('width', '100%'); + } + }); + }); + }; + + useEffect(() => { + if (isBrowser) { + adjustCalloutImg(); + window.addEventListener('resize', adjustCalloutImg); + return () => { + window.removeEventListener('resize', adjustCalloutImg); + }; + } + }, []); +}; + +export default useAdjustStyle; diff --git a/pages/_app.js b/pages/_app.js index da9b3efc..4fb5c7a0 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -9,11 +9,14 @@ import '@/styles/notion.css' // 重写部分样式 import 'aos/dist/aos.css' // You can also use <link> for styles import { GlobalContextProvider } from '@/lib/global' +import useAdjustStyle from '@/hooks/useAdjustStyle' // 各种扩展插件 这个要阻塞引入 import ExternalPlugins from '@/components/ExternalPlugins' const MyApp = ({ Component, pageProps }) => { + // 一些可能出现 bug 的样式,可以统一放入该钩子进行调整 + useAdjustStyle(); return ( <GlobalContextProvider {...pageProps}> <Component {...pageProps} /> From 48bf3012e8cb9662317f8d998a84fb280288b0f9 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Tue, 30 Jan 2024 10:58:47 +0800 Subject: [PATCH 48/53] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=BE=AE=E8=BD=AFclari?= =?UTF-8?q?ty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- blog.config.js | 3 +++ components/Busuanzi.js | 8 ++++---- components/ExternalPlugins.js | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/blog.config.js b/blog.config.js index 50e16921..8f35f94d 100644 --- a/blog.config.js +++ b/blog.config.js @@ -352,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/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/ExternalPlugins.js b/components/ExternalPlugins.js index 77433f97..b426ee65 100644 --- a/components/ExternalPlugins.js +++ b/components/ExternalPlugins.js @@ -78,6 +78,7 @@ const ExternalPlugin = (props) => { 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) { @@ -167,6 +168,19 @@ const ExternalPlugin = (props) => { }} /> </>)} + + {CLARITY_ID && (<> + <script async dangerouslySetInnerHTML={{ + __html:` + (function(c,l,a,r,i,t,y){ + c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; + t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; + y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); + })(window, document, "clarity", "script", "${CLARITY_ID}"); + ` + }}/> + </>)} + {COMMENT_DAO_VOICE_ID && (<> {/* DaoVoice 反馈 */} <script async dangerouslySetInnerHTML={{ From b415446aa6b4d502d095f533cfb68a97d0a88dea Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Tue, 30 Jan 2024 12:50:13 +0800 Subject: [PATCH 49/53] =?UTF-8?q?theme=20=E5=8A=A0=E8=BD=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/example/index.js | 23 ++--- themes/fukasawa/index.js | 23 ++--- themes/gitbook/index.js | 29 +++--- themes/heo/index.js | 139 +++++++--------------------- themes/hexo/index.js | 37 ++++---- themes/landing/index.js | 21 +++-- themes/matery/index.js | 36 +++---- themes/medium/index.js | 29 +++--- themes/nav/index.js | 31 ++++--- themes/nobelium/index.js | 29 +++--- themes/plog/index.js | 25 ++--- themes/simple/components/SideBar.js | 4 - 12 files changed, 185 insertions(+), 241 deletions(-) diff --git a/themes/example/index.js b/themes/example/index.js index 4abf3756..118a1d75 100644 --- a/themes/example/index.js +++ b/themes/example/index.js @@ -133,9 +133,9 @@ const LayoutPostList = props => { slotTop = props.slotTop } return ( - <LayoutBase {...props} slotTop={slotTop}> + <div {...props} slotTop={slotTop}> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />} - </LayoutBase> + </div> ) } @@ -147,7 +147,7 @@ const LayoutPostList = props => { const LayoutSlug = props => { const { post, lock, validPassword } = props return ( - <LayoutBase {...props}> + <div {...props}> {lock ? <ArticleLock validPassword={validPassword} /> : <div id="article-wrapper" className="px-2"> @@ -156,7 +156,7 @@ const LayoutSlug = props => { <ShareBar post={post} /> <Comment frontMatter={post} /> </div>} - </LayoutBase> + </div> ) } @@ -166,7 +166,7 @@ const LayoutSlug = props => { * @returns */ const Layout404 = (props) => { - return <LayoutBase {...props}>404 Not found.</LayoutBase> + return <div {...props}>404 Not found.</div> } /** @@ -207,13 +207,13 @@ const LayoutSearch = props => { const LayoutArchive = props => { const { archivePosts } = props return ( - <LayoutBase {...props}> + <div {...props}> <div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full"> {Object.keys(archivePosts).map(archiveTitle => ( <BlogListGroupByDate key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} /> ))} </div> - </LayoutBase> + </div> ) } @@ -225,11 +225,11 @@ const LayoutArchive = props => { const LayoutCategoryIndex = props => { const { categoryOptions } = props return ( - <LayoutBase {...props}> + <div {...props}> <div id='category-list' className='duration-200 flex flex-wrap'> {categoryOptions?.map(category => <CategoryItem key={category.name} category={category} />)} </div> - </LayoutBase> + </div> ) } @@ -241,16 +241,17 @@ const LayoutCategoryIndex = props => { const LayoutTagIndex = (props) => { const { tagOptions } = props return ( - <LayoutBase {...props}> + <div {...props}> <div id='tags-list' className='duration-200 flex flex-wrap'> {tagOptions.map(tag => <TagItem key={tag.name} tag={tag} />)} </div> - </LayoutBase> + </div> ) } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutPostList, LayoutSearch, diff --git a/themes/fukasawa/index.js b/themes/fukasawa/index.js index bf41b1a6..7ce9763f 100644 --- a/themes/fukasawa/index.js +++ b/themes/fukasawa/index.js @@ -126,12 +126,12 @@ const LayoutIndex = (props) => { * @param {*} props */ const LayoutPostList = (props) => { - return <LayoutBase {...props}> + return <div {...props}> <div className='w-full p-2'><WWAds className='w-full' orientation='horizontal'/></div> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />} - </LayoutBase> + </div> } /** @@ -142,9 +142,9 @@ const LayoutPostList = (props) => { const LayoutSlug = (props) => { const { lock, validPassword } = props return ( - <LayoutBase {...props} > + <div {...props} > {lock ? <ArticleLock validPassword={validPassword} /> : <ArticleDetail {...props} />} - </LayoutBase> + </div> ) } @@ -174,7 +174,7 @@ const LayoutSearch = props => { */ const LayoutArchive = (props) => { const { archivePosts } = props - return <LayoutBase {...props}> + return <div {...props}> <div className="mb-10 pb-20 bg-white md:p-12 p-3 dark:bg-gray-800 shadow-md min-h-full"> {Object.keys(archivePosts).map(archiveTitle => ( <BlogArchiveItem @@ -184,7 +184,7 @@ const LayoutArchive = (props) => { /> ))} </div> - </LayoutBase> + </div> } /** @@ -193,7 +193,7 @@ const LayoutArchive = (props) => { * @returns */ const Layout404 = props => { - return <LayoutBase {...props}>404</LayoutBase> + return <div {...props}>404</div> } /** @@ -205,7 +205,7 @@ const LayoutCategoryIndex = (props) => { const { locale } = useGlobal() const { categoryOptions } = props return ( - <LayoutBase {...props}> + <div {...props}> <div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'> <div className='dark:text-gray-200 mb-5'> <i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}: @@ -227,7 +227,7 @@ const LayoutCategoryIndex = (props) => { })} </div> </div> - </LayoutBase> + </div> ) } @@ -239,7 +239,7 @@ const LayoutCategoryIndex = (props) => { const LayoutTagIndex = (props) => { const { locale } = useGlobal() const { tagOptions } = props - return <LayoutBase {...props} > + return <div {...props} > <div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'> <div className='dark:text-gray-200 mb-5'><i className='mr-4 fas fa-tag' />{locale.COMMON.TAGS}:</div> <div id="tags-list" className="duration-200 flex flex-wrap ml-8"> @@ -252,11 +252,12 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </LayoutBase> + </div> } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutSearch, LayoutArchive, diff --git a/themes/gitbook/index.js b/themes/gitbook/index.js index 4743199c..57d652c9 100644 --- a/themes/gitbook/index.js +++ b/themes/gitbook/index.js @@ -193,7 +193,7 @@ const LayoutIndex = (props) => { }) }, []) - return <LayoutBase {...props} /> + return <div {...props} /> } /** @@ -203,9 +203,9 @@ const LayoutIndex = (props) => { * @returns */ const LayoutPostList = (props) => { - return <LayoutBase {...props} > + return <div {...props} > <div className='mt-10'><BlogPostListPage {...props} /></div> - </LayoutBase> + </div> } /** @@ -217,7 +217,7 @@ const LayoutSlug = (props) => { const { post, prev, next, lock, validPassword } = props return ( - <LayoutBase {...props} > + <div {...props} > {/* 文章锁 */} {lock && <ArticleLock validPassword={validPassword} />} @@ -250,7 +250,7 @@ const LayoutSlug = (props) => { <TocDrawer {...props} /> </div>} - </LayoutBase> + </div> ) } @@ -261,7 +261,7 @@ const LayoutSlug = (props) => { * @returns */ const LayoutSearch = (props) => { - return <LayoutBase {...props}></LayoutBase> + return <div {...props}></div> } /** @@ -273,20 +273,20 @@ const LayoutSearch = (props) => { const LayoutArchive = (props) => { const { archivePosts } = props - return <LayoutBase {...props}> + return <div {...props}> <div className="mb-10 pb-20 md:py-12 py-3 min-h-full"> {Object.keys(archivePosts)?.map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} </div> - </LayoutBase> + </div> } /** * 404 */ const Layout404 = props => { - return <LayoutBase {...props}> + return <div {...props}> <div className='w-full h-96 py-80 flex justify-center items-center'>404 Not found.</div> - </LayoutBase> + </div> } /** @@ -295,7 +295,7 @@ const Layout404 = props => { const LayoutCategoryIndex = (props) => { const { categoryOptions } = props const { locale } = useGlobal() - return <LayoutBase {...props}> + return <div {...props}> <div className='bg-white dark:bg-gray-700 py-10'> <div className='dark:text-gray-200 mb-5'> <i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}: @@ -317,7 +317,7 @@ const LayoutCategoryIndex = (props) => { })} </div> </div> - </LayoutBase> + </div> } /** @@ -327,7 +327,7 @@ const LayoutTagIndex = (props) => { const { tagOptions } = props const { locale } = useGlobal() - return <LayoutBase {...props}> + return <div {...props}> <div className="bg-white dark:bg-gray-700 py-10"> <div className="dark:text-gray-200 mb-5"> <i className="mr-4 fas fa-tag" /> @@ -343,11 +343,12 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </LayoutBase> + </div> } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutSearch, LayoutArchive, diff --git a/themes/heo/index.js b/themes/heo/index.js index 30a7eef1..f81fb21d 100644 --- a/themes/heo/index.js +++ b/themes/heo/index.js @@ -50,15 +50,38 @@ import { siteConfig } from '@/lib/config' const LayoutBase = props => { const { children, - headerSlot, slotTop, - slotRight, className, meta } = props // 全屏模式下的最大宽度 const { fullWidth } = useGlobal() + const router = useRouter() + console.log(router) + + const headerSlot = ( + <header> + {/* 顶部导航 */} + <div id="nav-bar-wrapper" className="h-16"> + <NavBar {...props} /> + </div> + {/* 通知横幅 */} + {router.route==='/' ? <> + <NoticeBar /> + <Hero {...props} /> + </> + : null} + <div className="max-w-[86rem] mx-auto px-3"> + <WWAds className="w-full" orientation="horizontal" /> + </div> + {fullWidth ? null : <PostHeader {...props} />} + </header> + ) + + // 右侧栏 用户信息+标签列表 + const slotRight = fullWidth ? null : <SideRight {...props} /> + const maxWidth = fullWidth ? 'max-w-[96rem] mx-auto' : 'max-w-[86rem]' // 普通最大宽度是86rem和顶部菜单栏对齐,留空则与窗口对齐 const HEO_HERO_BODY_REVERSE = siteConfig('HEO_HERO_BODY_REVERSE', false, CONFIG) @@ -115,26 +138,7 @@ const LayoutBase = props => { * @returns */ const LayoutIndex = props => { - const headerSlot = ( - <header> - {/* 顶部导航 */} - <div id="nav-bar-wrapper" className="h-16"> - <NavBar {...props} /> - </div> - {/* 通知横幅 */} - <NoticeBar /> - <Hero {...props} /> - <div className="max-w-[86rem] mx-auto px-3"> - <WWAds className="w-full" orientation="horizontal" /> - </div> - </header> - ) - - // 右侧栏 用户信息+标签列表 - const slotRight = <SideRight {...props} /> - return ( - <LayoutBase {...props} slotRight={slotRight} headerSlot={headerSlot}> <div id="post-outer-wrapper" className="px-5 md:px-0"> {/* 文章分类条 */} <CategoryBar {...props} /> @@ -146,7 +150,6 @@ const LayoutIndex = props => { <BlogPostListScroll {...props} /> )} </div> - </LayoutBase> ) } @@ -156,19 +159,8 @@ const LayoutIndex = props => { * @returns */ const LayoutPostList = props => { - // 右侧栏 - const slotRight = <SideRight {...props} /> - const headerSlot = ( - <header> - {/* 顶部导航 */} - <div id="nav-bar-wrapper" className="h-16"> - <NavBar {...props} /> - </div> - </header> - ) return ( - <LayoutBase {...props} slotRight={slotRight} headerSlot={headerSlot}> <div id="post-outer-wrapper" className="px-5 md:px-0"> {/* 文章分类条 */} <CategoryBar {...props} /> @@ -180,7 +172,6 @@ const LayoutPostList = props => { <BlogPostListScroll {...props} /> )} </div> - </LayoutBase> ) } @@ -193,16 +184,7 @@ const LayoutSearch = props => { const { keyword } = props const router = useRouter() const currentSearch = keyword || router?.query?.s - const headerSlot = ( - <header className="post-bg"> - {/* 顶部导航 */} - <div id="nav-bar-wrapper"> - <NavBar {...props} /> - </div> - <PostHeader {...props} /> - </header> - ) - + useEffect(() => { // 高亮搜索结果 if (currentSearch) { @@ -219,10 +201,9 @@ const LayoutSearch = props => { } }, []) return ( - <LayoutBase + <div {...props} currentSearch={currentSearch} - headerSlot={headerSlot} > <div id="post-outer-wrapper" className="px-5 md:px-0"> {!currentSearch @@ -241,7 +222,7 @@ const LayoutSearch = props => { </div> )} </div> - </LayoutBase> + </div> ) } @@ -253,21 +234,9 @@ const LayoutSearch = props => { const LayoutArchive = props => { const { archivePosts } = props - // 右侧栏 - const slotRight = <SideRight {...props} /> - const headerSlot = ( - <header> - {/* 顶部导航 */} - <div id="nav-bar-wrapper" className="h-16"> - <NavBar {...props} /> - </div> - </header> - ) - // 归档页顶部显示条,如果是默认归档则不显示。分类详情页显示分类列表,标签详情页显示当前标签 return ( - <LayoutBase {...props} slotRight={slotRight} headerSlot={headerSlot}> <div className="p-5 rounded-xl border dark:border-gray-600 max-w-6xl w-full bg-white dark:bg-[#1e1e1e]"> {/* 文章分类条 */} <CategoryBar {...props} border={false} /> @@ -282,7 +251,6 @@ const LayoutArchive = props => { ))} </div> </div> - </LayoutBase> ) } @@ -302,34 +270,16 @@ const LayoutSlug = props => { setHasCode(hasCode) }, []) - // 右侧栏 - const slotRight = fullWidth ? null : <SideRight {...props} /> - const headerSlot = ( - <header - data-aos="fade-up" - data-aos-duration="300" - data-aos-once="false" - data-aos-anchor-placement="top-bottom" - className="post-bg" - > - {/* 顶部导航 */} - <div id="nav-bar-wrapper"> - <NavBar {...props} /> - </div> - {fullWidth ? null : <PostHeader {...props} />} - </header> - ) + const commentEnable = siteConfig('COMMENT_TWIKOO_ENV_ID') || siteConfig('COMMENT_WALINE_SERVER_URL') || siteConfig('COMMENT_VALINE_APP_ID') || siteConfig('COMMENT_GISCUS_REPO') || siteConfig('COMMENT_CUSDIS_APP_ID') || siteConfig('COMMENT_UTTERRANCES_REPO') || siteConfig('COMMENT_GITALK_CLIENT_ID') || siteConfig('COMMENT_WEBMENTION_ENABLE') return ( - <LayoutBase + <div {...props} - headerSlot={headerSlot} showCategory={false} showTag={false} - slotRight={slotRight} > <div className={`w-full ${fullWidth ? '' : 'xl:max-w-5xl'} ${hasCode ? 'xl:w-[73.15vw]' : ''} lg:hover:shadow lg:border rounded-2xl lg:px-2 lg:py-4 bg-white dark:bg-[#18171d] dark:border-gray-600 article`}> {lock && <ArticleLock validPassword={validPassword} />} @@ -390,7 +340,7 @@ const LayoutSlug = props => { )} </div> <FloatTocButton {...props} /> - </LayoutBase> + </div> ) } @@ -477,18 +427,10 @@ const Layout404 = props => { const LayoutCategoryIndex = props => { const { categoryOptions } = props const { locale } = useGlobal() - const headerSlot = ( - <header> - {/* 顶部导航 */} - <div id="nav-bar-wrapper" className="h-16"> - <NavBar {...props} /> - </div> - </header> - ) + return ( - <LayoutBase {...props} className="mt-8" headerSlot={headerSlot}> - <div id="category-outer-wrapper" className="px-5 md:px-0"> + <div id="category-outer-wrapper" className="mt-8 px-5 md:px-0"> <div className="text-4xl font-extrabold dark:text-gray-200 mb-5"> {locale.COMMON.CATEGORY} </div> @@ -520,7 +462,6 @@ const LayoutCategoryIndex = props => { })} </div> </div> - </LayoutBase> ) } @@ -532,17 +473,9 @@ const LayoutCategoryIndex = props => { const LayoutTagIndex = props => { const { tagOptions } = props const { locale } = useGlobal() - const headerSlot = ( - <header> - {/* 顶部导航 */} - <div id="nav-bar-wrapper" className="h-16"> - <NavBar {...props} /> - </div> - </header> - ) + return ( - <LayoutBase {...props} className="mt-8" headerSlot={headerSlot}> - <div id="tag-outer-wrapper" className="px-5 md:px-0"> + <div id="tag-outer-wrapper" className="px-5 mt-8 md:px-0"> <div className="text-4xl font-extrabold dark:text-gray-200 mb-5"> {locale.COMMON.TAGS} </div> @@ -574,12 +507,12 @@ const LayoutTagIndex = props => { })} </div> </div> - </LayoutBase> ) } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutSearch, LayoutArchive, diff --git a/themes/hexo/index.js b/themes/hexo/index.js index fc3dace7..3664a2a7 100644 --- a/themes/hexo/index.js +++ b/themes/hexo/index.js @@ -46,8 +46,11 @@ export const useHexoGlobal = () => useContext(ThemeGlobalHexo) * @constructor */ const LayoutBase = props => { - const { children, headerSlot, floatSlot, slotTop, meta, className } = props + const { children, floatSlot, slotTop, meta, className } = props const { onLoading, fullWidth } = useGlobal() + + const router = useRouter() + const headerSlot = router.route==='/' && siteConfig('HEXO_HOME_BANNER_ENABLE', null, CONFIG) ? <Hero {...props} /> : null // Algolia搜索框 const searchModal = useRef(null) @@ -125,8 +128,7 @@ const LayoutBase = props => { * @returns */ const LayoutIndex = (props) => { - const headerSlot = siteConfig('HEXO_HOME_BANNER_ENABLE', null, CONFIG) && <Hero {...props} /> - return <LayoutPostList {...props} headerSlot={headerSlot} className='pt-8' /> + return <LayoutPostList {...props} className='pt-8' /> } /** @@ -135,10 +137,10 @@ const LayoutIndex = (props) => { * @returns */ const LayoutPostList = (props) => { - return <LayoutBase {...props} className='pt-8'> + return <div {...props} className='pt-8'> <SlotBar {...props} /> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} - </LayoutBase> + </div> } /** @@ -165,11 +167,11 @@ const LayoutSearch = props => { }) return ( - <LayoutBase {...props} currentSearch={currentSearch} className='pt-8'> + <div {...props} currentSearch={currentSearch} className='pt-8'> {!currentSearch ? <SearchNav {...props} /> : <div id="posts-wrapper"> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} </div>} - </LayoutBase> + </div> ) } @@ -180,7 +182,7 @@ const LayoutSearch = props => { */ const LayoutArchive = (props) => { const { archivePosts } = props - return <LayoutBase {...props} className='pt-8'> + return <div {...props} className='pt-8'> <Card className='w-full'> <div className="mb-10 pb-20 bg-white md:p-12 p-3 min-h-full dark:bg-hexo-black-gray"> {Object.keys(archivePosts).map(archiveTitle => ( @@ -192,7 +194,7 @@ const LayoutArchive = (props) => { ))} </div> </Card> - </LayoutBase> + </div> } /** @@ -218,7 +220,7 @@ const LayoutSlug = props => { </> return ( - <LayoutBase {...props} headerSlot={<PostHeader {...props} />} showCategory={false} showTag={false} floatSlot={floatSlot} > + <div {...props} headerSlot={<PostHeader {...props} />} showCategory={false} showTag={false} floatSlot={floatSlot} > <div className="w-full lg:hover:shadow lg:border rounded-t-xl lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black article"> {lock && <ArticleLock validPassword={validPassword} />} @@ -253,7 +255,7 @@ const LayoutSlug = props => { <TocDrawer post={post} cRef={drawerRight} targetRef={targetRef} /> </div> - </LayoutBase> + </div> ) } @@ -278,7 +280,7 @@ const Layout404 = props => { }, 3000) }) return ( - <LayoutBase {...props}> + <div {...props}> <div className="text-black w-full h-screen text-center justify-center content-center items-center flex flex-col"> <div className="dark:text-gray-200"> <h2 className="inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top"> @@ -289,7 +291,7 @@ const Layout404 = props => { </div> </div> </div> - </LayoutBase> + </div> ) } @@ -302,7 +304,7 @@ const LayoutCategoryIndex = props => { const { categoryOptions } = props const { locale } = useGlobal() return ( - <LayoutBase {...props} className='mt-8'> + <div {...props} className='mt-8'> <Card className="w-full min-h-screen"> <div className="dark:text-gray-200 mb-5 mx-3"> <i className="mr-4 fas fa-th" /> {locale.COMMON.CATEGORY}: @@ -319,7 +321,7 @@ const LayoutCategoryIndex = props => { })} </div> </Card> - </LayoutBase> + </div> ) } @@ -332,7 +334,7 @@ const LayoutTagIndex = props => { const { tagOptions } = props const { locale } = useGlobal() return ( - <LayoutBase {...props} className='mt-8'> + <div {...props} className='mt-8'> <Card className='w-full'> <div className="dark:text-gray-200 mb-5 ml-4"> <i className="mr-4 fas fa-tag" /> {locale.COMMON.TAGS}: @@ -343,12 +345,13 @@ const LayoutTagIndex = props => { </div>)} </div> </Card> - </LayoutBase> + </div> ) } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutSearch, LayoutArchive, diff --git a/themes/landing/index.js b/themes/landing/index.js index b7f81495..86ef856d 100644 --- a/themes/landing/index.js +++ b/themes/landing/index.js @@ -57,13 +57,13 @@ const LayoutBase = (props) => { */ const LayoutIndex = (props) => { return ( - <LayoutBase {...props}> + <div {...props}> <Hero /> <Features /> <FeaturesBlocks /> <Testimonials /> <Newsletter /> - </LayoutBase> + </div> ) } @@ -81,24 +81,25 @@ const LayoutSlug = (props) => { return <div id='theme-landing'><Loading /></div> } - return <LayoutBase {...props}> + return <div {...props}> <div id='container-inner' className='mx-auto max-w-screen-lg p-12'> <NotionPage {...props} /> </div> - </LayoutBase> + </div> } // 其他布局暂时留空 -const LayoutSearch = (props) => <LayoutBase {...props}><Hero /></LayoutBase> -const LayoutArchive = (props) => <LayoutBase {...props}><Hero /></LayoutBase> -const Layout404 = (props) => <LayoutBase {...props}><Hero /></LayoutBase> -const LayoutCategoryIndex = (props) => <LayoutBase {...props}><Hero /></LayoutBase> -const LayoutPostList = (props) => <LayoutBase {...props}><Hero /></LayoutBase> -const LayoutTagIndex = (props) => <LayoutBase {...props}><Hero /></LayoutBase> +const LayoutSearch = (props) => <div {...props}><Hero /></div> +const LayoutArchive = (props) => <div {...props}><Hero /></div> +const Layout404 = (props) => <div {...props}><Hero /></div> +const LayoutCategoryIndex = (props) => <div {...props}><Hero /></div> +const LayoutPostList = (props) => <div {...props}><Hero /></div> +const LayoutTagIndex = (props) => <div {...props}><Hero /></div> export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutSearch, LayoutArchive, diff --git a/themes/matery/index.js b/themes/matery/index.js index 6ecb7dbf..cbe23823 100644 --- a/themes/matery/index.js +++ b/themes/matery/index.js @@ -40,9 +40,12 @@ import { siteConfig } from '@/lib/config' * @constructor */ const LayoutBase = props => { - const { children, headerSlot, meta, siteInfo, containerSlot, post } = props + const { children, meta, siteInfo, post } = props const { onLoading, fullWidth } = useGlobal() + const containerSlot= <Announcement {...props} /> + const headerSlot= siteConfig('MATERY_HOME_BANNER_ENABLE', null, CONFIG) ? <Hero {...props} /> : null + return ( <div id='theme-matery' className="min-h-screen flex flex-col justify-between bg-hexo-background-gray dark:bg-black w-full"> {/* SEO相关 */} @@ -113,7 +116,7 @@ const LayoutBase = props => { * @returns */ const LayoutIndex = (props) => { - return <LayoutPostList {...props} containerSlot={<Announcement {...props} />} headerSlot={siteConfig('MATERY_HOME_BANNER_ENABLE', null, CONFIG) && <Hero {...props} />} /> + return <LayoutPostList {...props}/> } /** @@ -123,9 +126,9 @@ const LayoutIndex = (props) => { */ const LayoutPostList = (props) => { return ( - <LayoutBase {...props} containerSlot={<BlogListBar {...props} />}> + <div {...props} containerSlot={<BlogListBar {...props} />}> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} - </LayoutBase> + </div> ) } @@ -152,13 +155,13 @@ const LayoutSearch = props => { } }) return ( - <LayoutBase {...props} currentSearch={currentSearch}> + <div {...props} currentSearch={currentSearch}> {!currentSearch ? <SearchNave {...props} /> : <div id="posts-wrapper"> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} </div>} - </LayoutBase> + </div> ) } @@ -169,7 +172,7 @@ const LayoutSearch = props => { */ const LayoutArchive = (props) => { const { archivePosts } = props - return <LayoutBase {...props} headerSlot={<PostHeader {...props} />} > + return <div {...props} headerSlot={<PostHeader {...props} />} > <Card className='w-full -mt-32'> <div className="mb-10 pb-20 bg-white md:p-12 p-3 min-h-full dark:bg-hexo-black-gray"> {Object.keys(archivePosts).map(archiveTitle => ( @@ -181,7 +184,7 @@ const LayoutArchive = (props) => { ))} </div> </Card> - </LayoutBase> + </div> } /** @@ -194,7 +197,7 @@ const LayoutSlug = props => { const { fullWidth } = useGlobal() const headerSlot = fullWidth ? null : <PostHeader {...props} /> - return (<LayoutBase {...props} headerSlot={headerSlot} showCategory={false} showTag={false} floatRightBottom={<JumpToCommentButton />}> + return (<div {...props} headerSlot={headerSlot} showCategory={false} showTag={false} floatRightBottom={<JumpToCommentButton />}> <div id='inner-wrapper' className={`w-full ${fullWidth ? '' : 'lg:max-w-3xl 2xl:max-w-4xl'}`} > @@ -257,7 +260,7 @@ const LayoutSlug = props => { </div> - </LayoutBase> + </div> ) } @@ -280,7 +283,7 @@ const Layout404 = props => { }, 3000) }) return ( - <LayoutBase {...props}> + <div {...props}> <div className="text-black w-full h-screen text-center justify-center content-center items-center flex flex-col"> <div className="dark:text-gray-200"> <h2 className="inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top"> @@ -291,7 +294,7 @@ const Layout404 = props => { </div> </div> </div> - </LayoutBase> + </div> ) } @@ -304,7 +307,7 @@ const LayoutCategoryIndex = props => { const { categoryOptions } = props return ( - <LayoutBase {...props} headerSlot={<PostHeader {...props} />} > + <div {...props} headerSlot={<PostHeader {...props} />} > <div id='inner-wrapper' className='w-full'> <div className="drop-shadow-xl -mt-32 rounded-md mx-3 px-5 lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black dark:text-gray-300"> @@ -321,7 +324,7 @@ const LayoutCategoryIndex = props => { </div> </div> </div> - </LayoutBase> + </div> ) } @@ -334,7 +337,7 @@ const LayoutTagIndex = props => { const { tagOptions } = props const { locale } = useGlobal() return ( - <LayoutBase {...props} headerSlot={<PostHeader {...props} />} > + <div {...props} headerSlot={<PostHeader {...props} />} > <div id='inner-wrapper' className='w-full drop-shadow-xl'> <div className="-mt-32 rounded-md mx-3 px-5 lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black"> @@ -354,12 +357,13 @@ const LayoutTagIndex = props => { </div> </div> </div> - </LayoutBase> + </div> ) } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutPostList, LayoutSearch, diff --git a/themes/medium/index.js b/themes/medium/index.js index 433ed80b..cb6bf541 100644 --- a/themes/medium/index.js +++ b/themes/medium/index.js @@ -138,9 +138,9 @@ const LayoutIndex = (props) => { */ const LayoutPostList = (props) => { const slotTop = <BlogPostBar {...props} /> - return <LayoutBase {...props} slotTop={slotTop}> + return <div {...props} slotTop={slotTop}> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} - </LayoutBase> + </div> } /** @@ -158,7 +158,7 @@ const LayoutSlug = props => { ) return ( - <LayoutBase showInfoCard={true} slotRight={slotRight} {...props} > + <div showInfoCard={true} slotRight={slotRight} {...props} > {/* 文章锁 */} {lock && <ArticleLock validPassword={validPassword} />} @@ -192,7 +192,7 @@ const LayoutSlug = props => { {/* 移动端目录 */} <TocDrawer {...props} /> </div>} - </LayoutBase> + </div> ) } @@ -220,7 +220,7 @@ const LayoutSearch = (props) => { } }, []) - return <LayoutBase {...props}> + return <div {...props}> {/* 搜索导航栏 */} <div className='py-12'> @@ -236,7 +236,7 @@ const LayoutSearch = (props) => { {currentSearch && <div> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} </div>} - </LayoutBase> + </div> } /** @@ -247,12 +247,12 @@ const LayoutSearch = (props) => { const LayoutArchive = props => { const { archivePosts } = props return ( - <LayoutBase {...props}> + <div {...props}> <div className="mb-10 pb-20 md:py-12 py-3 min-h-full"> {Object.keys(archivePosts)?.map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} /> )} </div> - </LayoutBase> + </div> ) } @@ -262,9 +262,9 @@ const LayoutArchive = props => { * @returns */ const Layout404 = props => { - return <LayoutBase {...props}> + return <div {...props}> <div className='w-full h-96 py-80 flex justify-center items-center'>404 Not found.</div> - </LayoutBase> + </div> } /** @@ -276,7 +276,7 @@ const LayoutCategoryIndex = (props) => { const { categoryOptions } = props const { locale } = useGlobal() return ( - <LayoutBase {...props}> + <div {...props}> <div className='bg-white dark:bg-gray-700 py-10'> <div className='dark:text-gray-200 mb-5'> <i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}: @@ -298,7 +298,7 @@ const LayoutCategoryIndex = (props) => { })} </div> </div> - </LayoutBase> + </div> ) } @@ -311,7 +311,7 @@ const LayoutTagIndex = props => { const { tagOptions } = props const { locale } = useGlobal() return ( - <LayoutBase {...props}> + <div {...props}> <div className="bg-white dark:bg-gray-700 py-10"> <div className="dark:text-gray-200 mb-5"> <i className="mr-4 fas fa-tag" /> @@ -327,12 +327,13 @@ const LayoutTagIndex = props => { })} </div> </div> - </LayoutBase> + </div> ) } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutPostList, LayoutSearch, diff --git a/themes/nav/index.js b/themes/nav/index.js index d4870f12..9c98dab2 100755 --- a/themes/nav/index.js +++ b/themes/nav/index.js @@ -172,10 +172,10 @@ const LayoutPostListIndex = props => { // const { customMenu, children, post, allNavPages, categoryOptions, slotLeft, slotRight, slotTop, meta } = props // const [filteredNavPages, setFilteredNavPages] = useState(allNavPages) return ( - <LayoutBase {...props} > + <div {...props} > <Announcement {...props} /> <BlogPostListAll { ...props } /> - </LayoutBase> + </div> ) } @@ -189,7 +189,7 @@ const LayoutPostList = props => { // 顶部如果是按照分类或标签查看文章列表,列表顶部嵌入一个横幅 // 如果是搜索,则列表顶部嵌入 搜索框 return ( - <LayoutBase {...props} > + <div {...props} > <div className='w-full max-w-7xl mx-auto justify-center mt-8'> <div id='posts-wrapper' class='card-list grid gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5'> {posts?.map(post => ( @@ -197,7 +197,7 @@ const LayoutPostList = props => { ))} </div> </div> - </LayoutBase> + </div> ) } @@ -210,7 +210,7 @@ const LayoutSlug = (props) => { const { post, lock, validPassword } = props return ( - <LayoutBase {...props} > + <div {...props} > {/* 文章锁 */} {lock && <ArticleLock validPassword={validPassword} />} @@ -244,7 +244,7 @@ const LayoutSlug = (props) => { <TocDrawer {...props} /> </div>} - </LayoutBase> + </div> ) } @@ -255,7 +255,7 @@ const LayoutSlug = (props) => { * @returns */ const LayoutSearch = (props) => { - return <LayoutBase {...props}></LayoutBase> + return <div {...props}></div> } /** @@ -267,20 +267,20 @@ const LayoutSearch = (props) => { const LayoutArchive = (props) => { const { archivePosts } = props - return <LayoutBase {...props}> + return <div {...props}> <div className="mb-10 pb-20 md:py-12 py-3 min-h-full"> {Object.keys(archivePosts)?.map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} </div> - </LayoutBase> + </div> } /** * 404 */ const Layout404 = props => { - return <LayoutBase {...props}> + return <div {...props}> <div className='w-full h-96 py-80 flex justify-center items-center'>404 Not found.</div> - </LayoutBase> + </div> } /** @@ -289,7 +289,7 @@ const Layout404 = props => { const LayoutCategoryIndex = (props) => { const { categoryOptions } = props const { locale } = useGlobal() - return <LayoutBase {...props}> + return <div {...props}> <div className='bg-white dark:bg-gray-700 py-10'> <div className='dark:text-gray-200 mb-5'> <i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}: @@ -311,7 +311,7 @@ const LayoutCategoryIndex = (props) => { })} </div> </div> - </LayoutBase> + </div> } /** @@ -321,7 +321,7 @@ const LayoutTagIndex = (props) => { const { tagOptions } = props const { locale } = useGlobal() - return <LayoutBase {...props}> + return <div {...props}> <div className="bg-white dark:bg-gray-700 py-10"> <div className="dark:text-gray-200 mb-5"> <i className="mr-4 fas fa-tag" /> @@ -337,11 +337,12 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </LayoutBase> + </div> } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutSearch, LayoutArchive, diff --git a/themes/nobelium/index.js b/themes/nobelium/index.js index c45bd08d..f5152842 100644 --- a/themes/nobelium/index.js +++ b/themes/nobelium/index.js @@ -130,10 +130,10 @@ const LayoutPostList = props => { } return ( - <LayoutBase {...props} topSlot={<BlogListBar {...props} setFilterKey={setFilterKey} />}> + <div {...props} topSlot={<BlogListBar {...props} setFilterKey={setFilterKey} />}> {topSlot} {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} posts={filteredBlogPosts} /> : <BlogListScroll {...props} posts={filteredBlogPosts} />} - </LayoutBase> + </div> ) } @@ -171,10 +171,10 @@ const LayoutSearch = props => { filteredBlogPosts = deepClone(posts) } - return <LayoutBase {...props} topSlot={<BlogListBar {...props} setFilterKey={setFilterKey} />}> + return <div {...props} topSlot={<BlogListBar {...props} setFilterKey={setFilterKey} />}> <SearchNavBar {...props} /> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} posts={filteredBlogPosts} /> : <BlogListScroll {...props} posts={filteredBlogPosts} />} - </LayoutBase> + </div> } /** @@ -185,11 +185,11 @@ const LayoutSearch = props => { const LayoutArchive = props => { const { archivePosts } = props return ( - <LayoutBase {...props}> + <div {...props}> <div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full"> {Object.keys(archivePosts).map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} </div> - </LayoutBase> + </div> ) } @@ -202,7 +202,7 @@ const LayoutSlug = props => { const { post, lock, validPassword } = props return ( - <LayoutBase {...props}> + <div {...props}> {lock && <ArticleLock validPassword={validPassword} />} @@ -216,7 +216,7 @@ const LayoutSlug = props => { </> </div>} - </LayoutBase> + </div> ) } @@ -226,9 +226,9 @@ const LayoutSlug = props => { * @returns */ const Layout404 = (props) => { - return <LayoutBase {...props}> + return <div {...props}> 404 Not found. - </LayoutBase> + </div> } /** @@ -240,7 +240,7 @@ const LayoutCategoryIndex = (props) => { const { categoryOptions } = props return ( - <LayoutBase {...props}> + <div {...props}> <div id='category-list' className='duration-200 flex flex-wrap'> {categoryOptions?.map(category => { return ( @@ -257,7 +257,7 @@ const LayoutCategoryIndex = (props) => { ) })} </div> - </LayoutBase> + </div> ) } @@ -269,7 +269,7 @@ const LayoutCategoryIndex = (props) => { const LayoutTagIndex = (props) => { const { tagOptions } = props return ( - <LayoutBase {...props}> + <div {...props}> <div> <div id='tags-list' className='duration-200 flex flex-wrap'> {tagOptions.map(tag => { @@ -284,12 +284,13 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </LayoutBase> + </div> ) } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutSearch, LayoutArchive, diff --git a/themes/plog/index.js b/themes/plog/index.js index 22ec32c6..a777055b 100644 --- a/themes/plog/index.js +++ b/themes/plog/index.js @@ -98,9 +98,9 @@ const LayoutIndex = props => { */ const LayoutPostList = props => { return ( - <LayoutBase {...props}> + <div {...props}> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />} - </LayoutBase> + </div> ) } @@ -137,11 +137,11 @@ const LayoutSearch = props => { const LayoutArchive = props => { const { archivePosts } = props return ( - <LayoutBase {...props}> + <div {...props}> <div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full"> {Object.keys(archivePosts).map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} </div> - </LayoutBase> + </div> ) } @@ -154,7 +154,7 @@ const LayoutSlug = props => { const { post, lock, validPassword } = props return ( - <LayoutBase {...props}> + <div {...props}> {lock && <ArticleLock validPassword={validPassword} />} @@ -168,7 +168,7 @@ const LayoutSlug = props => { </> </div>} - </LayoutBase> + </div> ) } @@ -178,9 +178,9 @@ const LayoutSlug = props => { * @returns */ const Layout404 = (props) => { - return <LayoutBase {...props}> + return <div {...props}> 404 Not found. - </LayoutBase> + </div> } /** @@ -192,7 +192,7 @@ const LayoutCategoryIndex = (props) => { const { categoryOptions } = props return ( - <LayoutBase {...props}> + <div {...props}> <div id='category-list' className='duration-200 flex flex-wrap'> {categoryOptions?.map(category => { return ( @@ -209,7 +209,7 @@ const LayoutCategoryIndex = (props) => { ) })} </div> - </LayoutBase> + </div> ) } @@ -221,7 +221,7 @@ const LayoutCategoryIndex = (props) => { const LayoutTagIndex = (props) => { const { tagOptions } = props return ( - <LayoutBase {...props}> + <div {...props}> <div> <div id='tags-list' className='duration-200 flex flex-wrap'> {tagOptions.map(tag => { @@ -236,12 +236,13 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </LayoutBase> + </div> ) } export { CONFIG as THEME_CONFIG, + LayoutBase, LayoutIndex, LayoutSearch, LayoutArchive, diff --git a/themes/simple/components/SideBar.js b/themes/simple/components/SideBar.js index 0d17afec..980cccee 100644 --- a/themes/simple/components/SideBar.js +++ b/themes/simple/components/SideBar.js @@ -2,7 +2,6 @@ import { AdSlot } from '@/components/GoogleAdsense' import Live2D from '@/components/Live2D' import Announcement from './Announcement' import Catalog from './Catalog' -import { useEffect } from 'react' /** * 侧边栏 @@ -12,9 +11,6 @@ import { useEffect } from 'react' let counter = 0; export default function SideBar (props) { const { notice } = props - useEffect(()=>{ - console.log('sidebar 渲染次数: ', counter++) -}, []) return (<> <aside> From c9d622e7e53e818ee32dda4320a39f6cdba1121e Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Tue, 30 Jan 2024 13:05:30 +0800 Subject: [PATCH 50/53] build --- components/ExternalPlugins.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/ExternalPlugins.js b/components/ExternalPlugins.js index b426ee65..2b1f1cd0 100644 --- a/components/ExternalPlugins.js +++ b/components/ExternalPlugins.js @@ -168,17 +168,17 @@ const ExternalPlugin = (props) => { }} /> </>)} - {CLARITY_ID && (<> - <script async dangerouslySetInnerHTML={{ - __html:` + <script async dangerouslySetInnerHTML={{ + __html: ` (function(c,l,a,r,i,t,y){ c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); })(window, document, "clarity", "script", "${CLARITY_ID}"); ` - }}/> + }} + /> </>)} {COMMENT_DAO_VOICE_ID && (<> From c1ee671e3ed8affd71b9ae68669d87349bf2ac9a Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Tue, 30 Jan 2024 17:37:35 +0800 Subject: [PATCH 51/53] fix themes --- components/ExternalPlugins.js | 15 +++--- themes/example/components/BlogPostCard.js | 2 +- themes/example/index.js | 57 ++++++++++++----------- themes/fukasawa/index.js | 24 +++++----- themes/gitbook/index.js | 24 +++++----- themes/matery/index.js | 10 ++-- themes/next/index.js | 8 +--- 7 files changed, 66 insertions(+), 74 deletions(-) diff --git a/components/ExternalPlugins.js b/components/ExternalPlugins.js index 2b1f1cd0..768cc384 100644 --- a/components/ExternalPlugins.js +++ b/components/ExternalPlugins.js @@ -171,14 +171,13 @@ const ExternalPlugin = (props) => { {CLARITY_ID && (<> <script async dangerouslySetInnerHTML={{ __html: ` - (function(c,l,a,r,i,t,y){ - c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; - t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; - y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); - })(window, document, "clarity", "script", "${CLARITY_ID}"); - ` - }} - /> + (function(c,l,a,r,i,t,y){ + c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; + t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; + y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); + })(window, document, "clarity", "script", "${CLARITY_ID}"); + ` + }} /> </>)} {COMMENT_DAO_VOICE_ID && (<> diff --git a/themes/example/components/BlogPostCard.js b/themes/example/components/BlogPostCard.js index 5b690743..cd330a83 100644 --- a/themes/example/components/BlogPostCard.js +++ b/themes/example/components/BlogPostCard.js @@ -21,7 +21,7 @@ const BlogPostCard = ({ post }) => { by <a href="#" className="text-gray-700 dark:text-gray-300">{siteConfig('AUTHOR')}</a> on {post.date?.start_date || post.createdTime} <TwikooCommentCount post={post} className='pl-1'/> <span className="font-bold mx-1"> | </span> - <a href={`/category${post.category}`} className="text-gray-700 dark:text-gray-300 hover:underline">{post.category}</a> + <Link href={`/category/${post.category}`} className="text-gray-700 dark:text-gray-300 hover:underline">{post.category}</Link> {/* <span className="font-bold mx-1"> | </span> */} {/* <a href="#" className="text-gray-700">2 Comments</a> */} </div> diff --git a/themes/example/index.js b/themes/example/index.js index 118a1d75..fde016f7 100644 --- a/themes/example/index.js +++ b/themes/example/index.js @@ -36,8 +36,23 @@ import { siteConfig } from '@/lib/config' * @constructor */ const LayoutBase = props => { - const { children, slotTop, meta } = props + const { children, meta } = props const { onLoading, fullWidth } = useGlobal() + const router = useRouter() + const { category, tag } = props + // 顶部如果是按照分类或标签查看文章列表,列表顶部嵌入一个横幅 + // 如果是搜索,则列表顶部嵌入 搜索框 + let slotTop = null + if (category) { + slotTop = <div className='pb-12'><i className="mr-1 fas fa-folder-open" />{category}</div> + } else if (tag) { + slotTop = <div className='pb-12'>#{tag}</div> + } else if (props.slotTop) { + slotTop = props.slotTop + } else if (router.route==='/search'){ + // 嵌入一个搜索框在顶部 + slotTop = <div className='pb-12'><SearchInput {...props} /></div> + } // 增加一个状态以触发 Transition 组件的动画 // const [showTransition, setShowTransition] = useState(true) @@ -121,21 +136,11 @@ const LayoutIndex = props => { * @returns */ const LayoutPostList = props => { - const { category, tag } = props - // 顶部如果是按照分类或标签查看文章列表,列表顶部嵌入一个横幅 - // 如果是搜索,则列表顶部嵌入 搜索框 - let slotTop = null - if (category) { - slotTop = <div className='pb-12'><i className="mr-1 fas fa-folder-open" />{category}</div> - } else if (tag) { - slotTop = <div className='pb-12'>#{tag}</div> - } else if (props.slotTop) { - slotTop = props.slotTop - } + return ( - <div {...props} slotTop={slotTop}> + <> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />} - </div> + </> ) } @@ -147,7 +152,7 @@ const LayoutPostList = props => { const LayoutSlug = props => { const { post, lock, validPassword } = props return ( - <div {...props}> + <> {lock ? <ArticleLock validPassword={validPassword} /> : <div id="article-wrapper" className="px-2"> @@ -156,7 +161,7 @@ const LayoutSlug = props => { <ShareBar post={post} /> <Comment frontMatter={post} /> </div>} - </div> + </> ) } @@ -166,7 +171,7 @@ const LayoutSlug = props => { * @returns */ const Layout404 = (props) => { - return <div {...props}>404 Not found.</div> + return <>404 Not found.</> } /** @@ -176,8 +181,6 @@ const Layout404 = (props) => { */ const LayoutSearch = props => { const { keyword } = props - // 嵌入一个搜索框在顶部 - const slotTop = <div className='pb-12'><SearchInput {...props} /></div> const router = useRouter() useEffect(() => { if (isBrowser) { @@ -196,7 +199,7 @@ const LayoutSearch = props => { } }, [router]) - return <LayoutPostList slotTop={slotTop} {...props} /> + return <LayoutPostList {...props} /> } /** @@ -206,15 +209,13 @@ const LayoutSearch = props => { */ const LayoutArchive = props => { const { archivePosts } = props - return ( - <div {...props}> + return (<> <div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full"> {Object.keys(archivePosts).map(archiveTitle => ( <BlogListGroupByDate key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} /> ))} </div> - </div> - ) + </>) } /** @@ -225,11 +226,11 @@ const LayoutArchive = props => { const LayoutCategoryIndex = props => { const { categoryOptions } = props return ( - <div {...props}> + <> <div id='category-list' className='duration-200 flex flex-wrap'> {categoryOptions?.map(category => <CategoryItem key={category.name} category={category} />)} </div> - </div> + </> ) } @@ -241,11 +242,11 @@ const LayoutCategoryIndex = props => { const LayoutTagIndex = (props) => { const { tagOptions } = props return ( - <div {...props}> + <> <div id='tags-list' className='duration-200 flex flex-wrap'> {tagOptions.map(tag => <TagItem key={tag.name} tag={tag} />)} </div> - </div> + </> ) } diff --git a/themes/fukasawa/index.js b/themes/fukasawa/index.js index 7ce9763f..8587daad 100644 --- a/themes/fukasawa/index.js +++ b/themes/fukasawa/index.js @@ -126,12 +126,10 @@ const LayoutIndex = (props) => { * @param {*} props */ const LayoutPostList = (props) => { - return <div {...props}> - + return <> <div className='w-full p-2'><WWAds className='w-full' orientation='horizontal'/></div> - {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />} - </div> + </> } /** @@ -142,9 +140,9 @@ const LayoutPostList = (props) => { const LayoutSlug = (props) => { const { lock, validPassword } = props return ( - <div {...props} > + <> {lock ? <ArticleLock validPassword={validPassword} /> : <ArticleDetail {...props} />} - </div> + </> ) } @@ -174,7 +172,7 @@ const LayoutSearch = props => { */ const LayoutArchive = (props) => { const { archivePosts } = props - return <div {...props}> + return <> <div className="mb-10 pb-20 bg-white md:p-12 p-3 dark:bg-gray-800 shadow-md min-h-full"> {Object.keys(archivePosts).map(archiveTitle => ( <BlogArchiveItem @@ -184,7 +182,7 @@ const LayoutArchive = (props) => { /> ))} </div> - </div> + </> } /** @@ -193,7 +191,7 @@ const LayoutArchive = (props) => { * @returns */ const Layout404 = props => { - return <div {...props}>404</div> + return <>404</> } /** @@ -205,7 +203,7 @@ const LayoutCategoryIndex = (props) => { const { locale } = useGlobal() const { categoryOptions } = props return ( - <div {...props}> + <> <div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'> <div className='dark:text-gray-200 mb-5'> <i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}: @@ -227,7 +225,7 @@ const LayoutCategoryIndex = (props) => { })} </div> </div> - </div> + </> ) } @@ -239,7 +237,7 @@ const LayoutCategoryIndex = (props) => { const LayoutTagIndex = (props) => { const { locale } = useGlobal() const { tagOptions } = props - return <div {...props} > + return <> <div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'> <div className='dark:text-gray-200 mb-5'><i className='mr-4 fas fa-tag' />{locale.COMMON.TAGS}:</div> <div id="tags-list" className="duration-200 flex flex-wrap ml-8"> @@ -252,7 +250,7 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </div> + </> } export { diff --git a/themes/gitbook/index.js b/themes/gitbook/index.js index 57d652c9..69aeca1a 100644 --- a/themes/gitbook/index.js +++ b/themes/gitbook/index.js @@ -193,7 +193,7 @@ const LayoutIndex = (props) => { }) }, []) - return <div {...props} /> + return <></> } /** @@ -203,9 +203,7 @@ const LayoutIndex = (props) => { * @returns */ const LayoutPostList = (props) => { - return <div {...props} > - <div className='mt-10'><BlogPostListPage {...props} /></div> - </div> + return <></> } /** @@ -217,7 +215,7 @@ const LayoutSlug = (props) => { const { post, prev, next, lock, validPassword } = props return ( - <div {...props} > + <> {/* 文章锁 */} {lock && <ArticleLock validPassword={validPassword} />} @@ -250,7 +248,7 @@ const LayoutSlug = (props) => { <TocDrawer {...props} /> </div>} - </div> + </> ) } @@ -261,7 +259,7 @@ const LayoutSlug = (props) => { * @returns */ const LayoutSearch = (props) => { - return <div {...props}></div> + return <></> } /** @@ -273,20 +271,20 @@ const LayoutSearch = (props) => { const LayoutArchive = (props) => { const { archivePosts } = props - return <div {...props}> + return <> <div className="mb-10 pb-20 md:py-12 py-3 min-h-full"> {Object.keys(archivePosts)?.map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} </div> - </div> + </> } /** * 404 */ const Layout404 = props => { - return <div {...props}> + return <> <div className='w-full h-96 py-80 flex justify-center items-center'>404 Not found.</div> - </div> + </> } /** @@ -295,7 +293,7 @@ const Layout404 = props => { const LayoutCategoryIndex = (props) => { const { categoryOptions } = props const { locale } = useGlobal() - return <div {...props}> + return <> <div className='bg-white dark:bg-gray-700 py-10'> <div className='dark:text-gray-200 mb-5'> <i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}: @@ -317,7 +315,7 @@ const LayoutCategoryIndex = (props) => { })} </div> </div> - </div> + </> } /** diff --git a/themes/matery/index.js b/themes/matery/index.js index cbe23823..80ed61ee 100644 --- a/themes/matery/index.js +++ b/themes/matery/index.js @@ -42,9 +42,9 @@ import { siteConfig } from '@/lib/config' const LayoutBase = props => { const { children, meta, siteInfo, post } = props const { onLoading, fullWidth } = useGlobal() - - const containerSlot= <Announcement {...props} /> - const headerSlot= siteConfig('MATERY_HOME_BANNER_ENABLE', null, CONFIG) ? <Hero {...props} /> : null + const router = useRouter() + const containerSlot= router.route==='/' ? <Announcement {...props} /> : <BlogListBar {...props} /> + const headerSlot= siteConfig('MATERY_HOME_BANNER_ENABLE', null, CONFIG) && router.route==='/' ? <Hero {...props} /> : null return ( <div id='theme-matery' className="min-h-screen flex flex-col justify-between bg-hexo-background-gray dark:bg-black w-full"> @@ -126,9 +126,9 @@ const LayoutIndex = (props) => { */ const LayoutPostList = (props) => { return ( - <div {...props} containerSlot={<BlogListBar {...props} />}> + <> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} - </div> + </> ) } diff --git a/themes/next/index.js b/themes/next/index.js index 9e0b1c4a..0203b749 100644 --- a/themes/next/index.js +++ b/themes/next/index.js @@ -32,7 +32,6 @@ import { siteConfig } from '@/lib/config' * @returns {JSX.Element} * @constructor */ -let counter = 0 const LayoutBase = (props) => { const { children, headerSlot, floatSlot, rightAreaSlot, meta } = props const { onLoading } = useGlobal() @@ -40,9 +39,6 @@ const LayoutBase = (props) => { const floatButtonGroup = useRef(null) const [showRightFloat, switchShow] = useState(false) const [percent, changePercent] = useState(0) // 页面阅读百分比 - useEffect(()=>{ - console.log('sidebar 渲染次数: ', counter++) - }, []) const scrollListener = () => { const targetRef = document.getElementById('wrapper') const clientHeight = targetRef?.clientHeight @@ -213,7 +209,7 @@ const Layout404 = props => { }, 3000) }, []) - return <div {...props}> + return <> <div className='md:-mt-20 text-black w-full h-screen text-center justify-center content-center items-center flex flex-col'> <div className='dark:text-gray-200'> <h2 className='inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top'><i className='mr-2 fas fa-spinner animate-spin' />404</h2> @@ -222,7 +218,7 @@ const Layout404 = props => { </div> </div> </div> - </div> + </> } /** From b5bfdcba4be2d9de00a2541ac623624e9afe457f Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Tue, 30 Jan 2024 18:05:37 +0800 Subject: [PATCH 52/53] =?UTF-8?q?theme=20=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/_document.js | 1 + themes/gitbook/index.js | 4 +- themes/hexo/index.js | 51 ++++++++++++----------- themes/landing/index.js | 21 +++++----- themes/matery/index.js | 38 +++++++++-------- themes/medium/index.js | 29 ++++++------- themes/nav/components/MenuItem.js | 4 +- themes/nav/index.js | 30 ++++++------- themes/next/components/Card.js | 19 +++++---- themes/next/index.js | 50 +++++++++++----------- themes/nobelium/components/BlogListBar.js | 3 +- themes/nobelium/index.js | 45 ++++++++++---------- themes/plog/components/BlogListBar.js | 39 ----------------- themes/plog/components/Modal.js | 3 +- themes/plog/index.js | 24 +++++------ themes/simple/index.js | 24 +++++------ 16 files changed, 180 insertions(+), 205 deletions(-) delete mode 100644 themes/plog/components/BlogListBar.js diff --git a/pages/_document.js b/pages/_document.js index 976a45fb..96c999c3 100644 --- a/pages/_document.js +++ b/pages/_document.js @@ -20,6 +20,7 @@ class MyDocument extends Document { </>} {BLOG.FONT_URL?.map((fontUrl, index) => { + console.log(fontUrl) if (fontUrl.endsWith('.css')) { return <link key={index} rel="stylesheet" href={fontUrl} /> } else { diff --git a/themes/gitbook/index.js b/themes/gitbook/index.js index 69aeca1a..ccef346b 100644 --- a/themes/gitbook/index.js +++ b/themes/gitbook/index.js @@ -325,7 +325,7 @@ const LayoutTagIndex = (props) => { const { tagOptions } = props const { locale } = useGlobal() - return <div {...props}> + return <> <div className="bg-white dark:bg-gray-700 py-10"> <div className="dark:text-gray-200 mb-5"> <i className="mr-4 fas fa-tag" /> @@ -341,7 +341,7 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </div> + </> } export { diff --git a/themes/hexo/index.js b/themes/hexo/index.js index 3664a2a7..18a7daf2 100644 --- a/themes/hexo/index.js +++ b/themes/hexo/index.js @@ -46,12 +46,25 @@ export const useHexoGlobal = () => useContext(ThemeGlobalHexo) * @constructor */ const LayoutBase = props => { - const { children, floatSlot, slotTop, meta, className } = props + const { post , children, slotTop, meta, className } = props const { onLoading, fullWidth } = useGlobal() const router = useRouter() - const headerSlot = router.route==='/' && siteConfig('HEXO_HOME_BANNER_ENABLE', null, CONFIG) ? <Hero {...props} /> : null + const headerSlot = post + ? <PostHeader {...props} /> : (router.route==='/' && siteConfig('HEXO_HOME_BANNER_ENABLE', null, CONFIG) + ? <Hero {...props} /> : null) + const floatSlot = <> + {post?.toc?.length > 1 && <div className="block lg:hidden"> + <TocDrawerButton + onClick={() => { + drawerRight?.current?.handleSwitchVisible() + }} + /> + </div>} + <JumpToCommentButton /> + </> + // Algolia搜索框 const searchModal = useRef(null) @@ -137,7 +150,7 @@ const LayoutIndex = (props) => { * @returns */ const LayoutPostList = (props) => { - return <div {...props} className='pt-8'> + return <div className='pt-8'> <SlotBar {...props} /> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} </div> @@ -167,7 +180,7 @@ const LayoutSearch = props => { }) return ( - <div {...props} currentSearch={currentSearch} className='pt-8'> + <div className='pt-8'> {!currentSearch ? <SearchNav {...props} /> : <div id="posts-wrapper"> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} </div>} @@ -182,7 +195,7 @@ const LayoutSearch = props => { */ const LayoutArchive = (props) => { const { archivePosts } = props - return <div {...props} className='pt-8'> + return <div className='pt-8'> <Card className='w-full'> <div className="mb-10 pb-20 bg-white md:p-12 p-3 min-h-full dark:bg-hexo-black-gray"> {Object.keys(archivePosts).map(archiveTitle => ( @@ -205,22 +218,10 @@ const LayoutArchive = (props) => { const LayoutSlug = props => { const { post, lock, validPassword } = props const drawerRight = useRef(null) - - const targetRef = isBrowser ? document.getElementById('article-wrapper') : null - - const floatSlot = <> - {post?.toc?.length > 1 && <div className="block lg:hidden"> - <TocDrawerButton - onClick={() => { - drawerRight?.current?.handleSwitchVisible() - }} - /> - </div>} - <JumpToCommentButton /> - </> + const tocRef = isBrowser ? document.getElementById('article-wrapper') : null return ( - <div {...props} headerSlot={<PostHeader {...props} />} showCategory={false} showTag={false} floatSlot={floatSlot} > + <> <div className="w-full lg:hover:shadow lg:border rounded-t-xl lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black article"> {lock && <ArticleLock validPassword={validPassword} />} @@ -252,10 +253,10 @@ const LayoutSlug = props => { </div> <div className='block lg:hidden'> - <TocDrawer post={post} cRef={drawerRight} targetRef={targetRef} /> + <TocDrawer post={post} cRef={drawerRight} targetRef={tocRef} /> </div> - </div> + </> ) } @@ -280,7 +281,7 @@ const Layout404 = props => { }, 3000) }) return ( - <div {...props}> + <> <div className="text-black w-full h-screen text-center justify-center content-center items-center flex flex-col"> <div className="dark:text-gray-200"> <h2 className="inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top"> @@ -291,7 +292,7 @@ const Layout404 = props => { </div> </div> </div> - </div> + </> ) } @@ -304,7 +305,7 @@ const LayoutCategoryIndex = props => { const { categoryOptions } = props const { locale } = useGlobal() return ( - <div {...props} className='mt-8'> + <div className='mt-8'> <Card className="w-full min-h-screen"> <div className="dark:text-gray-200 mb-5 mx-3"> <i className="mr-4 fas fa-th" /> {locale.COMMON.CATEGORY}: @@ -334,7 +335,7 @@ const LayoutTagIndex = props => { const { tagOptions } = props const { locale } = useGlobal() return ( - <div {...props} className='mt-8'> + <div className='mt-8'> <Card className='w-full'> <div className="dark:text-gray-200 mb-5 ml-4"> <i className="mr-4 fas fa-tag" /> {locale.COMMON.TAGS}: diff --git a/themes/landing/index.js b/themes/landing/index.js index 86ef856d..51bf84ff 100644 --- a/themes/landing/index.js +++ b/themes/landing/index.js @@ -57,13 +57,13 @@ const LayoutBase = (props) => { */ const LayoutIndex = (props) => { return ( - <div {...props}> + <> <Hero /> <Features /> <FeaturesBlocks /> <Testimonials /> <Newsletter /> - </div> + </> ) } @@ -81,21 +81,20 @@ const LayoutSlug = (props) => { return <div id='theme-landing'><Loading /></div> } - return <div {...props}> - + return <> <div id='container-inner' className='mx-auto max-w-screen-lg p-12'> <NotionPage {...props} /> </div> - </div> + </> } // 其他布局暂时留空 -const LayoutSearch = (props) => <div {...props}><Hero /></div> -const LayoutArchive = (props) => <div {...props}><Hero /></div> -const Layout404 = (props) => <div {...props}><Hero /></div> -const LayoutCategoryIndex = (props) => <div {...props}><Hero /></div> -const LayoutPostList = (props) => <div {...props}><Hero /></div> -const LayoutTagIndex = (props) => <div {...props}><Hero /></div> +const LayoutSearch = (props) => <><Hero /></> +const LayoutArchive = (props) => <><Hero /></> +const Layout404 = (props) => <><Hero /></> +const LayoutCategoryIndex = (props) => <><Hero /></> +const LayoutPostList = (props) => <><Hero /></> +const LayoutTagIndex = (props) => <><Hero /></> export { CONFIG as THEME_CONFIG, diff --git a/themes/matery/index.js b/themes/matery/index.js index 80ed61ee..ce099cd7 100644 --- a/themes/matery/index.js +++ b/themes/matery/index.js @@ -44,7 +44,10 @@ const LayoutBase = props => { const { onLoading, fullWidth } = useGlobal() const router = useRouter() const containerSlot= router.route==='/' ? <Announcement {...props} /> : <BlogListBar {...props} /> - const headerSlot= siteConfig('MATERY_HOME_BANNER_ENABLE', null, CONFIG) && router.route==='/' ? <Hero {...props} /> : null + const headerSlot= siteConfig('MATERY_HOME_BANNER_ENABLE', null, CONFIG) && router.route==='/' + ? <Hero {...props} /> : (post && !fullWidth ? <PostHeader {...props} /> : null) + + const floatRightBottom = post ? <JumpToCommentButton /> : null return ( <div id='theme-matery' className="min-h-screen flex flex-col justify-between bg-hexo-background-gray dark:bg-black w-full"> @@ -61,7 +64,7 @@ const LayoutBase = props => { appear={true} enter="transition ease-in-out duration-700 transform order-first" enterFrom="opacity-0 -translate-y-16" - enterTo="opacity-100" + enterTo="opacity-100 w-full" leave="transition ease-in-out duration-300 transform" leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 translate-y-16" @@ -82,7 +85,7 @@ const LayoutBase = props => { appear={true} enter="transition ease-in-out duration-700 transform order-first" enterFrom="opacity-0 translate-y-16" - enterTo="opacity-100" + enterTo="opacity-100 w-full" leave="transition ease-in-out duration-300 transform" leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 -translate-y-16" @@ -101,7 +104,7 @@ const LayoutBase = props => { </div> {/* 右下角悬浮 */} - <RightFloatButtons {...props} /> + <RightFloatButtons {...props} floatRightBottom={floatRightBottom}/> {/* 页脚 */} <Footer title={siteConfig('TITLE')} /> @@ -155,13 +158,13 @@ const LayoutSearch = props => { } }) return ( - <div {...props} currentSearch={currentSearch}> + <> {!currentSearch ? <SearchNave {...props} /> : <div id="posts-wrapper"> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} </div>} - </div> + </> ) } @@ -172,7 +175,7 @@ const LayoutSearch = props => { */ const LayoutArchive = (props) => { const { archivePosts } = props - return <div {...props} headerSlot={<PostHeader {...props} />} > + return <> <Card className='w-full -mt-32'> <div className="mb-10 pb-20 bg-white md:p-12 p-3 min-h-full dark:bg-hexo-black-gray"> {Object.keys(archivePosts).map(archiveTitle => ( @@ -184,7 +187,7 @@ const LayoutArchive = (props) => { ))} </div> </Card> - </div> + </> } /** @@ -195,9 +198,8 @@ const LayoutArchive = (props) => { const LayoutSlug = props => { const { post, lock, validPassword } = props const { fullWidth } = useGlobal() - const headerSlot = fullWidth ? null : <PostHeader {...props} /> - - return (<div {...props} headerSlot={headerSlot} showCategory={false} showTag={false} floatRightBottom={<JumpToCommentButton />}> + + return (<> <div id='inner-wrapper' className={`w-full ${fullWidth ? '' : 'lg:max-w-3xl 2xl:max-w-4xl'}`} > @@ -260,7 +262,7 @@ const LayoutSlug = props => { </div> - </div> + </> ) } @@ -283,7 +285,7 @@ const Layout404 = props => { }, 3000) }) return ( - <div {...props}> + <> <div className="text-black w-full h-screen text-center justify-center content-center items-center flex flex-col"> <div className="dark:text-gray-200"> <h2 className="inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top"> @@ -294,7 +296,7 @@ const Layout404 = props => { </div> </div> </div> - </div> + </> ) } @@ -307,7 +309,7 @@ const LayoutCategoryIndex = props => { const { categoryOptions } = props return ( - <div {...props} headerSlot={<PostHeader {...props} />} > + <> <div id='inner-wrapper' className='w-full'> <div className="drop-shadow-xl -mt-32 rounded-md mx-3 px-5 lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black dark:text-gray-300"> @@ -324,7 +326,7 @@ const LayoutCategoryIndex = props => { </div> </div> </div> - </div> + </> ) } @@ -337,7 +339,7 @@ const LayoutTagIndex = props => { const { tagOptions } = props const { locale } = useGlobal() return ( - <div {...props} headerSlot={<PostHeader {...props} />} > + <> <div id='inner-wrapper' className='w-full drop-shadow-xl'> <div className="-mt-32 rounded-md mx-3 px-5 lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black"> @@ -357,7 +359,7 @@ const LayoutTagIndex = props => { </div> </div> </div> - </div> + </> ) } diff --git a/themes/medium/index.js b/themes/medium/index.js index cb6bf541..8087057c 100644 --- a/themes/medium/index.js +++ b/themes/medium/index.js @@ -47,12 +47,14 @@ export const useMediumGlobal = () => useContext(ThemeGlobalMedium) * @constructor */ const LayoutBase = props => { - const { children, showInfoCard = true, slotRight, slotTop, notice, meta } = props + const { children, showInfoCard = true, slotRight, notice, meta } = props const { locale } = useGlobal() const router = useRouter() const [tocVisible, changeTocVisible] = useState(false) const { onLoading, fullWidth } = useGlobal() + const slotTop = <BlogPostBar {...props} /> + return ( <ThemeGlobalMedium.Provider value={{ tocVisible, changeTocVisible }}> {/* SEO相关 */} @@ -137,10 +139,9 @@ const LayoutIndex = (props) => { * @returns */ const LayoutPostList = (props) => { - const slotTop = <BlogPostBar {...props} /> - return <div {...props} slotTop={slotTop}> + return <> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} - </div> + </> } /** @@ -220,7 +221,7 @@ const LayoutSearch = (props) => { } }, []) - return <div {...props}> + return <> {/* 搜索导航栏 */} <div className='py-12'> @@ -236,7 +237,7 @@ const LayoutSearch = (props) => { {currentSearch && <div> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} </div>} - </div> + </> } /** @@ -247,12 +248,12 @@ const LayoutSearch = (props) => { const LayoutArchive = props => { const { archivePosts } = props return ( - <div {...props}> + <> <div className="mb-10 pb-20 md:py-12 py-3 min-h-full"> {Object.keys(archivePosts)?.map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} /> )} </div> - </div> + </> ) } @@ -262,9 +263,9 @@ const LayoutArchive = props => { * @returns */ const Layout404 = props => { - return <div {...props}> + return <> <div className='w-full h-96 py-80 flex justify-center items-center'>404 Not found.</div> - </div> + </> } /** @@ -276,7 +277,7 @@ const LayoutCategoryIndex = (props) => { const { categoryOptions } = props const { locale } = useGlobal() return ( - <div {...props}> + <> <div className='bg-white dark:bg-gray-700 py-10'> <div className='dark:text-gray-200 mb-5'> <i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}: @@ -298,7 +299,7 @@ const LayoutCategoryIndex = (props) => { })} </div> </div> - </div> + </> ) } @@ -311,7 +312,7 @@ const LayoutTagIndex = props => { const { tagOptions } = props const { locale } = useGlobal() return ( - <div {...props}> + <> <div className="bg-white dark:bg-gray-700 py-10"> <div className="dark:text-gray-200 mb-5"> <i className="mr-4 fas fa-tag" /> @@ -327,7 +328,7 @@ const LayoutTagIndex = props => { })} </div> </div> - </div> + </> ) } diff --git a/themes/nav/components/MenuItem.js b/themes/nav/components/MenuItem.js index 9eeb5ecf..84d2a42e 100644 --- a/themes/nav/components/MenuItem.js +++ b/themes/nav/components/MenuItem.js @@ -50,9 +50,9 @@ export const MenuItem = ({ link }) => { { link?.subMenus?.map((sLink, index) => ( <div key={index} className='nav-submenu'> - <a href={sLink?.to}> + <Link href={sLink?.to}> <span className='dark:text-neutral-400 text-gray-500 hover:text-black dark:hover:text-white text-xs font-bold'><i className={`text-xs mr-1 ${sLink?.icon ? sLink?.icon : 'fas fa-hashtag'}`} />{sLink.title}</span> - </a> + </Link> </div> )) } diff --git a/themes/nav/index.js b/themes/nav/index.js index 9c98dab2..bf6e4662 100755 --- a/themes/nav/index.js +++ b/themes/nav/index.js @@ -172,10 +172,10 @@ const LayoutPostListIndex = props => { // const { customMenu, children, post, allNavPages, categoryOptions, slotLeft, slotRight, slotTop, meta } = props // const [filteredNavPages, setFilteredNavPages] = useState(allNavPages) return ( - <div {...props} > + <> <Announcement {...props} /> <BlogPostListAll { ...props } /> - </div> + </> ) } @@ -189,7 +189,7 @@ const LayoutPostList = props => { // 顶部如果是按照分类或标签查看文章列表,列表顶部嵌入一个横幅 // 如果是搜索,则列表顶部嵌入 搜索框 return ( - <div {...props} > + <> <div className='w-full max-w-7xl mx-auto justify-center mt-8'> <div id='posts-wrapper' class='card-list grid gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5'> {posts?.map(post => ( @@ -197,7 +197,7 @@ const LayoutPostList = props => { ))} </div> </div> - </div> + </> ) } @@ -210,7 +210,7 @@ const LayoutSlug = (props) => { const { post, lock, validPassword } = props return ( - <div {...props} > + <> {/* 文章锁 */} {lock && <ArticleLock validPassword={validPassword} />} @@ -244,7 +244,7 @@ const LayoutSlug = (props) => { <TocDrawer {...props} /> </div>} - </div> + </> ) } @@ -255,7 +255,7 @@ const LayoutSlug = (props) => { * @returns */ const LayoutSearch = (props) => { - return <div {...props}></div> + return <></> } /** @@ -267,20 +267,20 @@ const LayoutSearch = (props) => { const LayoutArchive = (props) => { const { archivePosts } = props - return <div {...props}> + return <> <div className="mb-10 pb-20 md:py-12 py-3 min-h-full"> {Object.keys(archivePosts)?.map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} </div> - </div> + </> } /** * 404 */ const Layout404 = props => { - return <div {...props}> + return <> <div className='w-full h-96 py-80 flex justify-center items-center'>404 Not found.</div> - </div> + </> } /** @@ -289,7 +289,7 @@ const Layout404 = props => { const LayoutCategoryIndex = (props) => { const { categoryOptions } = props const { locale } = useGlobal() - return <div {...props}> + return <> <div className='bg-white dark:bg-gray-700 py-10'> <div className='dark:text-gray-200 mb-5'> <i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}: @@ -311,7 +311,7 @@ const LayoutCategoryIndex = (props) => { })} </div> </div> - </div> + </> } /** @@ -321,7 +321,7 @@ const LayoutTagIndex = (props) => { const { tagOptions } = props const { locale } = useGlobal() - return <div {...props}> + return <> <div className="bg-white dark:bg-gray-700 py-10"> <div className="dark:text-gray-200 mb-5"> <i className="mr-4 fas fa-tag" /> @@ -337,7 +337,7 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </div> + </> } export { diff --git a/themes/next/components/Card.js b/themes/next/components/Card.js index a1c507b6..de70f580 100644 --- a/themes/next/components/Card.js +++ b/themes/next/components/Card.js @@ -1,10 +1,15 @@ +/** + * 卡片组件 + * @param {*} param0 + * @returns + */ const Card = (props) => { - const { children, headerSlot } = props - return <div {...props}> - <>{headerSlot}</> - <section className="shadow px-2 py-4 bg-white dark:bg-hexo-black-gray hover:shadow-xl duration-200"> - {children} - </section> - </div> + const { children, headerSlot, className } = props + return <div className={className}> + <>{headerSlot}</> + <section className="shadow px-2 py-4 bg-white dark:bg-hexo-black-gray hover:shadow-xl duration-200"> + {children} + </section> + </div> } export default Card diff --git a/themes/next/index.js b/themes/next/index.js index 0203b749..35a6091a 100644 --- a/themes/next/index.js +++ b/themes/next/index.js @@ -33,7 +33,7 @@ import { siteConfig } from '@/lib/config' * @constructor */ const LayoutBase = (props) => { - const { children, headerSlot, floatSlot, rightAreaSlot, meta } = props + const { children, headerSlot, rightAreaSlot, meta, post } = props const { onLoading } = useGlobal() const targetRef = useRef(null) const floatButtonGroup = useRef(null) @@ -67,6 +67,15 @@ const LayoutBase = (props) => { return () => document.removeEventListener('scroll', scrollListener) }, [showRightFloat]) + // 悬浮抽屉 + const drawerRight = useRef(null) + const floatSlot = <div className='block lg:hidden'> + <TocDrawerButton onClick={() => { + drawerRight?.current?.handleSwitchVisible() + }} /> + </div> + const tocRef = isBrowser ? document.getElementById('article-wrapper') : null + return ( <div id='theme-next'> {/* SEO相关 */} @@ -105,8 +114,14 @@ const LayoutBase = (props) => { {/* 右侧栏样式 */} {siteConfig('NEXT_RIGHT_BAR', null, CONFIG) && <SideAreaRight targetRef={targetRef} slot={rightAreaSlot} {...props} />} + </main> + {/* 悬浮目录按钮 */} + {post && <div className='block lg:hidden'> + <TocDrawer post={post} cRef={drawerRight} targetRef={tocRef} /> + </div>} + {/* 右下角悬浮 */} <div ref={floatButtonGroup} className='right-8 bottom-12 lg:right-2 fixed justify-end z-20 font-sans'> <div className={(showRightFloat ? 'animate__animated ' : 'hidden') + ' animate__fadeInUp rounded-md glassmorphism justify-center duration-500 animate__faster flex space-x-2 items-center cursor-pointer '}> @@ -139,7 +154,7 @@ const LayoutIndex = (props) => { * @returns */ const LayoutPostList = (props) => { - return <div {...props} > + return <> <BlogListBar {...props} /> @@ -147,7 +162,7 @@ const LayoutPostList = (props) => { ? <BlogPostListScroll {...props} showSummary={true} /> : <BlogPostListPage {...props} /> } - </div> + </> } /** @@ -173,7 +188,7 @@ const LayoutSearch = (props) => { }, []) return ( - <div {...props} > + <> <StickyBar> <div className="p-4 dark:text-gray-200"> <i className="mr-1 fas fa-search" />{' '} @@ -186,7 +201,7 @@ const LayoutSearch = (props) => { : <BlogPostListPage {...props} /> } </div> - </div> + </> ) } @@ -230,7 +245,7 @@ const LayoutArchive = (props) => { const { archivePosts } = props return ( - <div {...props}> + <> <div className="mb-10 pb-20 bg-white md:p-12 p-3 dark:bg-hexo-black-gray shadow-md min-h-full"> {Object.keys(archivePosts).map(archiveTitle => ( <BlogPostArchive @@ -240,7 +255,7 @@ const LayoutArchive = (props) => { /> ))} </div> - </div> + </> ) } @@ -251,27 +266,14 @@ const LayoutArchive = (props) => { */ const LayoutSlug = (props) => { const { post, lock, validPassword } = props - const drawerRight = useRef(null) - const targetRef = isBrowser ? document.getElementById('article-wrapper') : null - const floatSlot = <div className='block lg:hidden'> - <TocDrawerButton onClick={() => { - drawerRight?.current?.handleSwitchVisible() - }} /> - </div> - return ( - <div {...props} floatSlot={floatSlot}> + <> {post && !lock && <ArticleDetail {...props} />} {post && lock && <ArticleLock validPassword={validPassword} />} - {/* 悬浮目录按钮 */} - {post && <div className='block lg:hidden'> - <TocDrawer post={post} cRef={drawerRight} targetRef={targetRef} /> - </div>} - - </div> + </> ) } @@ -318,7 +320,7 @@ const LayoutCategoryIndex = (props) => { const LayoutTagIndex = (props) => { const { tagOptions } = props const { locale } = useGlobal() - return <div {...props}> + return <> <div className='bg-white dark:bg-hexo-black-gray px-10 py-10 shadow h-full'> <div className='dark:text-gray-200 mb-5'><i className='fas fa-tags mr-4' />{locale.COMMON.TAGS}:</div> <div id='tags-list' className='duration-200 flex flex-wrap'> @@ -327,7 +329,7 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </div> + </> } export { diff --git a/themes/nobelium/components/BlogListBar.js b/themes/nobelium/components/BlogListBar.js index 69076937..57ca7e7b 100644 --- a/themes/nobelium/components/BlogListBar.js +++ b/themes/nobelium/components/BlogListBar.js @@ -1,7 +1,8 @@ +import { useNobeliumGlobal } from '..' import Tags from './Tags' export default function BlogListBar(props) { - const { tag, setFilterKey } = props + const { tag, setFilterKey } = useNobeliumGlobal() const handleSearchChange = (val) => { setFilterKey(val) } diff --git a/themes/nobelium/index.js b/themes/nobelium/index.js index f5152842..83650ae8 100644 --- a/themes/nobelium/index.js +++ b/themes/nobelium/index.js @@ -37,14 +37,16 @@ export const useNobeliumGlobal = () => useContext(ThemeGlobalNobelium) * @constructor */ const LayoutBase = props => { - const { children, post, topSlot, meta } = props - + const { children, post, meta } = props const fullWidth = post?.fullWidth ?? false const { onLoading } = useGlobal() const searchModal = useRef(null) + // 在列表中进行实时过滤 + const [filterKey, setFilterKey] = useState('') + const topSlot= <BlogListBar {...props}/> return ( - <ThemeGlobalNobelium.Provider value={{ searchModal }}> + <ThemeGlobalNobelium.Provider value={{ searchModal, filterKey, setFilterKey }}> <div id='theme-nobelium' className='nobelium relative dark:text-gray-300 w-full bg-white dark:bg-black min-h-screen flex flex-col'> {/* SEO相关 */} <CommonHead meta={meta} /> @@ -114,10 +116,8 @@ const LayoutIndex = props => { * @returns */ const LayoutPostList = props => { - const { posts, topSlot } = props - - // 在列表中进行实时过滤 - const [filterKey, setFilterKey] = useState('') + const { posts, topSlot,tag } = props + const { filterKey } = useNobeliumGlobal() let filteredBlogPosts = [] if (filterKey && posts) { filteredBlogPosts = posts.filter(post => { @@ -130,10 +130,11 @@ const LayoutPostList = props => { } return ( - <div {...props} topSlot={<BlogListBar {...props} setFilterKey={setFilterKey} />}> + <> {topSlot} + {tag && <SearchNavBar {...props} />} {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} posts={filteredBlogPosts} /> : <BlogListScroll {...props} posts={filteredBlogPosts} />} - </div> + </> ) } @@ -159,7 +160,7 @@ const LayoutSearch = props => { }, []) // 在列表中进行实时过滤 - const [filterKey, setFilterKey] = useState('') + const {filterKey} = useNobeliumGlobal() let filteredBlogPosts = [] if (filterKey && posts) { filteredBlogPosts = posts.filter(post => { @@ -171,10 +172,10 @@ const LayoutSearch = props => { filteredBlogPosts = deepClone(posts) } - return <div {...props} topSlot={<BlogListBar {...props} setFilterKey={setFilterKey} />}> + return <> <SearchNavBar {...props} /> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} posts={filteredBlogPosts} /> : <BlogListScroll {...props} posts={filteredBlogPosts} />} - </div> + </> } /** @@ -185,11 +186,11 @@ const LayoutSearch = props => { const LayoutArchive = props => { const { archivePosts } = props return ( - <div {...props}> + <> <div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full"> {Object.keys(archivePosts).map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} </div> - </div> + </> ) } @@ -202,7 +203,7 @@ const LayoutSlug = props => { const { post, lock, validPassword } = props return ( - <div {...props}> + <> {lock && <ArticleLock validPassword={validPassword} />} @@ -216,7 +217,7 @@ const LayoutSlug = props => { </> </div>} - </div> + </> ) } @@ -226,9 +227,9 @@ const LayoutSlug = props => { * @returns */ const Layout404 = (props) => { - return <div {...props}> + return <> 404 Not found. - </div> + </> } /** @@ -240,7 +241,7 @@ const LayoutCategoryIndex = (props) => { const { categoryOptions } = props return ( - <div {...props}> + <> <div id='category-list' className='duration-200 flex flex-wrap'> {categoryOptions?.map(category => { return ( @@ -257,7 +258,7 @@ const LayoutCategoryIndex = (props) => { ) })} </div> - </div> + </> ) } @@ -269,7 +270,7 @@ const LayoutCategoryIndex = (props) => { const LayoutTagIndex = (props) => { const { tagOptions } = props return ( - <div {...props}> + <> <div> <div id='tags-list' className='duration-200 flex flex-wrap'> {tagOptions.map(tag => { @@ -284,7 +285,7 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </div> + </> ) } diff --git a/themes/plog/components/BlogListBar.js b/themes/plog/components/BlogListBar.js deleted file mode 100644 index 69076937..00000000 --- a/themes/plog/components/BlogListBar.js +++ /dev/null @@ -1,39 +0,0 @@ -import Tags from './Tags' - -export default function BlogListBar(props) { - const { tag, setFilterKey } = props - const handleSearchChange = (val) => { - setFilterKey(val) - } - if (tag) { - return (<div className="mb-4"> - <div className='relative'> - <input - type="text" - placeholder={ - tag ? `Search in #${tag}` : 'Search Articles' - } - className="outline-none block w-full border px-4 py-2 border-black bg-white text-black dark:bg-night dark:border-white dark:text-white" - onChange={e => handleSearchChange(e.target.value)} - /> - <svg - className="absolute right-3 top-3 h-5 w-5 text-black dark:text-white" - xmlns="http://www.w3.org/2000/svg" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth="2" - d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" - ></path> - </svg> - </div> - <Tags {...props} /> - </div>) - } else { - return <></> - } -} diff --git a/themes/plog/components/Modal.js b/themes/plog/components/Modal.js index 24494df7..8c490093 100644 --- a/themes/plog/components/Modal.js +++ b/themes/plog/components/Modal.js @@ -5,6 +5,7 @@ import { ArrowPath, ChevronLeft, ChevronRight } from '@/components/HeroIcons' import Link from 'next/link' import { siteConfig } from '@/lib/config' import LazyImage from '@/components/LazyImage' +import { compressImage } from '@/lib/notion/mapImage' /** * 弹出框 @@ -13,7 +14,7 @@ export default function Modal(props) { const { showModal, setShowModal, modalContent, setModalContent } = usePlogGlobal() const { siteInfo, posts } = props const cancelButtonRef = useRef(null) - const img = modalContent?.pageCover || siteInfo?.pageCover + const img = compressImage(modalContent?.pageCover || siteInfo?.pageCover, 1200, 85, 'webp') const imgRef = useRef(null) // 添加loading状态 diff --git a/themes/plog/index.js b/themes/plog/index.js index a777055b..07d34068 100644 --- a/themes/plog/index.js +++ b/themes/plog/index.js @@ -98,9 +98,9 @@ const LayoutIndex = props => { */ const LayoutPostList = props => { return ( - <div {...props}> + <> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />} - </div> + </> ) } @@ -137,11 +137,11 @@ const LayoutSearch = props => { const LayoutArchive = props => { const { archivePosts } = props return ( - <div {...props}> + <> <div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full"> {Object.keys(archivePosts).map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} </div> - </div> + </> ) } @@ -154,7 +154,7 @@ const LayoutSlug = props => { const { post, lock, validPassword } = props return ( - <div {...props}> + <> {lock && <ArticleLock validPassword={validPassword} />} @@ -168,7 +168,7 @@ const LayoutSlug = props => { </> </div>} - </div> + </> ) } @@ -178,9 +178,9 @@ const LayoutSlug = props => { * @returns */ const Layout404 = (props) => { - return <div {...props}> + return <> 404 Not found. - </div> + </> } /** @@ -192,7 +192,7 @@ const LayoutCategoryIndex = (props) => { const { categoryOptions } = props return ( - <div {...props}> + <> <div id='category-list' className='duration-200 flex flex-wrap'> {categoryOptions?.map(category => { return ( @@ -209,7 +209,7 @@ const LayoutCategoryIndex = (props) => { ) })} </div> - </div> + </> ) } @@ -221,7 +221,7 @@ const LayoutCategoryIndex = (props) => { const LayoutTagIndex = (props) => { const { tagOptions } = props return ( - <div {...props}> + <> <div> <div id='tags-list' className='duration-200 flex flex-wrap'> {tagOptions.map(tag => { @@ -236,7 +236,7 @@ const LayoutTagIndex = (props) => { })} </div> </div> - </div> + </> ) } diff --git a/themes/simple/index.js b/themes/simple/index.js index 36e48586..c4a705a7 100644 --- a/themes/simple/index.js +++ b/themes/simple/index.js @@ -120,9 +120,9 @@ const LayoutIndex = props => { */ const LayoutPostList = props => { return ( - <div {...props}> + <> {siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />} - </div> + </> ) } @@ -161,11 +161,11 @@ const LayoutSearch = props => { const LayoutArchive = props => { const { archivePosts } = props return ( - <div {...props}> + <> <div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full"> {Object.keys(archivePosts).map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} </div> - </div> + </> ) } @@ -179,7 +179,7 @@ const LayoutSlug = props => { const { fullWidth } = useGlobal() return ( - <div {...props}> + <> {lock && <ArticleLock validPassword={validPassword} />} @@ -208,7 +208,7 @@ const LayoutSlug = props => { </div> - </div> + </> ) } @@ -218,9 +218,9 @@ const LayoutSlug = props => { * @returns */ const Layout404 = (props) => { - return <div {...props}> + return <> 404 Not found. - </div> + </> } /** @@ -231,7 +231,7 @@ const Layout404 = (props) => { const LayoutCategoryIndex = props => { const { categoryOptions } = props return ( - <div {...props}> + <> <div id='category-list' className='duration-200 flex flex-wrap'> {categoryOptions?.map(category => { return ( @@ -248,7 +248,7 @@ const LayoutCategoryIndex = props => { ) })} </div> - </div> + </> ) } @@ -260,7 +260,7 @@ const LayoutCategoryIndex = props => { const LayoutTagIndex = (props) => { const { tagOptions } = props return ( - <div {...props}> + <> <div id='tags-list' className='duration-200 flex flex-wrap'> {tagOptions.map(tag => { return ( @@ -276,7 +276,7 @@ const LayoutTagIndex = (props) => { ) })} </div> - </div> + </> ) } From 7951ec963330b7ac1de7678b9883df1bd047f809 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" <tlyong1992@hotmail.com> Date: Tue, 30 Jan 2024 18:09:55 +0800 Subject: [PATCH 53/53] gitbook version --- themes/gitbook/components/Footer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/gitbook/components/Footer.js b/themes/gitbook/components/Footer.js index 1f7d86fb..78a91cd5 100644 --- a/themes/gitbook/components/Footer.js +++ b/themes/gitbook/components/Footer.js @@ -17,7 +17,7 @@ const Footer = ({ siteInfo }) => { © {`${copyrightDate}`} </div> - <div className='text-xs font-serif'>Powered By <a href='https://github.com/tangly1024/NotionNext' className='underline text-gray-500 dark:text-gray-300'>NotionNext</a></div> + <div className='text-xs font-serif'>Powered By <a href='https://github.com/tangly1024/NotionNext' className='underline text-gray-500 dark:text-gray-300'>NotionNext {siteConfig('VERSION')}</a></div> {siteConfig('BEI_AN') && <><i className='fas fa-shield-alt' /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{siteConfig('BEI_AN')}</a><br /></>}