diff --git a/themes/fukasawa/components/Catalog.js b/themes/fukasawa/components/Catalog.js index 0e1cde78..4bee0c3e 100644 --- a/themes/fukasawa/components/Catalog.js +++ b/themes/fukasawa/components/Catalog.js @@ -1,7 +1,7 @@ -import { useEffect, useRef, useState } from 'react' +import { useGlobal } from '@/lib/global' import throttle from 'lodash.throttle' import { uuidToId } from 'notion-utils' -import { useGlobal } from '@/lib/global' +import { useEffect, useRef, useState } from 'react' /** * 目录导航组件 @@ -58,29 +58,37 @@ const Catalog = ({ toc }) => { if (!toc || toc?.length < 1) { return <> } - return
-
{locale.COMMON.TABLE_OF_CONTENTS}
- -
+ return ( +
+
+ + {locale.COMMON.TABLE_OF_CONTENTS} +
+ +
+ ) } export default Catalog diff --git a/themes/hexo/components/Catalog.js b/themes/hexo/components/Catalog.js index 0bc2e616..33111801 100644 --- a/themes/hexo/components/Catalog.js +++ b/themes/hexo/components/Catalog.js @@ -1,8 +1,8 @@ -import { useCallback, useEffect, useRef, useState } from 'react' +import { useGlobal } from '@/lib/global' import throttle from 'lodash.throttle' import { uuidToId } from 'notion-utils' +import { useCallback, useEffect, useRef, useState } from 'react' import Progress from './Progress' -import { useGlobal } from '@/lib/global' /** * 目录导航组件 @@ -29,67 +29,77 @@ const Catalog = ({ toc }) => { const [activeSection, setActiveSection] = useState(null) const throttleMs = 200 - const actionSectionScrollSpy = useCallback(throttle(() => { - const sections = document.getElementsByClassName('notion-h') - let prevBBox = null - let currentSectionId = activeSection - for (let i = 0; i < sections.length; ++i) { - const section = sections[i] - if (!section || !(section instanceof Element)) continue - if (!currentSectionId) { - currentSectionId = section.getAttribute('data-id') + const actionSectionScrollSpy = useCallback( + throttle(() => { + const sections = document.getElementsByClassName('notion-h') + let prevBBox = null + let currentSectionId = activeSection + for (let i = 0; i < sections.length; ++i) { + const section = sections[i] + if (!section || !(section instanceof Element)) continue + if (!currentSectionId) { + currentSectionId = section.getAttribute('data-id') + } + const bbox = section.getBoundingClientRect() + const prevHeight = prevBBox ? bbox.top - prevBBox.bottom : 0 + const offset = Math.max(150, prevHeight / 4) + // GetBoundingClientRect returns values relative to viewport + if (bbox.top - offset < 0) { + currentSectionId = section.getAttribute('data-id') + prevBBox = bbox + continue + } + // No need to continue loop, if last element has been detected + break } - const bbox = section.getBoundingClientRect() - const prevHeight = prevBBox ? bbox.top - prevBBox.bottom : 0 - const offset = Math.max(150, prevHeight / 4) - // GetBoundingClientRect returns values relative to viewport - if (bbox.top - offset < 0) { - currentSectionId = section.getAttribute('data-id') - prevBBox = bbox - continue - } - // No need to continue loop, if last element has been detected - break - } - setActiveSection(currentSectionId) - const index = tocIds.indexOf(currentSectionId) || 0 - tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' }) - }, throttleMs)) + setActiveSection(currentSectionId) + const index = tocIds.indexOf(currentSectionId) || 0 + tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' }) + }, throttleMs) + ) // 无目录就直接返回空 if (!toc || toc.length < 1) { return <> } - return
-
{locale.COMMON.TABLE_OF_CONTENTS}
-
- + return ( +
+
+ + {locale.COMMON.TABLE_OF_CONTENTS} +
+
+ +
+
+ +
-
- - -
-
+ ) } export default Catalog diff --git a/themes/magzine/components/Catalog.js b/themes/magzine/components/Catalog.js index 0c5412d2..29ce6152 100644 --- a/themes/magzine/components/Catalog.js +++ b/themes/magzine/components/Catalog.js @@ -64,6 +64,7 @@ const Catalog = ({ post, toc, className }) => { return (
+ {/* 阅读进度条 */}
{ + className={`${activeSection === id && 'dark:border-white border-gray-800 text-gray-800 font-bold'} hover:font-semibold border-l pl-4 block hover:text-gray-800 border-lduration-300 transform dark:text-gray-400 dark:border-gray-400 + notion-table-of-contents-item-indent-level-${tocItem.indentLevel} `}> + className={`truncate ${activeSection === id ? ' font-bold text-black dark:text-white underline' : ''}`}> {tocItem.text} diff --git a/themes/magzine/components/Header.js b/themes/magzine/components/Header.js index d9896d3d..06ea6fec 100644 --- a/themes/magzine/components/Header.js +++ b/themes/magzine/components/Header.js @@ -1,4 +1,5 @@ import Collapse from '@/components/Collapse' +import DarkModeButton from '@/components/DarkModeButton' import { siteConfig } from '@/lib/config' import { useGlobal } from '@/lib/global' import { SignInButton, SignedOut, UserButton } from '@clerk/nextjs' @@ -162,15 +163,21 @@ export default function Header(props) { {/* 搜索按钮 */}
+ className='flex text-center items-center cursor-pointer p-2.5 hover:bg-black hover:bg-opacity-10 rounded-full'>
+ {/* 深色模式切换 */} +
+ +
+ {/* 移动端显示开关 */}
diff --git a/themes/magzine/components/Progress.js b/themes/magzine/components/Progress.js index 8a3db8b5..38ad79c4 100644 --- a/themes/magzine/components/Progress.js +++ b/themes/magzine/components/Progress.js @@ -31,7 +31,7 @@ const Progress = ({ targetRef, showPercent = true }) => { return (
{showPercent && (
{percent}%
diff --git a/themes/next/components/Toc.js b/themes/next/components/Toc.js index 435679fd..388d3fa1 100644 --- a/themes/next/components/Toc.js +++ b/themes/next/components/Toc.js @@ -1,10 +1,10 @@ -import { useCallback, useEffect, useRef, useState } from 'react' import throttle from 'lodash.throttle' import { uuidToId } from 'notion-utils' +import { useCallback, useEffect, useRef, useState } from 'react' import Progress from './Progress' /** - * 目录导航组件 + * 目录导航组件 Table of Contents * @param toc * @returns {JSX.Element} * @constructor @@ -26,63 +26,73 @@ const Toc = ({ toc }) => { // 同步选中目录事件 const [activeSection, setActiveSection] = useState(null) const throttleMs = 200 - const actionSectionScrollSpy = useCallback(throttle(() => { - const sections = document.getElementsByClassName('notion-h') - let prevBBox = null - let currentSectionId = activeSection - for (let i = 0; i < sections.length; ++i) { - const section = sections[i] - if (!section || !(section instanceof Element)) continue - if (!currentSectionId) { - currentSectionId = section.getAttribute('data-id') + const actionSectionScrollSpy = useCallback( + throttle(() => { + const sections = document.getElementsByClassName('notion-h') + let prevBBox = null + let currentSectionId = activeSection + for (let i = 0; i < sections.length; ++i) { + const section = sections[i] + if (!section || !(section instanceof Element)) continue + if (!currentSectionId) { + currentSectionId = section.getAttribute('data-id') + } + const bbox = section.getBoundingClientRect() + const prevHeight = prevBBox ? bbox.top - prevBBox.bottom : 0 + const offset = Math.max(150, prevHeight / 4) + // GetBoundingClientRect returns values relative to viewport + if (bbox.top - offset < 0) { + currentSectionId = section.getAttribute('data-id') + prevBBox = bbox + continue + } + // No need to continue loop, if last element has been detected + break } - const bbox = section.getBoundingClientRect() - const prevHeight = prevBBox ? bbox.top - prevBBox.bottom : 0 - const offset = Math.max(150, prevHeight / 4) - // GetBoundingClientRect returns values relative to viewport - if (bbox.top - offset < 0) { - currentSectionId = section.getAttribute('data-id') - prevBBox = bbox - continue - } - // No need to continue loop, if last element has been detected - break - } - setActiveSection(currentSectionId) - const index = tocIds.indexOf(currentSectionId) || 0 - tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' }) - }, throttleMs)) + setActiveSection(currentSectionId) + const index = tocIds.indexOf(currentSectionId) || 0 + tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' }) + }, throttleMs) + ) // 无目录就直接返回空 if (!toc || toc.length < 1) { return <> } - return
-
- + return ( +
+
+ +
+
+ +
-
- -
-
+ ) } export default Toc diff --git a/themes/nobelium/components/Catalog.js b/themes/nobelium/components/Catalog.js new file mode 100644 index 00000000..db881e93 --- /dev/null +++ b/themes/nobelium/components/Catalog.js @@ -0,0 +1,96 @@ +import throttle from 'lodash.throttle' +import { uuidToId } from 'notion-utils' +import { useCallback, useEffect, useRef, useState } from 'react' + +/** + * 目录导航组件 + * @param toc + * @returns {JSX.Element} + * @constructor + */ +const Catalog = ({ toc }) => { + // 监听滚动事件 + useEffect(() => { + window.addEventListener('scroll', actionSectionScrollSpy) + actionSectionScrollSpy() + return () => { + window.removeEventListener('scroll', actionSectionScrollSpy) + } + }, []) + + // 目录自动滚动 + const tRef = useRef(null) + const tocIds = [] + + // 同步选中目录事件 + const [activeSection, setActiveSection] = useState(null) + const throttleMs = 200 + const actionSectionScrollSpy = useCallback( + throttle(() => { + const sections = document.getElementsByClassName('notion-h') + let prevBBox = null + let currentSectionId = activeSection + for (let i = 0; i < sections.length; ++i) { + const section = sections[i] + if (!section || !(section instanceof Element)) continue + if (!currentSectionId) { + currentSectionId = section.getAttribute('data-id') + } + const bbox = section.getBoundingClientRect() + const prevHeight = prevBBox ? bbox.top - prevBBox.bottom : 0 + const offset = Math.max(150, prevHeight / 4) + // GetBoundingClientRect returns values relative to viewport + if (bbox.top - offset < 0) { + currentSectionId = section.getAttribute('data-id') + prevBBox = bbox + continue + } + // No need to continue loop, if last element has been detected + break + } + setActiveSection(currentSectionId) + const index = tocIds.indexOf(currentSectionId) || 0 + tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' }) + }, throttleMs) + ) + + // 无目录就直接返回空 + if (!toc || toc.length < 1) { + return <> + } + + return ( +
+
+
+ +
+
+
+ ) +} + +export default Catalog diff --git a/themes/nobelium/components/Nav.js b/themes/nobelium/components/Nav.js index 7f699f97..112b8f1a 100644 --- a/themes/nobelium/components/Nav.js +++ b/themes/nobelium/components/Nav.js @@ -1,4 +1,5 @@ import Collapse from '@/components/Collapse' +import DarkModeButton from '@/components/DarkModeButton' import LazyImage from '@/components/LazyImage' import { siteConfig } from '@/lib/config' import { useGlobal } from '@/lib/global' @@ -14,7 +15,7 @@ import { SvgIcon } from './SvgIcon' * 顶部导航 */ const Nav = props => { - const { navBarTitle, fullWidth, siteInfo } = props + const { post, fullWidth, siteInfo } = props const autoCollapseNavBar = siteConfig( 'NOBELIUM_AUTO_COLLAPSE_NAV_BAR', true, @@ -54,7 +55,7 @@ const Nav = props => {
{/* */} - {siteConfig('NOBELIUM_NAV_NOTION_ICON', null, CONFIG) ? ( + {siteConfig('NOBELIUM_NAV_NOTION_ICON') ? ( { )}
- {navBarTitle ? ( + {post ? (

- {navBarTitle} + {post?.title}

) : (

@@ -97,34 +98,32 @@ const NavBar = props => { id: 2, name: locale.NAV.RSS, href: '/feed', - show: - siteConfig('ENABLE_RSS') && - siteConfig('NOBELIUM_MENU_RSS', null, CONFIG), + show: siteConfig('ENABLE_RSS') && siteConfig('NOBELIUM_MENU_RSS'), target: '_blank' }, { icon: 'fas fa-search', name: locale.NAV.SEARCH, href: '/search', - show: siteConfig('NOBELIUM_MENU_SEARCH', null, CONFIG) + show: siteConfig('NOBELIUM_MENU_SEARCH') }, { icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, href: '/archive', - show: siteConfig('NOBELIUM_MENU_ARCHIVE', null, CONFIG) + show: siteConfig('NOBELIUM_MENU_ARCHIVE') }, { icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, href: '/category', - show: siteConfig('NOBELIUM_MENU_CATEGORY', null, CONFIG) + show: siteConfig('NOBELIUM_MENU_CATEGORY') }, { icon: 'fas fa-tag', name: locale.COMMON.TAGS, href: '/tag', - show: siteConfig('NOBELIUM_MENU_TAG', null, CONFIG) + show: siteConfig('NOBELIUM_MENU_TAG') } ] if (customNav) { @@ -167,12 +166,14 @@ const NavBar = props => {

- {JSON.parse(siteConfig('NOBELIUM_MENU_RANDOM_POST', null, CONFIG)) && ( + {siteConfig('NOBELIUM_MENU_DARKMODE_BUTTON') && ( + + )} + + {siteConfig('NOBELIUM_MENU_RANDOM_POST') && ( )} - {JSON.parse(siteConfig('NOBELIUM_MENU_SEARCH_BUTTON', null, CONFIG)) && ( - - )} + {siteConfig('NOBELIUM_MENU_SEARCH_BUTTON') && } diff --git a/themes/nobelium/config.js b/themes/nobelium/config.js index 905a40e1..8dfe5895 100644 --- a/themes/nobelium/config.js +++ b/themes/nobelium/config.js @@ -4,6 +4,7 @@ const CONFIG = { // 特殊菜单 NOBELIUM_MENU_RANDOM_POST: true, // 是否显示随机跳转文章按钮 NOBELIUM_MENU_SEARCH_BUTTON: true, // 是否显示搜索按钮,该按钮支持Algolia搜索 + NOBELIUM_MENU_DARKMODE_BUTTON: true, // 菜单显示深色模式切换 // 默认菜单配置 (开启自定义菜单后,以下配置则失效,请在Notion中自行配置菜单) NOBELIUM_MENU_CATEGORY: false, // 显示分类 diff --git a/themes/nobelium/index.js b/themes/nobelium/index.js index 08186a47..ed2b6ea6 100644 --- a/themes/nobelium/index.js +++ b/themes/nobelium/index.js @@ -19,6 +19,7 @@ import BlogArchiveItem from './components/BlogArchiveItem' import BlogListBar from './components/BlogListBar' import { BlogListPage } from './components/BlogListPage' import { BlogListScroll } from './components/BlogListScroll' +import Catalog from './components/Catalog' import { Footer } from './components/Footer' import JumpToTopButton from './components/JumpToTopButton' import Nav from './components/Nav' @@ -78,6 +79,7 @@ const LayoutBase = props => { {/* 顶部插槽 */} {topSlot} {children} + {post && } diff --git a/themes/simple/components/Catalog.js b/themes/simple/components/Catalog.js index 928c3af8..0c4a04fe 100644 --- a/themes/simple/components/Catalog.js +++ b/themes/simple/components/Catalog.js @@ -1,7 +1,7 @@ -import { useEffect, useRef, useState } from 'react' +import { useGlobal } from '@/lib/global' import throttle from 'lodash.throttle' import { uuidToId } from 'notion-utils' -import { useGlobal } from '@/lib/global' +import { useEffect, useRef, useState } from 'react' /** * 目录导航组件 @@ -40,7 +40,9 @@ const Catalog = ({ post }) => { break } setActiveSection(currentSectionId) - const index = post?.toc?.findIndex(obj => uuidToId(obj.id) === currentSectionId) + const index = post?.toc?.findIndex( + obj => uuidToId(obj.id) === currentSectionId + ) tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' }) }, throttleMs) @@ -56,34 +58,40 @@ const Catalog = ({ post }) => { return <> } - return
-
- {locale.COMMON.TABLE_OF_CONTENTS} -
+ return ( +
+
+ + {locale.COMMON.TABLE_OF_CONTENTS} +
-
- - -
+
+ +
+ ) } export default Catalog