From 905dbcce47585b48d6b2761b66b388d11ff050ee Mon Sep 17 00:00:00 2001 From: techotaku39 Date: Sun, 24 May 2026 03:21:17 +0800 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=E5=A2=9E=E5=BC=BA=E9=94=9A?= =?UTF-8?q?=E7=82=B9=E9=93=BE=E6=8E=A5=E6=A8=A1=E7=B3=8A=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=EF=BC=8C=E5=85=BC=E5=AE=B9=20LLM=20=E7=94=9F=E6=88=90=E7=9A=84?= =?UTF-8?q?=E4=B8=8D=E4=B8=80=E8=87=B4=E7=9B=AE=E5=BD=95=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BillNote_frontend/package.json | 2 +- BillNote_frontend/pnpm-lock.yaml | 36 +++++++++++++++++-- .../HomePage/components/MarkdownViewer.tsx | 22 +++++++++++- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/BillNote_frontend/package.json b/BillNote_frontend/package.json index 9f329cc..fdd9911 100644 --- a/BillNote_frontend/package.json +++ b/BillNote_frontend/package.json @@ -57,7 +57,7 @@ "react-router-dom": "^7.5.1", "react-syntax-highlighter": "^15.6.1", "rehype-katex": "^6.0.2", - "rehype-slug": "^6.0.0", + "rehype-slug": "5.1.0", "remark-gfm": "3.0.1", "remark-math": "^5.1.1", "sonner": "^2.0.3", diff --git a/BillNote_frontend/pnpm-lock.yaml b/BillNote_frontend/pnpm-lock.yaml index 1b93d81..7ea277c 100644 --- a/BillNote_frontend/pnpm-lock.yaml +++ b/BillNote_frontend/pnpm-lock.yaml @@ -150,8 +150,8 @@ importers: specifier: ^6.0.2 version: 6.0.3 rehype-slug: - specifier: ^6.0.0 - version: 6.0.0 + specifier: 5.1.0 + version: 5.1.0 remark-gfm: specifier: 3.0.1 version: 3.0.1 @@ -2803,9 +2803,15 @@ packages: hast-util-from-parse5@8.0.3: resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + hast-util-has-property@2.0.1: + resolution: {integrity: sha512-X2+RwZIMTMKpXUzlotatPzWj8bspCymtXH3cfG3iQKV+wPF53Vgaqxi/eLqGck0wKq1kS9nvoB1wchbCPEL8sg==} + hast-util-has-property@3.0.0: resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + hast-util-heading-rank@2.1.1: + resolution: {integrity: sha512-iAuRp+ESgJoRFJbSyaqsfvJDY6zzmFoEnL1gtz1+U8gKtGGj1p0CVlysuUAUjq95qlZESHINLThwJzNGmgGZxA==} + hast-util-heading-rank@3.0.0: resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} @@ -2842,6 +2848,9 @@ packages: hast-util-to-parse5@8.0.1: resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + hast-util-to-string@2.0.0: + resolution: {integrity: sha512-02AQ3vLhuH3FisaMM+i/9sm4OXGSq1UhOOCpTLLQtHdL3tZt7qil69r8M8iDkZYyC0HCFylcYoP+8IO7ddta1A==} + hast-util-to-string@3.0.1: resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} @@ -4411,6 +4420,9 @@ packages: resolution: {integrity: sha512-L/FO96EOzSA6bzOam4DVu61/PB3AGKcSPXpa53yMIozoxH4qg1+bVZDF8zh1EsuxtSauAhzt5cCnvoplAaSLrw==} engines: {node: '>=16.0.0'} + rehype-slug@5.1.0: + resolution: {integrity: sha512-Gf91dJoXneiorNEnn+Phx97CO7oRMrpi+6r155tTxzGuLtm+QrI4cTwCa9e1rtePdL4i9tSO58PeSS6HWfgsiw==} + rehype-slug@6.0.0: resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==} @@ -7878,10 +7890,16 @@ snapshots: vfile-location: 5.0.3 web-namespaces: 2.0.1 + hast-util-has-property@2.0.1: {} + hast-util-has-property@3.0.0: dependencies: '@types/hast': 3.0.4 + hast-util-heading-rank@2.1.1: + dependencies: + '@types/hast': 2.3.10 + hast-util-heading-rank@3.0.0: dependencies: '@types/hast': 3.0.4 @@ -8004,6 +8022,10 @@ snapshots: web-namespaces: 2.0.1 zwitch: 2.0.4 + hast-util-to-string@2.0.0: + dependencies: + '@types/hast': 2.3.10 + hast-util-to-string@3.0.1: dependencies: '@types/hast': 3.0.4 @@ -10191,6 +10213,16 @@ snapshots: unified: 11.0.5 unist-util-visit: 5.1.0 + rehype-slug@5.1.0: + dependencies: + '@types/hast': 2.3.10 + github-slugger: 2.0.0 + hast-util-has-property: 2.0.1 + hast-util-heading-rank: 2.1.1 + hast-util-to-string: 2.0.0 + unified: 10.1.2 + unist-util-visit: 4.1.2 + rehype-slug@6.0.0: dependencies: '@types/hast': 3.0.4 diff --git a/BillNote_frontend/src/pages/HomePage/components/MarkdownViewer.tsx b/BillNote_frontend/src/pages/HomePage/components/MarkdownViewer.tsx index f16ad4d..c34a0e5 100644 --- a/BillNote_frontend/src/pages/HomePage/components/MarkdownViewer.tsx +++ b/BillNote_frontend/src/pages/HomePage/components/MarkdownViewer.tsx @@ -123,7 +123,27 @@ function createMarkdownComponents(baseURL: string) { const handleAnchorClick = (e: React.MouseEvent) => { e.preventDefault() const id = decodeURIComponent(href.slice(1)) - const target = document.getElementById(id) + + // 1. 优先精确匹配 id + let target = document.getElementById(id) + + // 2. 精确失败时按 heading 文本模糊匹配 + // LLM 生成的目录锚点可能和 heading 实际文本不完全一致 + //(例如 heading 带 *Content-[00:00]* 后缀,目录链接里没有) + if (!target) { + const normalize = (s: string) => + s.replace(/[-::\s*\[\]]/g, '').toLowerCase() + const search = normalize(id) + const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6') + for (const h of headings) { + const text = h.textContent || '' + if (normalize(text).includes(search) || search.includes(normalize(text))) { + target = h + break + } + } + } + if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }) } else {