mapcomplete/UI/Base/TableOfContents.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

121 lines
4.1 KiB
TypeScript
Raw Normal View History

2021-11-30 22:50:48 +01:00
import Combine from "./Combine"
import BaseUIElement from "../BaseUIElement"
import { Translation } from "../i18n/Translation"
import { FixedUiElement } from "./FixedUiElement"
import Title from "./Title"
import List from "./List"
import Link from "./Link"
import { Utils } from "../../Utils"
export default class TableOfContents extends Combine {
2022-01-18 18:52:42 +01:00
private readonly titles: Title[]
2021-11-30 22:50:48 +01:00
constructor(
elements: Combine | Title[],
options?: {
noTopLevel: false | boolean
maxDepth?: number
}
) {
let titles: Title[]
if (elements instanceof Combine) {
2022-01-25 21:55:51 +01:00
titles = TableOfContents.getTitles(elements.getElements()) ?? []
2021-11-30 22:50:48 +01:00
} else {
2022-01-25 21:55:51 +01:00
titles = elements ?? []
2021-11-30 22:50:48 +01:00
}
2022-01-26 21:40:38 +01:00
2021-11-30 22:50:48 +01:00
let els: { level: number; content: BaseUIElement }[] = []
for (const title of titles) {
let content: BaseUIElement
if (title.title instanceof Translation) {
content = title.title.Clone()
2022-01-18 18:52:42 +01:00
} else if (title.title instanceof FixedUiElement) {
2022-01-25 21:55:51 +01:00
content = new FixedUiElement(title.title.content)
2022-01-18 18:52:42 +01:00
} else if (Utils.runningFromConsole) {
2021-11-30 22:50:48 +01:00
content = new FixedUiElement(title.AsMarkdown())
2022-01-26 21:40:38 +01:00
} else if (title["title"] !== undefined) {
content = new FixedUiElement(title.title.ConstructElement().textContent)
2022-01-26 21:40:38 +01:00
} else {
2022-01-25 21:55:51 +01:00
console.log("Not generating a title for ", title)
continue
2021-11-30 22:50:48 +01:00
}
const vis = new Link(content, "#" + title.id)
els.push({ level: title.level, content: vis })
}
2022-01-18 18:52:42 +01:00
const minLevel = Math.min(...els.map((e) => e.level))
2021-11-30 22:50:48 +01:00
if (options?.noTopLevel) {
2022-01-18 18:52:42 +01:00
els = els.filter((e) => e.level !== minLevel)
2021-11-30 22:50:48 +01:00
}
2022-01-18 18:52:42 +01:00
if (options?.maxDepth) {
2021-11-30 22:50:48 +01:00
els = els.filter((e) => e.level <= options.maxDepth + minLevel)
}
super(TableOfContents.mergeLevel(els).map((el) => el.SetClass("mt-2")))
this.SetClass("flex flex-col")
this.titles = titles
}
2022-01-18 18:52:42 +01:00
private static getTitles(elements: BaseUIElement[]): Title[] {
2021-11-30 22:50:48 +01:00
const titles = []
2022-01-18 18:52:42 +01:00
for (const uiElement of elements) {
if (uiElement instanceof Combine) {
2021-11-30 22:50:48 +01:00
titles.push(...TableOfContents.getTitles(uiElement.getElements()))
2022-01-18 18:52:42 +01:00
} else if (uiElement instanceof Title) {
2021-11-30 22:50:48 +01:00
titles.push(uiElement)
}
}
return titles
}
2022-01-18 18:52:42 +01:00
2021-11-30 22:50:48 +01:00
private static mergeLevel(
elements: { level: number; content: BaseUIElement }[]
): BaseUIElement[] {
const maxLevel = Math.max(...elements.map((e) => e.level))
const minLevel = Math.min(...elements.map((e) => e.level))
if (maxLevel === minLevel) {
return elements.map((e) => e.content)
}
const result: { level: number; content: BaseUIElement }[] = []
let running: BaseUIElement[] = []
for (const element of elements) {
if (element.level === maxLevel) {
running.push(element.content)
continue
}
if (running.length !== undefined) {
result.push({
content: new List(running),
level: maxLevel - 1,
})
running = []
}
result.push(element)
}
if (running.length !== undefined) {
result.push({
content: new List(running),
level: maxLevel - 1,
})
}
return TableOfContents.mergeLevel(result)
}
AsMarkdown(): string {
2022-01-18 18:52:42 +01:00
const depthIcons = ["1.", " -", " +", " *"]
2021-11-30 22:50:48 +01:00
const lines = ["## Table of contents\n"]
const minLevel = Math.min(...this.titles.map((t) => t.level))
for (const title of this.titles) {
const prefix = depthIcons[title.level - minLevel] ?? " ~"
2022-01-18 18:52:42 +01:00
const text = title.title.AsMarkdown().replace("\n", "")
2021-11-30 22:50:48 +01:00
const link = title.id
2022-01-18 18:52:42 +01:00
lines.push(prefix + " [" + text + "](#" + link + ")")
2021-11-30 22:50:48 +01:00
}
2022-01-18 18:52:42 +01:00
return lines.join("\n") + "\n\n"
2021-11-30 22:50:48 +01:00
}
}