|
import { getTextContent } from 'notion-utils' |
|
|
|
const indentLevels = { |
|
header: 0, |
|
sub_header: 1, |
|
sub_sub_header: 2 |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
export const getPageTableOfContents = (page, recordMap) => { |
|
const contents = (page.content ?? []) |
|
const toc = getBlockHeader(contents, recordMap) |
|
const indentLevelStack = [ |
|
{ |
|
actual: -1, |
|
effective: -1 |
|
} |
|
] |
|
|
|
|
|
|
|
|
|
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() |
|
} |
|
|
|
|
|
} 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 (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] |
|
}) |
|
} |
|
} |
|
|
|
if (block.content?.length > 0) { |
|
getBlockHeader(block.content, recordMap, toc) |
|
} |
|
} |
|
|
|
return toc |
|
} |
|
|