diff --git a/UI/Base/Combine.ts b/UI/Base/Combine.ts index e714092f6..a9e1a90bb 100644 --- a/UI/Base/Combine.ts +++ b/UI/Base/Combine.ts @@ -1,6 +1,7 @@ import {FixedUiElement} from "./FixedUiElement"; import {Utils} from "../../Utils"; import BaseUIElement from "../BaseUIElement"; +import Title from "./Title"; export default class Combine extends BaseUIElement { private readonly uiElements: BaseUIElement[]; @@ -22,10 +23,7 @@ export default class Combine extends BaseUIElement { protected InnerConstructElement(): HTMLElement { const el = document.createElement("span") - try { - - for (const subEl of this.uiElements) { if (subEl === undefined || subEl === null) { continue; @@ -48,5 +46,19 @@ export default class Combine extends BaseUIElement { return el; } + + public getToC(): Title[]{ + const titles = [] + for (const uiElement of this.uiElements) { + if(uiElement instanceof Combine){ + titles.push(...uiElement.getToC()) + }else if(uiElement instanceof Title){ + titles.push(uiElement) + } + } + return titles + + + } } \ No newline at end of file diff --git a/UI/Base/Title.ts b/UI/Base/Title.ts index adf4b2dd7..31afdfc80 100644 --- a/UI/Base/Title.ts +++ b/UI/Base/Title.ts @@ -2,39 +2,39 @@ import BaseUIElement from "../BaseUIElement"; import {FixedUiElement} from "./FixedUiElement"; export default class Title extends BaseUIElement { - private readonly _embedded: BaseUIElement; - private readonly _level: number; + public readonly title: BaseUIElement; + public readonly level: number; constructor(embedded: string | BaseUIElement, level: number = 3) { super() if (typeof embedded === "string") { - this._embedded = new FixedUiElement(embedded) + this.title = new FixedUiElement(embedded) } else { - this._embedded = embedded + this.title = embedded } - this._level = level; + this.level = level; } AsMarkdown(): string { - const embedded = " " + this._embedded.AsMarkdown() + " "; + const embedded = " " + this.title.AsMarkdown() + " "; - if (this._level == 1) { + if (this.level == 1) { return "\n\n" + embedded + "\n" + "=".repeat(embedded.length) + "\n\n" } - if (this._level == 2) { + if (this.level == 2) { return "\n\n" + embedded + "\n" + "-".repeat(embedded.length) + "\n\n" } - return "\n\n" + "#".repeat(this._level) + embedded + "\n\n"; + return "\n\n" + "#".repeat(this.level) + embedded + "\n\n"; } protected InnerConstructElement(): HTMLElement { - const el = this._embedded.ConstructElement() + const el = this.title.ConstructElement() if (el === undefined) { return undefined; } - const h = document.createElement("h" + this._level) + const h = document.createElement("h" + this.level) h.appendChild(el) return h; } diff --git a/UI/Base/Toggleable.ts b/UI/Base/Toggleable.ts index 447869073..e828a5cf3 100644 --- a/UI/Base/Toggleable.ts +++ b/UI/Base/Toggleable.ts @@ -20,42 +20,26 @@ export class Accordeon extends Combine { } -export default class Toggleable extends BaseUIElement { +export default class Toggleable extends Combine { public readonly isVisible = new UIEventSource(false) - private readonly title: BaseUIElement; - private readonly content: BaseUIElement; constructor(title: BaseUIElement, content: BaseUIElement) { - super() - this.title = title; - this.content = content; - this.content.SetClass("animate-height border-l-4 border-gray-300 pl-2") - this.title.SetClass("background-subtle rounded-lg") + super([title, content]) + content.SetClass("animate-height border-l-4 border-gray-300 pl-2") + title.SetClass("background-subtle rounded-lg") const self = this this.onClick(() => self.isVisible.setData(!self.isVisible.data)) - } - - protected InnerConstructElement(): HTMLElement { - - const title = this.title.ConstructElement() - const content = this.content.ConstructElement() + const contentElement = content.ConstructElement() this.isVisible.addCallbackAndRun(isVisible => { if (isVisible) { - content.style.maxHeight = "100vh" - content.style["-webkit-mask-image"] = "unset" + contentElement.style.maxHeight = "100vh" + contentElement.style["-webkit-mask-image"] = "unset" } else { - content.style["-webkit-mask-image"] = "-webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,1)), to(rgba(0,0,0,0)))" - content.style.maxHeight = "2rem" + contentElement.style["-webkit-mask-image"] = "-webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,1)), to(rgba(0,0,0,0)))" + contentElement.style.maxHeight = "2rem" } }) - - const div = document.createElement("div") - div.appendChild(title) - div.appendChild(content) - - - return div; } } \ No newline at end of file diff --git a/UI/ProfessionalGui.ts b/UI/ProfessionalGui.ts index d1b72ffa9..738a656e0 100644 --- a/UI/ProfessionalGui.ts +++ b/UI/ProfessionalGui.ts @@ -4,6 +4,45 @@ import Combine from "./Base/Combine"; import Title from "./Base/Title"; import Toggleable, {Accordeon} from "./Base/Toggleable"; import List from "./Base/List"; +import BaseUIElement from "./BaseUIElement"; +import Link from "./Base/Link"; + +class TableOfContents extends Combine { + + /** + * All the padding levels. Note that these are written out so that tailwind-generate-css can detect them + * @private + */ + private static readonly paddings: string[] = ["pl-0, pl-2", "pl-4", "pl-6", "pl-8", "pl-10", "pl-12", "pl-14"] + private readonly titles: Title[] + + constructor(elements: Combine | Title[]) { + let titles: Title[] + if (elements instanceof Combine) { + titles = elements.getToC() + } else { + titles = elements + } + + const minLevel = Math.min(...titles.map(t => t.level)) + + const els: BaseUIElement[] = [] + for (const title of titles) { + const l = title.level - minLevel + const padding = TableOfContents.paddings[l] + const text = title.title.ConstructElement().innerText + const vis = new Link(new FixedUiElement(text), "#" + text).SetClass(padding) + els.push(vis) + } + super(els); + this.SetClass("flex flex-col") + this.titles = titles; + } + + AsMarkdown(): string { + return super.AsMarkdown(); + } +} class Snippet extends Toggleable { constructor(translations) { @@ -32,7 +71,8 @@ export default class ProfessionalGui { constructor() { const t = Translations.t.professional - new Combine([ + // LanguagePicker.CreateLanguagePicker(Translations.t.index.title.SupportedLanguages()).SetClass("flex absolute top-2 right-3"), + const content = new Combine([ new Combine([ new FixedUiElement(`MapComplete Logo`) .SetClass("flex-none m-3"), @@ -53,16 +93,17 @@ export default class ProfessionalGui { new Snippet(t.aboutOsm.license), new Snippet(t.aboutOsm.vandalism), ]).SetClass("flex flex-col"), - + new Title(t.aboutMc.title, 2).SetClass("text-2xl"), t.aboutMc.text0, t.aboutMc.text1, t.aboutMc.text2 - ]) - .SetClass("flex flex-col pb-12 m-5 lg:w-3/4 lg:ml-40") - .AttachTo("main") + ]).SetClass("flex flex-col pb-12 m-3 lg:w-3/4 lg:ml-10") + + const toc = new TableOfContents(content) + new Combine([toc, content]).SetClass("flex").AttachTo("main") }