Files
NotionNext/lib/notion/getPageTableOfContents.js
anime 8cb2244f37 feat(支持同步块格式的目录识别):
(cherry picked from commit 079515a157f3d0ba5cc1a92272fc16e74537f25f)

feat(支持同步块格式的目录识别): 修复额外的多余目录识别问题

(cherry picked from commit c2d8ed211c16413aec37fd2438d93a7525afc03d)

feat(支持同步块格式的目录识别): 去除多余的判断逻辑

(cherry picked from commit bacbe55bea13c4d3c6e79a11afcde4ba5139c67b)
2024-12-04 11:25:59 +08:00

99 lines
2.4 KiB
JavaScript

import { getTextContent } from 'notion-utils'
const indentLevels = {
header: 0,
sub_header: 1,
sub_sub_header: 2
}
/**
* @see https://github.com/NotionX/react-notion-x/blob/master/packages/notion-utils/src/get-page-table-of-contents.ts
* Gets the metadata for a table of contents block by parsing the page's
* H1, H2, and H3 elements.
*/
export const getPageTableOfContents = (page, recordMap) => {
const contents = page.content ?? []
const toc = getBlockHeader(contents, recordMap)
const indentLevelStack = [
{
actual: -1,
effective: -1
}
]
// Adjust indent levels to always change smoothly.
// This is a little tricky, but the key is that when increasing indent levels,
// they should never jump more than one at a time.
for (const tocItem of toc) {
const { indentLevel } = tocItem
const actual = indentLevel
do {
const prevIndent = indentLevelStack[indentLevelStack.length - 1]
const { actual: prevActual, effective: prevEffective } = prevIndent
if (actual > prevActual) {
tocItem.indentLevel = prevEffective + 1
indentLevelStack.push({
actual,
effective: tocItem.indentLevel
})
} else if (actual === prevActual) {
tocItem.indentLevel = prevEffective
break
} else {
indentLevelStack.pop()
}
// eslint-disable-next-line no-constant-condition
} while (true)
}
return toc
}
/**
* 重写获取目录方法
*/
function getBlockHeader(contents, recordMap, toc) {
if (!toc) {
toc = []
}
if (!contents) {
return toc
}
for (const blockId of contents) {
const block = recordMap.block[blockId]?.value
if (!block) {
continue
}
const { type } = block
if (block.content?.length > 0) {
getBlockHeader(block.content, recordMap, toc)
} else {
if (type.indexOf('header') >= 0) {
const existed = toc.find(e => e.id === blockId)
if (!existed) {
toc.push({
id: blockId,
type,
text: getTextContent(block.properties?.title),
indentLevel: indentLevels[type]
})
}
} else if (type === 'transclusion_reference') {
getBlockHeader(
[block.format.transclusion_reference_pointer.id],
recordMap,
toc
)
} else if (type === 'transclusion_container') {
getBlockHeader(block.content, recordMap, toc)
}
}
}
return toc
}