mirror of
https://github.com/JefferyHcool/BiliNote.git
synced 2026-06-11 18:49:59 +08:00
fix(frontend): 增强锚点链接模糊匹配,兼容 LLM 生成的不一致目录格式
This commit is contained in:
@@ -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",
|
||||
|
||||
36
BillNote_frontend/pnpm-lock.yaml
generated
36
BillNote_frontend/pnpm-lock.yaml
generated
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user