forked from MapComplete/MapComplete
Refactoring: port doc generation to generate markdown directly without UIElements
This commit is contained in:
parent
7a7439b161
commit
8e9c03e258
17 changed files with 309 additions and 320 deletions
|
@ -31,6 +31,7 @@ import { TagUtils } from "../src/Logic/Tags/TagUtils"
|
|||
import Script from "./Script"
|
||||
import { Changes } from "../src/Logic/Osm/Changes"
|
||||
import TableOfContents from "../src/UI/Base/TableOfContents"
|
||||
import MarkdownUtils from "../src/Utils/MarkdownUtils"
|
||||
|
||||
/**
|
||||
* Converts a markdown-file into a .json file, which a walkthrough/slideshow element can use
|
||||
|
@ -56,15 +57,15 @@ class ToSlideshowJson {
|
|||
sections.push(currentSection)
|
||||
currentSection = []
|
||||
}
|
||||
line = line.replace('src="../../public/', 'src="./')
|
||||
line = line.replace('src="../../', 'src="./')
|
||||
line = line.replace("src=\"../../public/", "src=\"./")
|
||||
line = line.replace("src=\"../../", "src=\"./")
|
||||
currentSection.push(line)
|
||||
}
|
||||
sections.push(currentSection)
|
||||
writeFileSync(
|
||||
this._target,
|
||||
JSON.stringify({
|
||||
sections: sections.map((s) => s.join("\n")).filter((s) => s.length > 0),
|
||||
sections: sections.map((s) => s.join("\n")).filter((s) => s.length > 0)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -83,7 +84,7 @@ class WikiPageGenerator {
|
|||
|
||||
generate() {
|
||||
let wikiPage =
|
||||
'{|class="wikitable sortable"\n' +
|
||||
"{|class=\"wikitable sortable\"\n" +
|
||||
"! Name, link !! Genre !! Covered region !! Language !! Description !! Free materials !! Image\n" +
|
||||
"|-"
|
||||
|
||||
|
@ -140,8 +141,8 @@ export class GenerateDocs extends Script {
|
|||
mkdirSync("./Docs/Themes")
|
||||
}
|
||||
|
||||
this.WriteFile("./Docs/Tags_format.md", TagUtils.generateDocs(), [
|
||||
"src/Logic/Tags/TagUtils.ts",
|
||||
this.WriteMarkdownFile("./Docs/Tags_format.md", TagUtils.generateDocs(), [
|
||||
"src/Logic/Tags/TagUtils.ts"
|
||||
])
|
||||
|
||||
new ToSlideshowJson(
|
||||
|
@ -166,58 +167,30 @@ export class GenerateDocs extends Script {
|
|||
})
|
||||
|
||||
this.WriteMarkdownFile("./Docs/SpecialRenderings.md", SpecialVisualizations.HelpMessage(), [
|
||||
"src/UI/SpecialVisualizations.ts",
|
||||
"src/UI/SpecialVisualizations.ts"
|
||||
])
|
||||
this.WriteFile(
|
||||
this.WriteMarkdownFile(
|
||||
"./Docs/CalculatedTags.md",
|
||||
new Combine([
|
||||
new Title("Metatags", 1),
|
||||
[
|
||||
"# Metatags",
|
||||
SimpleMetaTaggers.HelpText(),
|
||||
ExtraFunctions.HelpText(),
|
||||
]).SetClass("flex-col"),
|
||||
ExtraFunctions.HelpText()
|
||||
].join("\n"),
|
||||
["src/Logic/SimpleMetaTagger.ts", "src/Logic/ExtraFunctions.ts"]
|
||||
)
|
||||
this.WriteFile("./Docs/SpecialInputElements.md", Validators.HelpText(), [
|
||||
"src/UI/InputElement/Validators.ts",
|
||||
this.WriteMarkdownFile("./Docs/SpecialInputElements.md", Validators.HelpText(), [
|
||||
"src/UI/InputElement/Validators.ts"
|
||||
])
|
||||
|
||||
this.WriteFile("./Docs/ChangesetMeta.md", Changes.getDocs(), [
|
||||
this.WriteMarkdownFile("./Docs/ChangesetMeta.md", Changes.getDocs(), [
|
||||
"src/Logic/Osm/Changes.ts",
|
||||
"src/Logic/Osm/ChangesetHandler.ts",
|
||||
"src/Logic/Osm/ChangesetHandler.ts"
|
||||
])
|
||||
new WikiPageGenerator().generate()
|
||||
|
||||
console.log("Generated docs")
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
private WriteFile(
|
||||
filename,
|
||||
html: string | BaseUIElement,
|
||||
autogenSource: string[],
|
||||
options?: {
|
||||
noTableOfContents: boolean
|
||||
}
|
||||
): void {
|
||||
if (!html) {
|
||||
return
|
||||
}
|
||||
|
||||
let md = new Combine([
|
||||
Translations.W(html),
|
||||
"\n\nThis document is autogenerated from " +
|
||||
autogenSource
|
||||
.map(
|
||||
(file) =>
|
||||
`[${file}](https://github.com/pietervdvn/MapComplete/blob/develop/${file})`
|
||||
)
|
||||
.join(", "),
|
||||
]).AsMarkdown()
|
||||
this.WriteMarkdownFile(filename, md, autogenSource, options)
|
||||
}
|
||||
|
||||
private WriteMarkdownFile(
|
||||
filename: string,
|
||||
markdown: string,
|
||||
|
@ -254,22 +227,30 @@ export class GenerateDocs extends Script {
|
|||
const warnAutomated =
|
||||
"[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources)\n\n"
|
||||
|
||||
writeFileSync(filename, warnAutomated + md)
|
||||
const generatedFrom =
|
||||
[
|
||||
|
||||
"This document is autogenerated from",
|
||||
autogenSource.map(s => `[${s}](https://github.com/pietervdvn/MapComplete/blob/develop/${s})`).join(", ")
|
||||
].join(" ")
|
||||
|
||||
|
||||
writeFileSync(filename, warnAutomated + md+"\n\n" +generatedFrom+"\n")
|
||||
}
|
||||
|
||||
private generateHotkeyDocs() {
|
||||
new ThemeViewState(new LayoutConfig(<any>bookcases), new Set())
|
||||
this.WriteFile("./Docs/Hotkeys.md", Hotkeys.generateDocumentation(), [])
|
||||
this.WriteMarkdownFile("./Docs/Hotkeys.md", Hotkeys.generateDocumentation(), ["src/UI/Base/Hotkeys.ts"])
|
||||
}
|
||||
|
||||
private generateBuiltinUnits() {
|
||||
const layer = new LayerConfig(<LayerConfigJson>unit, "units", true)
|
||||
const els: (BaseUIElement | string)[] = [new Title(layer.id, 2)]
|
||||
const els: string[] = ["## " + layer.id]
|
||||
|
||||
for (const unit of layer.units) {
|
||||
els.push(new Title(unit.quantity))
|
||||
els.push("### " + unit.quantity)
|
||||
for (const denomination of unit.denominations) {
|
||||
els.push(new Title(denomination.canonical, 4))
|
||||
els.push("#### " + denomination.canonical)
|
||||
if (denomination.useIfNoUnitGiven === true) {
|
||||
els.push("*Default denomination*")
|
||||
} else if (
|
||||
|
@ -277,7 +258,7 @@ export class GenerateDocs extends Script {
|
|||
denomination.useIfNoUnitGiven.length > 0
|
||||
) {
|
||||
els.push("Default denomination in the following countries:")
|
||||
els.push(new List(denomination.useIfNoUnitGiven))
|
||||
els.push(MarkdownUtils.list(denomination.useIfNoUnitGiven))
|
||||
}
|
||||
if (denomination.prefix) {
|
||||
els.push("Prefixed")
|
||||
|
@ -285,14 +266,14 @@ export class GenerateDocs extends Script {
|
|||
if (denomination.alternativeDenominations.length > 0) {
|
||||
els.push(
|
||||
"Alternative denominations:",
|
||||
new List(denomination.alternativeDenominations)
|
||||
MarkdownUtils.list(denomination.alternativeDenominations)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.WriteFile("./Docs/builtin_units.md", new Combine([new Title("Units", 1), ...els]), [
|
||||
`assets/layers/unit/unit.json`,
|
||||
this.WriteMarkdownFile("./Docs/builtin_units.md", ["# Units", ...els].join("\n\n"), [
|
||||
`assets/layers/unit/unit.json`
|
||||
])
|
||||
}
|
||||
|
||||
|
@ -373,7 +354,7 @@ export class GenerateDocs extends Script {
|
|||
if (inlineSource !== undefined) {
|
||||
source = `assets/themes/${inlineSource}/${inlineSource}.json`
|
||||
}
|
||||
this.WriteFile("./Docs/Layers/" + layer.id + ".md", element, [source])
|
||||
this.WriteMarkdownFile("./Docs/Layers/" + layer.id + ".md", element, [source])
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -442,7 +423,7 @@ export class GenerateDocs extends Script {
|
|||
"The mode the application starts in, e.g. 'map', 'dashboard' or 'statistics'"
|
||||
)
|
||||
|
||||
this.WriteFile(
|
||||
this.WriteMarkdownFile(
|
||||
"./Docs/URL_Parameters.md",
|
||||
QueryParameterDocumentation.GenerateQueryParameterDocs(),
|
||||
["src/Logic/Web/QueryParameters.ts", "src/UI/QueryParameterDocumentation.ts"]
|
||||
|
@ -451,7 +432,7 @@ export class GenerateDocs extends Script {
|
|||
|
||||
private generateBuiltinQuestions() {
|
||||
const qLayer = new LayerConfig(<LayerConfigJson>questions, "questions.json", true)
|
||||
this.WriteFile(
|
||||
this.WriteMarkdownFile(
|
||||
"./Docs/BuiltinQuestions.md",
|
||||
qLayer.GenerateDocumentation([], new Map(), []),
|
||||
["assets/layers/questions/questions.json"]
|
||||
|
@ -459,27 +440,25 @@ export class GenerateDocs extends Script {
|
|||
}
|
||||
|
||||
private generateForTheme(theme: LayoutConfig): void {
|
||||
const el = new Combine([
|
||||
new Title(
|
||||
new Combine([
|
||||
theme.title,
|
||||
"(",
|
||||
new Link(theme.id, "https://mapcomplete.org/" + theme.id),
|
||||
")",
|
||||
]),
|
||||
2
|
||||
),
|
||||
theme.description,
|
||||
const el = [
|
||||
["##",
|
||||
theme.title,
|
||||
"(",
|
||||
`[${theme.id}](https://mapcomplete.org/${theme.id})`,
|
||||
")"
|
||||
].join(" "),
|
||||
|
||||
theme.description.txt,
|
||||
"This theme contains the following layers:",
|
||||
new List(
|
||||
MarkdownUtils.list(
|
||||
theme.layers
|
||||
.filter((l) => !l.id.startsWith("note_import_"))
|
||||
.map((l) => new Link(l.id, "../Layers/" + l.id + ".md"))
|
||||
.map((l) => (`[${l.id}](../Layers/${l.id}.md)`))
|
||||
),
|
||||
"Available languages:",
|
||||
new List(theme.language.filter((ln) => ln !== "_context")),
|
||||
]).SetClass("flex flex-col")
|
||||
this.WriteFile(
|
||||
MarkdownUtils.list(theme.language.filter((ln) => ln !== "_context"))
|
||||
].join("\n")
|
||||
this.WriteMarkdownFile(
|
||||
"./Docs/Themes/" + theme.id + ".md",
|
||||
el,
|
||||
[`assets/themes/${theme.id}/${theme.id}.json`],
|
||||
|
@ -533,11 +512,11 @@ export class GenerateDocs extends Script {
|
|||
}
|
||||
}
|
||||
|
||||
const el = new Combine([
|
||||
new Title("Special and other useful layers", 1),
|
||||
const el = [
|
||||
"# Special and other useful layers",
|
||||
"MapComplete has a few data layers available in the theme which have special properties through builtin-hooks. Furthermore, there are some normal layers (which are built from normal Theme-config files) but are so general that they get a mention here.",
|
||||
new Title("Priviliged layers", 1),
|
||||
new List(Constants.priviliged_layers.map((id) => "[" + id + "](#" + id + ")")),
|
||||
"# Priviliged layers",
|
||||
MarkdownUtils.list(Constants.priviliged_layers.map((id) => "[" + id + "](#" + id + ")")),
|
||||
...Utils.NoNull(
|
||||
Constants.priviliged_layers.map((id) => AllSharedLayers.sharedLayers.get(id))
|
||||
).map((l) =>
|
||||
|
@ -549,15 +528,15 @@ export class GenerateDocs extends Script {
|
|||
Constants.no_include.indexOf(<any>l.id) < 0
|
||||
)
|
||||
),
|
||||
new Title("Normal layers", 1),
|
||||
"# Normal layers",
|
||||
"The following layers are included in MapComplete:",
|
||||
new List(
|
||||
MarkdownUtils.list(
|
||||
Array.from(AllSharedLayers.sharedLayers.keys()).map(
|
||||
(id) => new Link(id, "./Layers/" + id + ".md")
|
||||
(id) => `[${id}](./Layers/${id}.md)`
|
||||
)
|
||||
),
|
||||
])
|
||||
this.WriteFile("./Docs/BuiltinLayers.md", el, ["src/Customizations/AllKnownLayouts.ts"])
|
||||
)
|
||||
].join("\n\n")
|
||||
this.WriteMarkdownFile("./Docs/BuiltinLayers.md", el, ["src/Customizations/AllKnownLayouts.ts"])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import List from "../UI/Base/List"
|
|||
import Title from "../UI/Base/Title"
|
||||
import { BBox } from "./BBox"
|
||||
import { Feature, Geometry, MultiPolygon, Polygon } from "geojson"
|
||||
import MarkdownUtils from "../Utils/MarkdownUtils"
|
||||
|
||||
export interface ExtraFuncParams {
|
||||
/**
|
||||
|
@ -517,16 +518,16 @@ export class ExtraFunctions {
|
|||
return record
|
||||
}
|
||||
|
||||
public static HelpText(): BaseUIElement {
|
||||
const elems = []
|
||||
public static HelpText(): string {
|
||||
const elems: string[] = []
|
||||
for (const func of ExtraFunctions.allFuncs) {
|
||||
elems.push(new Title(func._name, 3), func._doc, new List(func._args ?? [], true))
|
||||
elems.push("### "+func._name, func._doc, MarkdownUtils.list(func._args))
|
||||
}
|
||||
|
||||
return new Combine([
|
||||
return [
|
||||
ExtraFunctions.intro,
|
||||
new List(ExtraFunctions.allFuncs.map((func) => `[${func._name}](#${func._name})`)),
|
||||
MarkdownUtils.list(ExtraFunctions.allFuncs.map((func) => `[${func._name}](#${func._name})`)),
|
||||
...elems,
|
||||
])
|
||||
].join("\n")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import ChangeLocationAction from "./Actions/ChangeLocationAction"
|
|||
import ChangeTagAction from "./Actions/ChangeTagAction"
|
||||
import FeatureSwitchState from "../State/FeatureSwitchState"
|
||||
import DeleteAction from "./Actions/DeleteAction"
|
||||
import MarkdownUtils from "../../Utils/MarkdownUtils"
|
||||
|
||||
/**
|
||||
* Handles all changes made to OSM.
|
||||
|
@ -116,7 +117,7 @@ export class Changes {
|
|||
return changes
|
||||
}
|
||||
|
||||
public static getDocs(): BaseUIElement {
|
||||
public static getDocs(): string {
|
||||
function addSource(items: any[], src: string) {
|
||||
items.forEach((i) => {
|
||||
i["source"] = src
|
||||
|
@ -188,24 +189,24 @@ export class Changes {
|
|||
...ReplaceGeometryAction.metatags,
|
||||
...SplitAction.metatags,*/
|
||||
]
|
||||
return new Combine([
|
||||
new Title("Metatags on a changeset", 1),
|
||||
return [
|
||||
"# Metatags on a changeset",
|
||||
"You might encounter the following metatags on a changeset:",
|
||||
new Table(
|
||||
MarkdownUtils.table(
|
||||
["key", "value", "explanation", "source"],
|
||||
metatagsDocs.map(({ key, value, docs, source, changeType, specialMotivation }) => [
|
||||
key ?? changeType?.join(", ") ?? "",
|
||||
value,
|
||||
new Combine([
|
||||
[
|
||||
docs,
|
||||
specialMotivation
|
||||
? "This might give a reason per modified node or way"
|
||||
: "",
|
||||
]),
|
||||
].join("\n"),
|
||||
source,
|
||||
]),
|
||||
),
|
||||
])
|
||||
].join("\n\n")
|
||||
}
|
||||
|
||||
private static GetNeededIds(changes: ChangeDescription[]) {
|
||||
|
|
|
@ -766,29 +766,27 @@ export default class SimpleMetaTaggers {
|
|||
return somethingChanged
|
||||
}
|
||||
|
||||
public static HelpText(): BaseUIElement {
|
||||
const subElements: (string | BaseUIElement)[] = [
|
||||
new Combine([
|
||||
public static HelpText(): string {
|
||||
const subElements: string[] = [
|
||||
[
|
||||
"Metatags are extra tags available, in order to display more data or to give better questions.",
|
||||
"They are calculated automatically on every feature when the data arrives in the webbrowser. This document gives an overview of the available metatags.",
|
||||
"**Hint:** when using metatags, add the [query parameter](URL_Parameters.md) `debug=true` to the URL. This will include a box in the popup for features which shows all the properties of the object",
|
||||
]).SetClass("flex-col"),
|
||||
].join("\n"),
|
||||
]
|
||||
|
||||
subElements.push(new Title("Metatags calculated by MapComplete", 2))
|
||||
subElements.push("## Metatags calculated by MapComplete")
|
||||
subElements.push(
|
||||
new FixedUiElement(
|
||||
"The following values are always calculated, by default, by MapComplete and are available automatically on all elements in every theme"
|
||||
)
|
||||
)
|
||||
for (const metatag of SimpleMetaTaggers.metatags) {
|
||||
subElements.push(
|
||||
new Title(metatag.keys.join(", "), 3),
|
||||
"### "+metatag.keys.join(", "),
|
||||
metatag.doc,
|
||||
metatag.isLazy ? "This is a lazy metatag and is only calculated when needed" : ""
|
||||
)
|
||||
}
|
||||
|
||||
return new Combine(subElements).SetClass("flex-col")
|
||||
return subElements.join("\n\n")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import { RegexTag } from "../../Logic/Tags/RegexTag"
|
|||
import BaseUIElement from "../../UI/BaseUIElement"
|
||||
import Table from "../../UI/Base/Table"
|
||||
import Combine from "../../UI/Base/Combine"
|
||||
import MarkdownUtils from "../../Utils/MarkdownUtils"
|
||||
export type FilterConfigOption = {
|
||||
question: Translation
|
||||
osmTags: TagsFilter | undefined
|
||||
|
@ -199,20 +200,20 @@ export default class FilterConfig {
|
|||
)
|
||||
}
|
||||
|
||||
public GenerateDocs(): BaseUIElement {
|
||||
public GenerateDocs(): string {
|
||||
const hasField = this.options.some((opt) => opt.fields?.length > 0)
|
||||
return new Table(
|
||||
return MarkdownUtils.table(
|
||||
Utils.NoNull(["id", "question", "osmTags", hasField ? "fields" : undefined]),
|
||||
this.options.map((opt, i) => {
|
||||
const isDefault = this.options.length > 1 && (this.defaultSelection ?? 0) == i
|
||||
return Utils.NoNull([
|
||||
return <string[]> Utils.NoNull([
|
||||
this.id + "." + i,
|
||||
isDefault
|
||||
? new Combine([opt.question.SetClass("font-bold"), "(default)"])
|
||||
? `*${opt.question.txt}* (default)`
|
||||
: opt.question,
|
||||
opt.osmTags?.asHumanString(false, false, {}) ?? "",
|
||||
opt.osmTags?.asHumanString() ?? "",
|
||||
opt.fields?.length > 0
|
||||
? new Combine(opt.fields.map((f) => f.name + " (" + f.type + ")"))
|
||||
? (opt.fields.map((f) => f.name + " (" + f.type + ")")).join(" ")
|
||||
: undefined,
|
||||
])
|
||||
})
|
||||
|
|
|
@ -14,13 +14,9 @@ import WithContextLoader from "./WithContextLoader"
|
|||
import LineRenderingConfig from "./LineRenderingConfig"
|
||||
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
|
||||
import BaseUIElement from "../../UI/BaseUIElement"
|
||||
import Combine from "../../UI/Base/Combine"
|
||||
import Title from "../../UI/Base/Title"
|
||||
import List from "../../UI/Base/List"
|
||||
import Link from "../../UI/Base/Link"
|
||||
import { Utils } from "../../Utils"
|
||||
import { TagsFilter } from "../../Logic/Tags/TagsFilter"
|
||||
import Table from "../../UI/Base/Table"
|
||||
import FilterConfigJson from "./Json/FilterConfigJson"
|
||||
import { Overpass } from "../../Logic/Osm/Overpass"
|
||||
import { FixedUiElement } from "../../UI/Base/FixedUiElement"
|
||||
|
@ -28,6 +24,7 @@ import { ImmutableStore } from "../../Logic/UIEventSource"
|
|||
import { OsmTags } from "../OsmFeature"
|
||||
import Constants from "../Constants"
|
||||
import { QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRenderingConfigJson"
|
||||
import MarkdownUtils from "../../Utils/MarkdownUtils"
|
||||
|
||||
export default class LayerConfig extends WithContextLoader {
|
||||
public static readonly syncSelectionAllowed = ["no", "local", "theme-only", "global"] as const
|
||||
|
@ -90,7 +87,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
overpassScript: json.source["overpassScript"],
|
||||
isOsmCache: json.source["isOsmCache"],
|
||||
mercatorCrs: json.source["mercatorCrs"],
|
||||
idKey: json.source["idKey"],
|
||||
idKey: json.source["idKey"]
|
||||
},
|
||||
json.id
|
||||
)
|
||||
|
@ -159,7 +156,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
let preciseInput: PreciseInput = {
|
||||
preferredBackground: ["photo"],
|
||||
snapToLayers: undefined,
|
||||
maxSnapDistance: undefined,
|
||||
maxSnapDistance: undefined
|
||||
}
|
||||
if (pr["preciseInput"] !== undefined) {
|
||||
throw (
|
||||
|
@ -172,7 +169,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
let snapToLayers = pr.snapToLayer
|
||||
preciseInput = {
|
||||
snapToLayers,
|
||||
maxSnapDistance: pr.maxSnapDistance ?? 10,
|
||||
maxSnapDistance: pr.maxSnapDistance ?? 10
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,7 +181,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
`${translationContext}.presets.${i}.description`
|
||||
),
|
||||
preciseInput: preciseInput,
|
||||
exampleImages: pr.exampleImages,
|
||||
exampleImages: pr.exampleImages
|
||||
}
|
||||
return config
|
||||
})
|
||||
|
@ -306,7 +303,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
}
|
||||
|
||||
this.titleIcons = this.ParseTagRenderings(<TagRenderingConfigJson[]>json.titleIcons ?? [], {
|
||||
readOnlyMode: true,
|
||||
readOnlyMode: true
|
||||
})
|
||||
|
||||
this.title = this.tr("title", undefined, translationContext)
|
||||
|
@ -366,8 +363,8 @@ export default class LayerConfig extends WithContextLoader {
|
|||
}[] = [],
|
||||
addedByDefault = false,
|
||||
canBeIncluded = true
|
||||
): BaseUIElement {
|
||||
const extraProps: (string | BaseUIElement)[] = []
|
||||
): string {
|
||||
const extraProps: string[] = []
|
||||
extraProps.push("This layer is shown at zoomlevel **" + this.minzoom + "** and higher")
|
||||
|
||||
if (canBeIncluded) {
|
||||
|
@ -404,13 +401,11 @@ export default class LayerConfig extends WithContextLoader {
|
|||
|
||||
if (this.source?.geojsonSource !== undefined) {
|
||||
extraProps.push(
|
||||
new Combine([
|
||||
Utils.runningFromConsole
|
||||
? "<img src='../warning.svg' height='1rem'/>"
|
||||
: undefined,
|
||||
[
|
||||
"<img src='../warning.svg' height='1rem'/>",
|
||||
"This layer is loaded from an external source, namely ",
|
||||
new FixedUiElement(this.source.geojsonSource).SetClass("code"),
|
||||
])
|
||||
"`" + this.source.geojsonSource + "`"
|
||||
].join("\n\n")
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
@ -419,44 +414,44 @@ export default class LayerConfig extends WithContextLoader {
|
|||
)
|
||||
}
|
||||
|
||||
let usingLayer: BaseUIElement[] = []
|
||||
let usingLayer: string[] = []
|
||||
if (!addedByDefault) {
|
||||
if (usedInThemes?.length > 0) {
|
||||
usingLayer = [
|
||||
new Title("Themes using this layer", 2),
|
||||
new List(
|
||||
"## Themes using this layer",
|
||||
MarkdownUtils.list(
|
||||
(usedInThemes ?? []).map(
|
||||
(id) => new Link(id, "https://mapcomplete.org/" + id)
|
||||
(id) => (`[${id}](https://mapcomplete.org/${id})`)
|
||||
)
|
||||
),
|
||||
)
|
||||
]
|
||||
} else if (this.source !== null) {
|
||||
usingLayer = [new FixedUiElement("No themes use this layer")]
|
||||
usingLayer = ["No themes use this layer"]
|
||||
}
|
||||
}
|
||||
|
||||
for (const dep of dependencies) {
|
||||
extraProps.push(
|
||||
new Combine([
|
||||
[
|
||||
"This layer will automatically load ",
|
||||
new Link(dep.neededLayer, "./" + dep.neededLayer + ".md"),
|
||||
(`[${dep.neededLayer}](./${dep.neededLayer}.md)`),
|
||||
" into the layout as it depends on it: ",
|
||||
dep.reason,
|
||||
"(" + dep.context + ")",
|
||||
])
|
||||
"(" + dep.context + ")"
|
||||
].join(" ")
|
||||
)
|
||||
}
|
||||
|
||||
for (const revDep of Utils.Dedup(layerIsNeededBy?.get(this.id) ?? [])) {
|
||||
extraProps.push(
|
||||
new Combine([
|
||||
[
|
||||
"This layer is needed as dependency for layer",
|
||||
new Link(revDep, "#" + revDep),
|
||||
])
|
||||
(`[${revDep}](#${revDep})`)
|
||||
].join(" ")
|
||||
)
|
||||
}
|
||||
|
||||
const tableRows = Utils.NoNull(
|
||||
const tableRows: string[][] = Utils.NoNull(
|
||||
this.tagRenderings
|
||||
.map((tr) => tr.FreeformValues())
|
||||
.map((values) => {
|
||||
|
@ -467,32 +462,28 @@ export default class LayerConfig extends WithContextLoader {
|
|||
Link.OsmWiki(values.key, v, true).SetClass("mr-2")
|
||||
) ?? ["_no preset options defined, or no values in them_"]
|
||||
return [
|
||||
new Combine([
|
||||
new Link(
|
||||
"<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>",
|
||||
"https://taginfo.openstreetmap.org/keys/" + values.key + "#values",
|
||||
true
|
||||
),
|
||||
Link.OsmWiki(values.key),
|
||||
]).SetClass("flex"),
|
||||
[
|
||||
`<a target="_blank" href='https://taginfo.openstreetmap.org/keys/${ values.key}#values'><img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'></a>]`,
|
||||
Link.OsmWiki(values.key)
|
||||
].join(" "),
|
||||
values.type === undefined
|
||||
? "Multiple choice"
|
||||
: new Link(values.type, "../SpecialInputElements.md#" + values.type),
|
||||
new Combine(embedded).SetClass("flex"),
|
||||
: `[${values.type}](../SpecialInputElements.md#${values.type})`,
|
||||
embedded.join(" ")
|
||||
]
|
||||
})
|
||||
)
|
||||
|
||||
let quickOverview: BaseUIElement = undefined
|
||||
let quickOverview: string[] = []
|
||||
if (tableRows.length > 0) {
|
||||
quickOverview = new Combine([
|
||||
new FixedUiElement("Warning: ").SetClass("bold"),
|
||||
quickOverview = [
|
||||
("**Warning:**"),
|
||||
"this quick overview is incomplete",
|
||||
new Table(
|
||||
MarkdownUtils.table(
|
||||
["attribute", "type", "values which are supported by this layer"],
|
||||
tableRows
|
||||
).SetClass("zebra-table"),
|
||||
]).SetClass("flex-col flex")
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
let iconImg: BaseUIElement = new FixedUiElement("")
|
||||
|
@ -503,35 +494,36 @@ export default class LayerConfig extends WithContextLoader {
|
|||
.map(
|
||||
(mr) =>
|
||||
mr.RenderIcon(new ImmutableStore<OsmTags>({ id: "node/-1" }), {
|
||||
includeBadges: false,
|
||||
includeBadges: false
|
||||
}).html
|
||||
)
|
||||
.find((i) => i !== undefined)
|
||||
}
|
||||
|
||||
let overpassLink: BaseUIElement = undefined
|
||||
let overpassLink: string = undefined
|
||||
if (this.source !== undefined) {
|
||||
try {
|
||||
overpassLink = new Link(
|
||||
"Execute on overpass",
|
||||
overpassLink = (
|
||||
"[Execute on overpass](" +
|
||||
Overpass.AsOverpassTurboLink(<TagsFilter>this.source.osmTags.optimize())
|
||||
.replaceAll("(", "%28")
|
||||
.replaceAll(")", "%29")
|
||||
+ ")"
|
||||
)
|
||||
} catch (e) {
|
||||
console.error("Could not generate overpasslink for " + this.id)
|
||||
}
|
||||
}
|
||||
|
||||
const filterDocs: (string | BaseUIElement)[] = []
|
||||
const filterDocs: (string)[] = []
|
||||
if (this.filters.length > 0) {
|
||||
filterDocs.push(new Title("Filters", 4))
|
||||
filterDocs.push("#### Filters")
|
||||
filterDocs.push(...this.filters.map((filter) => filter.GenerateDocs()))
|
||||
}
|
||||
|
||||
const tagsDescription = []
|
||||
const tagsDescription: string[] = []
|
||||
if (this.source !== null) {
|
||||
tagsDescription.push(new Title("Basic tags for this layer", 2))
|
||||
tagsDescription.push("## Basic tags for this layer")
|
||||
|
||||
const neededTags = <TagsFilter>this.source.osmTags.optimize()
|
||||
if (neededTags["and"]) {
|
||||
|
@ -549,8 +541,8 @@ export default class LayerConfig extends WithContextLoader {
|
|||
} else {
|
||||
tagsDescription.push(
|
||||
"Elements must match the expression **" +
|
||||
neededTags.asHumanString(true, false, {}) +
|
||||
"**"
|
||||
neededTags.asHumanString(true, false, {}) +
|
||||
"**"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -559,20 +551,19 @@ export default class LayerConfig extends WithContextLoader {
|
|||
tagsDescription.push("This is a special layer - data is not sourced from OpenStreetMap")
|
||||
}
|
||||
|
||||
return new Combine([
|
||||
new Combine([new Title(this.id, 1), iconImg, this.description, "\n"]).SetClass(
|
||||
"flex flex-col"
|
||||
),
|
||||
new List(extraProps),
|
||||
return [
|
||||
[
|
||||
"# " + this.id+"\n",
|
||||
iconImg,
|
||||
this.description, "\n"].join("\n\n"),
|
||||
MarkdownUtils.list(extraProps),
|
||||
...usingLayer,
|
||||
...tagsDescription,
|
||||
new Title("Supported attributes", 2),
|
||||
"## Supported attributes",
|
||||
quickOverview,
|
||||
...this.tagRenderings.map((tr) => tr.GenerateDocumentation()),
|
||||
...filterDocs,
|
||||
])
|
||||
.SetClass("flex-col")
|
||||
.SetClass("link-underline")
|
||||
...filterDocs
|
||||
] .join("\n\n")
|
||||
}
|
||||
|
||||
public CustomCodeSnippets(): string[] {
|
||||
|
|
|
@ -3,11 +3,13 @@ import Combine from "./Combine"
|
|||
import BaseUIElement from "../BaseUIElement"
|
||||
import Title from "./Title"
|
||||
import Table from "./Table"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { VariableUiElement } from "./VariableUIElement"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import { FixedUiElement } from "./FixedUiElement"
|
||||
import Translations from "../i18n/Translations"
|
||||
import MarkdownUtils from "../../Utils/MarkdownUtils"
|
||||
import Locale from "../i18n/Locale"
|
||||
|
||||
export default class Hotkeys {
|
||||
public static readonly _docs: UIEventSource<
|
||||
|
@ -28,18 +30,18 @@ export default class Hotkeys {
|
|||
public static RegisterHotkey(
|
||||
key: (
|
||||
| {
|
||||
ctrl: string
|
||||
}
|
||||
ctrl: string
|
||||
}
|
||||
| {
|
||||
shift: string
|
||||
}
|
||||
shift: string
|
||||
}
|
||||
| {
|
||||
alt: string
|
||||
}
|
||||
alt: string
|
||||
}
|
||||
| {
|
||||
nomod: string
|
||||
}
|
||||
) & {
|
||||
nomod: string
|
||||
}
|
||||
) & {
|
||||
onUp?: boolean
|
||||
},
|
||||
documentation: string | Translation,
|
||||
|
@ -61,7 +63,7 @@ export default class Hotkeys {
|
|||
return
|
||||
}
|
||||
if (key["ctrl"] !== undefined) {
|
||||
document.addEventListener("keydown", function (event) {
|
||||
document.addEventListener("keydown", function(event) {
|
||||
if (event.ctrlKey && event.key === keycode) {
|
||||
if (action() !== false) {
|
||||
event.preventDefault()
|
||||
|
@ -69,7 +71,7 @@ export default class Hotkeys {
|
|||
}
|
||||
})
|
||||
} else if (key["shift"] !== undefined) {
|
||||
document.addEventListener(type, function (event) {
|
||||
document.addEventListener(type, function(event) {
|
||||
if (Hotkeys.textElementSelected(event)) {
|
||||
// A text element is selected, we don't do anything special
|
||||
return
|
||||
|
@ -81,7 +83,7 @@ export default class Hotkeys {
|
|||
}
|
||||
})
|
||||
} else if (key["alt"] !== undefined) {
|
||||
document.addEventListener(type, function (event) {
|
||||
document.addEventListener(type, function(event) {
|
||||
if (event.altKey && event.key === keycode) {
|
||||
if (action() !== false) {
|
||||
event.preventDefault()
|
||||
|
@ -89,7 +91,7 @@ export default class Hotkeys {
|
|||
}
|
||||
})
|
||||
} else if (key["nomod"] !== undefined) {
|
||||
document.addEventListener(type, function (event) {
|
||||
document.addEventListener(type, function(event) {
|
||||
if (Hotkeys.textElementSelected(event) && keycode !== "Escape") {
|
||||
// A text element is selected, we don't do anything special
|
||||
return
|
||||
|
@ -104,61 +106,71 @@ export default class Hotkeys {
|
|||
}
|
||||
}
|
||||
|
||||
static generateDocumentation(): BaseUIElement {
|
||||
return new VariableUiElement(
|
||||
Hotkeys._docs.mapD((docs) => {
|
||||
let byKey: [string, string | Translation, Translation[] | undefined][] = docs
|
||||
.map(({ key, documentation, alsoTriggeredBy }) => {
|
||||
const modifiers = Object.keys(key).filter(
|
||||
(k) => k !== "nomod" && k !== "onUp"
|
||||
)
|
||||
let keycode: string =
|
||||
key["ctrl"] ?? key["shift"] ?? key["alt"] ?? key["nomod"]
|
||||
if (keycode.length == 1) {
|
||||
keycode = keycode.toUpperCase()
|
||||
}
|
||||
if (keycode === " ") {
|
||||
keycode = "Spacebar"
|
||||
}
|
||||
modifiers.push(keycode)
|
||||
return <[string, string | Translation, Translation[] | undefined]>[
|
||||
modifiers.join("+"),
|
||||
documentation,
|
||||
alsoTriggeredBy,
|
||||
]
|
||||
})
|
||||
.sort()
|
||||
byKey = Utils.NoNull(byKey)
|
||||
for (let i = byKey.length - 1; i > 0; i--) {
|
||||
if (byKey[i - 1][0] === byKey[i][0]) {
|
||||
byKey.splice(i, 1)
|
||||
}
|
||||
static prepareDocumentation(docs: {
|
||||
key: { ctrl?: string; shift?: string; alt?: string; nomod?: string; onUp?: boolean }
|
||||
documentation: string | Translation
|
||||
alsoTriggeredBy: Translation[]
|
||||
}[]){
|
||||
let byKey: [string, string | Translation, Translation[] | undefined][] = docs
|
||||
.map(({ key, documentation, alsoTriggeredBy }) => {
|
||||
const modifiers = Object.keys(key).filter(
|
||||
(k) => k !== "nomod" && k !== "onUp"
|
||||
)
|
||||
let keycode: string =
|
||||
key["ctrl"] ?? key["shift"] ?? key["alt"] ?? key["nomod"]
|
||||
if (keycode.length == 1) {
|
||||
keycode = keycode.toUpperCase()
|
||||
}
|
||||
const t = Translations.t.hotkeyDocumentation
|
||||
return new Combine([
|
||||
new Title(t.title, 1),
|
||||
t.intro,
|
||||
new Table(
|
||||
[t.key, t.action],
|
||||
byKey.map(([key, doc, alsoTriggeredBy]) => {
|
||||
let keyEl: BaseUIElement = new FixedUiElement(key).SetClass(
|
||||
"literal-code w-fit h-fit"
|
||||
)
|
||||
if (alsoTriggeredBy?.length > 0) {
|
||||
keyEl = new Combine([keyEl, ...alsoTriggeredBy]).SetClass(
|
||||
"flex gap-x-4 items-center"
|
||||
)
|
||||
}
|
||||
return [keyEl, doc]
|
||||
})
|
||||
),
|
||||
])
|
||||
if (keycode === " ") {
|
||||
keycode = "Spacebar"
|
||||
}
|
||||
modifiers.push(keycode)
|
||||
return <[string, string | Translation, Translation[] | undefined]>[
|
||||
modifiers.join("+"),
|
||||
documentation,
|
||||
alsoTriggeredBy
|
||||
]
|
||||
})
|
||||
)
|
||||
.sort()
|
||||
byKey = Utils.NoNull(byKey)
|
||||
for (let i = byKey.length - 1; i > 0; i--) {
|
||||
if (byKey[i - 1][0] === byKey[i][0]) {
|
||||
byKey.splice(i, 1)
|
||||
}
|
||||
}
|
||||
return byKey
|
||||
}
|
||||
|
||||
static generateDocumentationDynamic(): BaseUIElement {
|
||||
return new VariableUiElement(Hotkeys._docs.map((_) => Hotkeys.generateDocumentation()))
|
||||
static generateDocumentationFor(docs: {
|
||||
key: { ctrl?: string; shift?: string; alt?: string; nomod?: string; onUp?: boolean }
|
||||
documentation: string | Translation
|
||||
alsoTriggeredBy: Translation[]
|
||||
}[], language: string): string {
|
||||
|
||||
const tr = Translations.t.hotkeyDocumentation
|
||||
function t(t: Translation | string){
|
||||
if(typeof t === "string"){
|
||||
return t
|
||||
}
|
||||
return t.textFor(language)
|
||||
}
|
||||
const contents: string[][] = this.prepareDocumentation(docs)
|
||||
.map(([key, doc, alsoTriggeredBy]) => {
|
||||
let keyEl: string = [key, ...(alsoTriggeredBy??[])].map(k => "`"+t(k)+"`").join(" ")
|
||||
return [keyEl, t(doc)]
|
||||
})
|
||||
return [
|
||||
"# "+t(tr.title),
|
||||
t(tr.intro),
|
||||
MarkdownUtils.table(
|
||||
[t(tr.key), t(tr.action)],
|
||||
contents
|
||||
)
|
||||
].join("\n")
|
||||
}
|
||||
|
||||
public static generateDocumentation(language?: string){
|
||||
return Hotkeys.generateDocumentationFor(Hotkeys._docs.data, language?? Locale.language.data)
|
||||
}
|
||||
|
||||
private static textElementSelected(event: KeyboardEvent): boolean {
|
||||
|
|
|
@ -98,7 +98,7 @@ export default class TableOfContents {
|
|||
const intro = md.substring(0, firstTitleIndex)
|
||||
const splitPoint = intro.lastIndexOf("\n")
|
||||
|
||||
return md.substring(0, splitPoint) + toc + md.substring(splitPoint)
|
||||
return md.substring(0, splitPoint) +"\n" toc + md.substring(splitPoint)
|
||||
}
|
||||
|
||||
public static generateStructure(
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
*/
|
||||
import { Utils } from "../Utils"
|
||||
|
||||
/* @deprecated
|
||||
*/
|
||||
export default abstract class BaseUIElement {
|
||||
protected _constructedHtmlElement: HTMLElement
|
||||
protected isDestroyed = false
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
<script lang="ts">
|
||||
import Translations from "../i18n/Translations"
|
||||
import { Utils } from "../../Utils"
|
||||
import Hotkeys from "../Base/Hotkeys"
|
||||
import Constants from "../../Models/Constants"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import Add from "../../assets/svg/Add.svelte"
|
||||
import Github from "../../assets/svg/Github.svelte"
|
||||
import DocumentChartBar from "@babeard/svelte-heroicons/outline/DocumentChartBar"
|
||||
import Mastodon from "../../assets/svg/Mastodon.svelte"
|
||||
import Liberapay from "../../assets/svg/Liberapay.svelte"
|
||||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import { EyeIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||
import MapillaryLink from "./MapillaryLink.svelte"
|
||||
import OpenJosm from "../Base/OpenJosm.svelte"
|
||||
|
@ -18,6 +15,7 @@
|
|||
import Community from "../../assets/svg/Community.svelte"
|
||||
import Bug from "../../assets/svg/Bug.svelte"
|
||||
import ThemeViewState from "../../Models/ThemeViewState"
|
||||
import DocumentChartBar from "@babeard/svelte-heroicons/outline/DocumentChartBar"
|
||||
|
||||
export let state: ThemeViewState
|
||||
|
||||
|
|
55
src/UI/BigComponents/HotkeyTable.svelte
Normal file
55
src/UI/BigComponents/HotkeyTable.svelte
Normal file
|
@ -0,0 +1,55 @@
|
|||
<script lang="ts">
|
||||
|
||||
import Hotkeys from "../Base/Hotkeys"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import { Utils } from "../../Utils"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import AccordionSingle from "../Flowbite/AccordionSingle.svelte"
|
||||
|
||||
let keys = Hotkeys._docs
|
||||
const t = Translations.t.hotkeyDocumentation
|
||||
|
||||
|
||||
let byKey = Hotkeys.prepareDocumentation($keys)
|
||||
$: {
|
||||
byKey = Hotkeys.prepareDocumentation($keys)
|
||||
}
|
||||
</script>
|
||||
<AccordionSingle>
|
||||
|
||||
<div slot="header">
|
||||
<Tr t={t.title} />
|
||||
</div>
|
||||
<Tr t={t.intro} />
|
||||
<table>
|
||||
<tr>
|
||||
<th>
|
||||
<Tr t={t.key}></Tr>
|
||||
</th>
|
||||
<th>
|
||||
<Tr t={t.action} />
|
||||
</th>
|
||||
</tr>
|
||||
{#each byKey as [key, doc, alsoTriggeredBy] }
|
||||
<tr>
|
||||
<td class="flex items-center justify-center">
|
||||
{#if alsoTriggeredBy}
|
||||
<div class="flex items-center justify-center gap-x-1">
|
||||
|
||||
<div class="literal-code w-fit h-fit">{key}</div>
|
||||
<div class="literal-code w-fit h-fit">{alsoTriggeredBy}</div>
|
||||
|
||||
</div>
|
||||
|
||||
{:else}
|
||||
<div class="literal-code w-fit h-fit flex items-center w-full">{key}</div>
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
<Tr t={doc} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
</AccordionSingle>
|
|
@ -22,7 +22,7 @@
|
|||
selectedElement.properties.id
|
||||
)
|
||||
|
||||
let isAddNew = tags.mapD(t => t.id.startsWith(LastClickFeatureSource.newPointElementId))
|
||||
let isAddNew = tags.mapD(t => t?.id?.startsWith(LastClickFeatureSource.newPointElementId) ?? false)
|
||||
|
||||
function getLayer(properties: Record<string, string>) {
|
||||
if (properties.id === "settings") {
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
import Combine from "../Base/Combine"
|
||||
import Translations from "../i18n/Translations"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
import { Store } from "../../Logic/UIEventSource"
|
||||
import { LicenseInfo } from "../../Logic/ImageProviders/LicenseInfo"
|
||||
import { FixedUiElement } from "../Base/FixedUiElement"
|
||||
import Link from "../Base/Link"
|
||||
|
||||
/**
|
||||
* Small box in the bottom left of an image, e.g. the image in a popup
|
||||
*/
|
||||
export default class Attribution extends VariableUiElement {
|
||||
constructor(license: Store<LicenseInfo>, icon: BaseUIElement, date?: Date) {
|
||||
if (license === undefined) {
|
||||
throw "No license source given in the attribution element"
|
||||
}
|
||||
super(
|
||||
license.map((license: LicenseInfo) => {
|
||||
if (license === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
let title = undefined
|
||||
if (license?.title) {
|
||||
title = Translations.W(license?.title).SetClass("block")
|
||||
if (license.informationLocation) {
|
||||
title = new Link(title, license.informationLocation.href, true)
|
||||
}
|
||||
}
|
||||
|
||||
return new Combine([
|
||||
icon
|
||||
?.SetClass("block left")
|
||||
.SetStyle("height: 2em; width: 2em; padding-right: 0.5em;"),
|
||||
|
||||
new Combine([
|
||||
title,
|
||||
Translations.W(license?.artist ?? "").SetClass("block font-bold"),
|
||||
Translations.W(license?.license ?? license?.licenseShortName),
|
||||
date === undefined
|
||||
? undefined
|
||||
: new FixedUiElement(date.toLocaleDateString()),
|
||||
]).SetClass("flex flex-col"),
|
||||
]).SetClass(
|
||||
"flex flex-row bg-black text-white text-sm absolute bottom-0 left-0 p-0.5 pl-5 pr-3 rounded-lg no-images"
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
|
@ -99,15 +99,15 @@ export default class Validators {
|
|||
|
||||
private static _byType = Validators._byTypeConstructor()
|
||||
|
||||
public static HelpText(): BaseUIElement {
|
||||
const explanations: BaseUIElement[] = Validators.AllValidators.map((type) =>
|
||||
new Combine([new Title(type.name, 3), type.explanation]).SetClass("flex flex-col")
|
||||
public static HelpText(): string {
|
||||
const explanations: string[] = Validators.AllValidators.flatMap((type) =>
|
||||
["### "+type.name, type.explanation]
|
||||
)
|
||||
return new Combine([
|
||||
new Title("Available types for text fields", 1),
|
||||
return [
|
||||
"# Available types for text fields",
|
||||
"The listed types here trigger a special input element. Use them in `tagrendering.freeform.type` of your tagrendering to activate them",
|
||||
...explanations,
|
||||
]).SetClass("flex flex-col")
|
||||
].join("\n")
|
||||
}
|
||||
|
||||
private static _byTypeConstructor(): Map<ValidatorType, Validator> {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import Combine from "../../Base/Combine"
|
||||
import Wikidata, { WikidataResponse } from "../../../Logic/Web/Wikidata"
|
||||
import WikidataSearchBox from "../../Wikipedia/WikidataSearchBox"
|
||||
import { Validator } from "../Validator"
|
||||
import { Translation } from "../../i18n/Translation"
|
||||
import Translations from "../../i18n/Translations"
|
||||
import Title from "../../Base/Title"
|
||||
import Table from "../../Base/Table"
|
||||
import MarkdownUtils from "../../../Utils/MarkdownUtils"
|
||||
|
||||
export default class WikidataValidator extends Validator {
|
||||
public static readonly _searchCache = new Map<string, Promise<WikidataResponse[]>>()
|
||||
|
@ -23,7 +23,7 @@ export default class WikidataValidator extends Validator {
|
|||
"options",
|
||||
new Combine([
|
||||
"A JSON-object of type `{ removePrefixes: string[], removePostfixes: string[] }`.",
|
||||
new Table(
|
||||
MarkdownUtils.table(
|
||||
["subarg", "doc"],
|
||||
[
|
||||
[
|
||||
|
|
|
@ -7,28 +7,29 @@ import { QueryParameters } from "../Logic/Web/QueryParameters"
|
|||
import FeatureSwitchState from "../Logic/State/FeatureSwitchState"
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"
|
||||
import MarkdownUtils from "../Utils/MarkdownUtils"
|
||||
|
||||
export default class QueryParameterDocumentation {
|
||||
private static QueryParamDocsIntro = [
|
||||
new Title("URL-parameters and URL-hash", 1),
|
||||
private static QueryParamDocsIntro: string[] = [
|
||||
"# URL-parameters and URL-hash",
|
||||
"This document gives an overview of which URL-parameters can be used to influence MapComplete.",
|
||||
new Title("What is a URL parameter?", 2),
|
||||
"## What is a URL parameter?",
|
||||
'"URL-parameters are extra parts of the URL used to set the state.',
|
||||
"For example, if the url is `https://mapcomplete.org/cyclofix?lat=51.0&lon=4.3&z=5&test=true#node/1234`, " +
|
||||
"the URL-parameters are stated in the part between the `?` and the `#`. There are multiple, all separated by `&`, namely: ",
|
||||
new List(
|
||||
MarkdownUtils.list(
|
||||
[
|
||||
"The url-parameter `lat` is `51.0` in this instance",
|
||||
"The url-parameter `lon` is `4.3` in this instance",
|
||||
"The url-parameter `z` is `5` in this instance",
|
||||
"The url-parameter `test` is `true` in this instance",
|
||||
].map((s) => Translations.W(s))
|
||||
]
|
||||
),
|
||||
"Finally, the URL-hash is the part after the `#`. It is `node/1234` in this case.",
|
||||
]
|
||||
|
||||
public static UrlParamDocs(): Map<string, string> {
|
||||
const dummyLayout = new LayoutConfig({
|
||||
const dummyLayout = new LayoutConfig(<any>{
|
||||
id: ">theme<",
|
||||
title: { en: "<theme>" },
|
||||
description: "A theme to generate docs with",
|
||||
|
@ -59,26 +60,26 @@ export default class QueryParameterDocumentation {
|
|||
QueryParameters.GetQueryParameter(
|
||||
"layer-<layer-id>",
|
||||
"true",
|
||||
"Wether or not the layer with id <layer-id> is shown"
|
||||
"Whether the layer with id <layer-id> is shown"
|
||||
)
|
||||
return QueryParameters.documentation
|
||||
}
|
||||
|
||||
public static GenerateQueryParameterDocs(): BaseUIElement {
|
||||
const docs: (string | BaseUIElement)[] = [
|
||||
public static GenerateQueryParameterDocs(): string {
|
||||
const docs: string[] = [
|
||||
...QueryParameterDocumentation.QueryParamDocsIntro,
|
||||
...ThemeViewStateHashActor.documentation,
|
||||
]
|
||||
this.UrlParamDocs().forEach((value, key) => {
|
||||
const c = new Combine([
|
||||
new Title(key, 2),
|
||||
const c = [
|
||||
"## "+key,
|
||||
value,
|
||||
QueryParameters.defaults[key] === undefined
|
||||
? "No default value set"
|
||||
: `The default value is _${QueryParameters.defaults[key]}_`,
|
||||
])
|
||||
].join("\n\n")
|
||||
docs.push(c)
|
||||
})
|
||||
return new Combine(docs).SetClass("flex flex-col")
|
||||
return docs.join("\n\n")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
import AboutMapComplete from "./BigComponents/AboutMapComplete.svelte"
|
||||
import IfNot from "./Base/IfNot.svelte"
|
||||
import Hotkeys from "./Base/Hotkeys"
|
||||
import HotkeyTable from "./BigComponents/HotkeyTable.svelte"
|
||||
|
||||
export let state: ThemeViewState
|
||||
let layout = state.layout
|
||||
|
@ -575,7 +576,7 @@
|
|||
<div slot="content0" class="flex flex-col">
|
||||
<AboutMapComplete {state} />
|
||||
<div class="m-2 flex flex-col">
|
||||
<ToSvelte construct={Hotkeys.generateDocumentationDynamic} />
|
||||
<HotkeyTable/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
Loading…
Reference in a new issue