From cbf35beeb87a91c1f1f7f35be3a8a8b6e6150ca6 Mon Sep 17 00:00:00 2001 From: CapaCake Date: Sun, 22 Mar 2026 12:16:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B0=86=E7=9B=AE=E5=BD=95(TOC)?= =?UTF-8?q?=E7=A7=BB=E8=87=B3=E4=BE=A7=E8=BE=B9=E6=A0=8F=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=BB=9A=E5=8A=A8=E9=AB=98=E4=BA=AE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构TOC组件,移至SideBar中显示 - 改进IntersectionObserver实现,优化章节高亮行为 - 添加toc国际化翻译(中/英/繁) - 更新Swup容器配置,支持文章页侧边栏刷新 - 移除原MainGridLayout中的独立TOC容器 --- src/components/widget/SideBar.astro | 28 +- src/components/widget/TOC.astro | 426 ++++++++++++++-------------- src/i18n/i18nKey.ts | 1 + src/i18n/languages/en.ts | 1 + src/i18n/languages/zh_CN.ts | 1 + src/i18n/languages/zh_TW.ts | 1 + src/layouts/Layout.astro | 35 +-- src/layouts/MainGridLayout.astro | 21 -- src/styles/main.css | 4 +- 9 files changed, 261 insertions(+), 257 deletions(-) diff --git a/src/components/widget/SideBar.astro b/src/components/widget/SideBar.astro index f3bafc2..48cac9b 100644 --- a/src/components/widget/SideBar.astro +++ b/src/components/widget/SideBar.astro @@ -1,22 +1,38 @@ --- import type { MarkdownHeading } from "astro"; +import { siteConfig } from "@/config"; import Categories from "./Categories.astro"; import Profile from "./Profile.astro"; import Tag from "./Tags.astro"; +import TOC from "./TOC.astro"; interface Props { class?: string; headings?: MarkdownHeading[]; } -const className = Astro.props.class; +const { class: className, headings } = Astro.props; +const currentPagePath = Astro.url.pathname; +const isPostPage = currentPagePath.startsWith("/posts/"); --- + diff --git a/src/components/widget/TOC.astro b/src/components/widget/TOC.astro index 6cb2fab..af317e4 100644 --- a/src/components/widget/TOC.astro +++ b/src/components/widget/TOC.astro @@ -1,7 +1,10 @@ --- import type { MarkdownHeading } from "astro"; import { siteConfig } from "../../config"; +import I18nKey from "../../i18n/i18nKey"; +import { i18n } from "../../i18n/translation"; import { url } from "../../utils/url-utils"; +import WidgetLayout from "./WidgetLayout.astro"; interface Props { class?: string; @@ -31,238 +34,249 @@ let heading1Count = 1; const maxLevel = siteConfig.toc.depth; --- -{isPostsRoute && - - {headings.filter((heading) => heading.depth < minDepth + maxLevel).map((heading) => - -
+ +
+
+ + + + + \ No newline at end of file + if (!customElements.get("table-of-contents")) { + customElements.define("table-of-contents", TableOfContents); + } + diff --git a/src/i18n/i18nKey.ts b/src/i18n/i18nKey.ts index 0f2da7f..a5d21a2 100644 --- a/src/i18n/i18nKey.ts +++ b/src/i18n/i18nKey.ts @@ -37,6 +37,7 @@ enum I18nKey { notFoundDesc = "notFoundDesc", backToHome = "backToHome", pinned = "pinned", + toc = "toc", } export default I18nKey; diff --git a/src/i18n/languages/en.ts b/src/i18n/languages/en.ts index 4953f50..ef4b1a6 100644 --- a/src/i18n/languages/en.ts +++ b/src/i18n/languages/en.ts @@ -40,4 +40,5 @@ export const en: Translation = { [Key.notFoundDesc]: "The link is broken, the page has gone missing", [Key.backToHome]: "Back to Home", [Key.pinned]: "Pinned", + [Key.toc]: "Toc", }; diff --git a/src/i18n/languages/zh_CN.ts b/src/i18n/languages/zh_CN.ts index 391efd6..9a5c6a3 100644 --- a/src/i18n/languages/zh_CN.ts +++ b/src/i18n/languages/zh_CN.ts @@ -40,4 +40,5 @@ export const zh_CN: Translation = { [Key.notFoundDesc]: "你访问的链接已断开,页面走丢了", [Key.backToHome]: "返回首页", [Key.pinned]: "置顶", + [Key.toc]: "目录", }; diff --git a/src/i18n/languages/zh_TW.ts b/src/i18n/languages/zh_TW.ts index b24ee7f..d881362 100644 --- a/src/i18n/languages/zh_TW.ts +++ b/src/i18n/languages/zh_TW.ts @@ -40,4 +40,5 @@ export const zh_TW: Translation = { [Key.notFoundDesc]: "你訪問的連結已斷開,頁面走丟了", [Key.backToHome]: "返回首頁", [Key.pinned]: "置頂", + [Key.toc]: "目錄", }; diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index c180522..9f3ee7b 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -405,7 +405,19 @@ const setup = () => { } }) window.swup.hooks.on('content:replace', initCustomScrollbar) - window.swup.hooks.on('visit:start', (visit: {to: {url: string}}) => { + window.swup.hooks.on('visit:start', (visit: {to: {url: string};from: { url: string };containers: string[]}) => { + + const postUrlPattern = "/posts/"; + const isToPost = visit.to.url.includes(postUrlPattern); + const isFromPost = visit.from.url.includes(postUrlPattern); + + if (isToPost || isFromPost) { + visit.containers = ["main", "#sidebar"]; // 刷新两者 + } else { + // 否则(例如,从首页导航到关于页面), + // 仅刷新主内容区域。 + visit.containers = ["main"]; + } // change banner height immediately when a link is clicked const bodyElement = document.querySelector('body') if (pathsEqual(visit.to.url, url('/'))) { @@ -419,12 +431,6 @@ const setup = () => { if (heightExtend) { heightExtend.classList.remove('hidden') } - - // Hide the TOC while scrolling back to top - let toc = document.getElementById('toc-wrapper'); - if (toc) { - toc.classList.add('toc-not-ready') - } }); window.swup.hooks.on('page:view', () => { // hide the temp high element when the transition is done @@ -439,12 +445,6 @@ const setup = () => { if (heightExtend) { heightExtend.classList.add('hidden') } - - // Just make the transition looks better - const toc = document.getElementById('toc-wrapper'); - if (toc) { - toc.classList.remove('toc-not-ready') - } }, 200) }); } @@ -455,7 +455,6 @@ if (window?.swup?.hooks) { } let backToTopBtn = document.getElementById('back-to-top-btn'); -let toc = document.getElementById('toc-wrapper'); let navbar = document.getElementById('navbar-wrapper') function scrollFunction() { let bannerHeight = window.innerHeight * (BANNER_HEIGHT / 100) @@ -468,14 +467,6 @@ function scrollFunction() { } } - if (bannerEnabled && toc) { - if (document.body.scrollTop > bannerHeight || document.documentElement.scrollTop > bannerHeight) { - toc.classList.remove('toc-hide') - } else { - toc.classList.add('toc-hide') - } - } - if (!bannerEnabled) return if (navbar) { const NAVBAR_HEIGHT = 72 diff --git a/src/layouts/MainGridLayout.astro b/src/layouts/MainGridLayout.astro index e1f8e5c..3ddcb2d 100644 --- a/src/layouts/MainGridLayout.astro +++ b/src/layouts/MainGridLayout.astro @@ -6,7 +6,6 @@ import SideBar from "@components/widget/SideBar.astro"; import type { MarkdownHeading } from "astro"; import { Icon } from "astro-icon/components"; import ImageWrapper from "../components/misc/ImageWrapper.astro"; -import TOC from "../components/widget/TOC.astro"; import { siteConfig } from "../config"; import { BANNER_HEIGHT, @@ -102,24 +101,4 @@ const mainPanelTop = siteConfig.banner.enable
- - diff --git a/src/styles/main.css b/src/styles/main.css index 9aaa104..bef7f47 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -65,9 +65,9 @@ @apply opacity-0 pointer-events-none } - #toc-inner-wrapper { + /* #toc-inner-wrapper { mask-image: linear-gradient(to bottom, transparent 0%, black 2rem, black calc(100% - 2rem), transparent 100%); - } + } */ .hide-scrollbar { scrollbar-width: none;