diff --git a/blog.config.js b/blog.config.js index 81c91c5e..2ca1c0fc 100644 --- a/blog.config.js +++ b/blog.config.js @@ -3,8 +3,7 @@ const BLOG = { // Important page_id!!!Duplicate Template from https://www.notion.so/tanghh/02ab3b8678004aa69e9e415905ef32a5 NOTION_PAGE_ID: - process.env.NOTION_PAGE_ID || - '02ab3b8678004aa69e9e415905ef32a5,en:7c1d570661754c8fbc568e00a01fd70e', + process.env.NOTION_PAGE_ID || '20cb7f4f464a80db8541cbd0da70a64b', THEME: process.env.NEXT_PUBLIC_THEME || 'typography', // 当前主题,在 themes 文件夹下可找到所有支持的主题;主题名称就是文件夹名,例如 example,fukasawa,gitbook,heo,hexo,landing,matery,medium,next,nobelium,plog,simple LANG: process.env.NEXT_PUBLIC_LANG || 'zh-CN', // e.g 'zh-CN','en-US' see /lib/lang.js for more. SINCE: process.env.NEXT_PUBLIC_SINCE || 2021, // e.g if leave this empty, current year will be used. @@ -20,7 +19,8 @@ const BLOG = { KEYWORDS: process.env.NEXT_PUBLIC_KEYWORD || 'Notion, 博客', // 网站关键词 英文逗号隔开 BLOG_FAVICON: process.env.NEXT_PUBLIC_FAVICON || '/favicon.ico', // blog favicon 配置,默认使用 /public/favicon.ico,支持在线图片,如 https://img.imesong.com/favicon.png BEI_AN: process.env.NEXT_PUBLIC_BEI_AN || '', // 备案号 闽 ICP 备 XXXXXX - BEI_AN_LINK: process.env.NEXT_PUBLIC_BEI_AN_LINK || 'https://beian.miit.gov.cn/', // 备案查询链接,如果用了萌备等备案请在这里填写 + BEI_AN_LINK: + process.env.NEXT_PUBLIC_BEI_AN_LINK || 'https://beian.miit.gov.cn/', // 备案查询链接,如果用了萌备等备案请在这里填写 // RSS 订阅 ENABLE_RSS: process.env.NEXT_PUBLIC_ENABLE_RSS || true, // 是否开启 RSS 订阅功能 diff --git a/themes/typography/components/BlogItem.js b/themes/typography/components/BlogItem.js index b880f1fe..195f9be2 100644 --- a/themes/typography/components/BlogItem.js +++ b/themes/typography/components/BlogItem.js @@ -14,7 +14,6 @@ export const BlogItem = props => { const showPageCover = siteConfig('SIMPLE_POST_COVER_ENABLE', false, CONFIG) const showPreview = siteConfig('POST_LIST_PREVIEW', false, NOTION_CONFIG) && post.blockMap - console.log(post); return (
+
{posts?.map((p, index) => (
diff --git a/themes/typography/components/Catalog.js b/themes/typography/components/Catalog.js index 6bea8bab..e92e586a 100644 --- a/themes/typography/components/Catalog.js +++ b/themes/typography/components/Catalog.js @@ -18,38 +18,71 @@ const Catalog = ({ post }) => { // 监听滚动事件 useEffect(() => { - const throttleMs = 200 + // 如果没有文章或目录,不执行任何操作 + if (!post || !post?.toc || post?.toc?.length < 1) { + return + } + + const throttleMs = 100 // 降低节流时间提高响应速度 + const actionSectionScrollSpy = throttle(() => { const sections = document.getElementsByClassName('notion-h') + if (!sections || sections.length === 0) return + let prevBBox = null - let currentSectionId = activeSection + let currentSectionId = null + + // 先检查当前视口中的所有标题 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) + const offset = 100 // 固定偏移量,避免计算不稳定 + + // 如果标题在视口上方或接近顶部,认为是当前标题 if (bbox.top - offset < 0) { currentSectionId = section.getAttribute('data-id') prevBBox = bbox - continue + } else { + // 找到第一个在视口下方的标题就停止 + break + } + } + + // 如果没找到任何标题在视口上方,使用第一个标题 + if (!currentSectionId && sections.length > 0) { + currentSectionId = sections[0].getAttribute('data-id') + } + + // 只有当 ID 变化时才更新状态,减少不必要的渲染 + if (currentSectionId !== activeSection) { + setActiveSection(currentSectionId) + + // 查找目录中对应的索引并滚动 + const index = post?.toc?.findIndex( + obj => uuidToId(obj.id) === currentSectionId + ) + + if (index !== -1 && tRef?.current) { + tRef.current.scrollTo({ top: 28 * index, behavior: 'smooth' }) } - break } - setActiveSection(currentSectionId) - const index = post?.toc?.findIndex( - obj => uuidToId(obj.id) === currentSectionId - ) - tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' }) }, throttleMs) - - window.addEventListener('scroll', actionSectionScrollSpy) - actionSectionScrollSpy() + + const content = document.querySelector('#container-inner') + if (!content) return // 防止 content 不存在 + + // 添加滚动和内容变化的监听 + content.addEventListener('scroll', actionSectionScrollSpy) + + // 初始执行一次 + setTimeout(() => { + actionSectionScrollSpy() + }, 300) // 延迟执行确保 DOM 已完全加载 + return () => { - window.removeEventListener('scroll', actionSectionScrollSpy) + content?.removeEventListener('scroll', actionSectionScrollSpy) } }, [post]) @@ -68,21 +101,27 @@ const Catalog = ({ post }) => {
-