Docs: more tweaks to the documentation

This commit is contained in:
Pieter Vander Vennet 2025-10-08 01:29:00 +02:00
parent 428e462faa
commit 558a899218
5 changed files with 84 additions and 105 deletions

View file

@ -12,6 +12,7 @@
</head>
<body>
<div id="app"></div>
<script src="./_paths.js"></script>
<script>
let language = "en"
if (document.location.pathname.startsWith("/nl/")) {
@ -25,7 +26,7 @@
repo: "https://source.mapcomplete.org/mapcomplete/mapcomplete/",
search: {
maxAge: 86400000, // 1 day cache
paths: "auto",
paths: docsify_paths, // Defined in sibling script _paths.js
auto2top: true,
placeholder: language === "nl" ? "Zoeken" : "Search",
noData: language === "nl" ? "Geen resultaten gevonden" : "No Results found",

View file

@ -1,85 +0,0 @@
<!DOCTYPE html>
<!-- This is meant to be run with docsify -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Description">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
</head>
<body>
<div id="app"></div>
<script>
let language = "en"
if (document.location.pathname.startsWith("/nl/")) {
language = "nl"
}
window.$docsify = {
name: "MapComplete Docs",
noEmoji: true,
loadSidebar: true,
autoToTop: true,
repo: "https://source.mapcomplete.org/mapcomplete/mapcomplete/",
search: {
maxAge: 86400000, // 1 day cache
paths: "auto",
auto2top: true,
placeholder: language === "nl" ? "Zoeken" : "Search",
noData: language === "nl" ? "Geen resultaten gevonden" : "No Results found",
depth: 2,
},
}
</script>
<!-- Docsify v4 -->
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.js"></script>
<style>
.sidebar a {
line-height: 1.3em;
}
.sidebar {
padding-left: 1rem;
}
.sidebar strong {
font-size: 1.2em;
}
.sidebar p:has(strong){
margin: 0;
top: 0;
position: sticky;
background: white;
padding: 0.25rem;
}
.sidebar a:has(strong) {
margin-top: 1em;
}
.active a {
color: #42b983 !important;;
color: var(--theme-color, #42b983) !important;
font-weight: 600 !important;
border-right: 2px solid !important;
}
/*noinspection CssUnusedSymbol*/
.back-to-mc {
display: block;
padding: 0.5rem;
background: #3f3f39;
color: white;
border: 2px solid white;
border-radius: 0.5rem;
}
</style>
</body>
</html>

View file

@ -141,7 +141,7 @@
"optimize-images-scaledown-jpg": "cd assets/ && find . -regextype sed -regex \".*/.*.\\(jpg\\|JPG\\|JPEG\\|jpeg\\)\" -exec mogrify -resize 640x640\\> '{}' \\; && echo 'JPGs are optimized'",
"generate:schemas": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && ./scripts/generateSchemas.sh && echo 'tsjson is done' && vite-node scripts/fixSchemas.ts ",
"reuse-compliance": "reuse lint",
"housekeeping": "export NODE_OPTIONS=\"--max-old-space-size=1200\" && git pull && npx update-browserslist-db@latest && npm run generate && npm run generate:schemas && npm run generate:contributor-list && vite-node scripts/fetchLanguages.ts && vite-node scripts/generateSunnyUnlabeled.ts && npm run format && npm run lint:themes && git add assets/ langs/ Docs/ **/*.ts Docs/* src/* && vite-node scripts/generateTaginfoProjectFiles.ts && git commit -m 'chore: automated housekeeping...'",
"housekeeping": "export NODE_OPTIONS=\"--max-old-space-size=1200\" && git pull && npx update-browserslist-db@latest && npm run generate && npm run generate:schemas && npm run generate:contributor-list && vite-node scripts/fetchLanguages.ts && vite-node scripts/generateSunnyUnlabeled.ts && npm run format && npm run lint:themes && git add assets/ langs/ Docs/ **/*.ts Docs/* src/* && git commit -m 'chore: automated housekeeping...'",
"###": "MICROSERVICES AND SERVER MAINTAINENCE",
"release": "standard-version && git push --follow-tags",
"release:minor": "standard-version --release-as minor",

View file

@ -130,6 +130,8 @@ class WikiPageGenerator {
}
export class GenerateDocs extends Script {
private generatedPaths: string[] = []
constructor() {
super("Generates various documentation files")
}
@ -192,7 +194,11 @@ export class GenerateDocs extends Script {
mkdirSync("./Docs/Themes")
}
this.generateOverviewsForAllSingleLayer()
this.generateNormalLayerOverview()
this.generateNormalLayerOverview("Layers")
this.generateNormalLayerOverview("Layers", "nl")
this.generateNormalLayerOverview("Themes")
this.generateNormalLayerOverview("Themes", "nl")
if (!existsSync("./Docs/nl")) {
mkdirSync("./Docs/nl")
}
@ -212,10 +218,16 @@ export class GenerateDocs extends Script {
])
new WikiPageGenerator().generate()
this.generatedPaths.push("wikiIndex.txt")
this.generateSidebar() // Must be last as it inspects the generated markdown files
this.generateSidebar("nl")
this.generatedPaths.push(".gitignore")
writeFileSync("./Docs/.gitignore", this.generatedPaths
.map(p => p.replace("./Docs/", ""))
.join("\n"), "utf-8")
console.log("Generated docs")
}
@ -272,6 +284,7 @@ export class GenerateDocs extends Script {
writeFileSync(filename, warnAutomated + md + (options?.noWarn ? "" : "\n\n" + generatedFrom + "\n"))
this.generatedPaths.push(filename)
}
@ -725,8 +738,9 @@ export class GenerateDocs extends Script {
/**
* Generates the '_sidebar.md' file that is used by docsify
* Returns _all_ the filepaths (including ''hidden'' ones)
*/
private generateSidebar(subdirectory = "") {
private generateSidebar(subdirectory = ""): string[] {
const tr = Translations.t.app.back.textFor(subdirectory)
const sidebar: string[] = [
`<a href='https://mapcomplete.org' class='back-to-mc'>${tr}</a>`
@ -734,8 +748,8 @@ export class GenerateDocs extends Script {
const allFiles = ScriptUtils.readDirRecSync("./Docs/" + subdirectory)
.filter(path => path.endsWith(".md"))
.filter(path => !path.startsWith("_"))
.filter(path => !path.startsWith("./Docs/nl/") || path.startsWith("./Docs/" + subdirectory))
.map(path => path.substring("./Docs/".length + subdirectory.length + 1))
console.log("AllFiles: " + subdirectory, allFiles)
const perDirectory = new Map<string, string[]>()
function addFile(dir: string, path: string) {
@ -761,6 +775,9 @@ export class GenerateDocs extends Script {
}
}
perDirectory.delete("nl")
// The directories to run over:
const directories: [string, Translation | string][] = [
["", ""],
@ -769,7 +786,6 @@ export class GenerateDocs extends Script {
["Layers", new Translation({ en: "Overview of layers", nl: "Overzicht van de lagen" })],
["Themes", new Translation({ en: "Overview of map themes", nl: "Overzicht van de themas" })],
["UserTests", "Usability tests with users"],
["nl", null] // indicate skip
]
@ -789,6 +805,9 @@ export class GenerateDocs extends Script {
}
sidebar.push(`\n\n [**${titleStr}**](${dir}/README.md)`)
}
if (dir === "Layers" || dir == "Themes") {
continue
}
for (const path of files) {
if (path.startsWith("_") || path.endsWith("README.md")) {
continue
@ -806,17 +825,60 @@ export class GenerateDocs extends Script {
noTableOfContents: true,
noWarn: true,
})
const scriptPath = `./Docs/${subdirectory}/_paths.js`
writeFileSync(scriptPath, "var docsify_paths = " + JSON.stringify(allFiles))
this.generatedPaths.push(scriptPath)
return allFiles
}
private generateNormalLayerOverview() {
const doc = ["# Layers",
`The following layers are available in MapComplete ${Constants.vNumber}:`,
MarkdownUtils.list(
Array.from(AllSharedLayers.sharedLayers.keys()).map(
(id) => `[${id}](./Layers/${id}.md)`,
),
)]
this.writeMarkdownFile("./Docs/Layers/README.md", doc.join("\n\n"), ["./assets/layers/*.json"])
private generateNormalLayerOverview(type: "Layers" | "Themes", subdir = "") {
const layerinfo: [string, string, string][] = []
const source: {
get(id: string): { id: string, name?: Translation, title?: Translation, description?: Translation },
keys(): Iterable<string>
}
= type === "Layers" ? AllSharedLayers.sharedLayers : AllKnownLayouts.allKnownLayouts
const keys = Array.from(source.keys())
keys.sort()
for (const id of keys) {
const layer = source.get(id)
let name = layer.title
if (type === "Layers") {
const layer_ = (<LayerConfig><unknown>layer)
if (!layer_.isNormal()) {
continue
}
name = layer.name
}
layerinfo.push([`[${id}](./Layers/${id})`, name.textFor(subdir), (layer["shortDescription"] ?? layer.description)?.textFor(subdir)])
}
const titles = {
"Layers": new Translation({ en: "Layers", nl: "Lagen" }),
"Themes": new Translation({ en: "Themes", nl: "Kaartthema's" })
}
const intro: Record<string, TypedTranslation<{ version }>> = {
"Layers": new TypedTranslation<{ version }>({
en: "The following layers are available in MapComplete {version}:",
nl: "De volgende lagen zijn beschikbaar in MapComplete {version}:"
}),
"Themes": new TypedTranslation<{ version }>({
en: "The following themes are available in MapComplete {version}:",
nl: "De volgende kaartthemas zijn beschikbaar in MapComplete {version}:"
})
}
const doc = ["# " + titles[type].textFor(subdir),
intro[type].Subs({ version: Constants.vNumber }).textFor(subdir)
, MarkdownUtils.table(
["id", "name", "description"],
layerinfo)
]
this.writeMarkdownFile(`./Docs/${subdir}/${type}/README.md`, doc.join("\n\n"), [`./assets/${type.toLowerCase()}/*.json`])
}
/**

View file

@ -225,10 +225,11 @@ export class Translation {
* @param copyContext if set, the context of 'this' will be added to the new translation. If not, _context will be removed alltogether
* @return The object itself (this) if all strings are the same
*
* new Translation({"en": "This is a sentence. This is another sentence"}).FirstSentence().textFor("en") // "This is a sentence"
* new Translation({"en": "This is a sentence <br/> This is another sentence"}).FirstSentence().textFor("en") // "This is a sentence"
* new Translation({"en": "This is a sentence <br> This is another sentence"}).FirstSentence().textFor("en") // "This is a sentence"
* new Translation({"en": "This is a sentence with a <b>bold</b> word. This is another sentence"}).FirstSentence().textFor("en") // "This is a sentence with a <b>bold</b> word"
* new Translation({"en": "This is a sentence. This is another sentence"}).FirstSentence().textFor("en") // => "This is a sentence"
* new Translation({"en": "This is a sentence <br/> This is another sentence"}).FirstSentence().textFor("en") // => "This is a sentence"
* new Translation({"en": "This is a sentence \n\n This is another sentence"}).FirstSentence().textFor("en") // => "This is a sentence"
* new Translation({"en": "This is a sentence <br> This is another sentence"}).FirstSentence().textFor("en") // => "This is a sentence"
* new Translation({"en": "This is a sentence with a <b>bold</b> word. This is another sentence"}).FirstSentence().textFor("en") // => "This is a sentence with a <b>bold</b> word"
* @constructor
*/
public FirstSentence(copyContext: boolean = false): Translation {
@ -239,7 +240,7 @@ export class Translation {
continue
}
let txt = this.translations[lng]
txt = txt.replace(/(\.|<br\/>|<br>|。).*/, "").trim()
txt = txt.replace(/(\.|<br\/>|<br>||\n).*/s, "").trim()
txt = Utils.EllipsesAfter(txt, 255)
allSame = allSame && txt == this.translations[lng]
tr[lng] = txt