Properly sort versions, add separator
This commit is contained in:
parent
a819d50945
commit
32cd536b69
10 changed files with 119 additions and 52 deletions
4
.github/workflows/build_docs.yml
vendored
4
.github/workflows/build_docs.yml
vendored
|
@ -49,7 +49,7 @@ jobs:
|
|||
|
||||
outputs:
|
||||
pages-url: ${{ steps.get-url.outputs.pages-url }}
|
||||
matrix: ${{ steps.list-langs.outputs.matrix }}
|
||||
matrix: ${{ fromJson(steps.list-langs.outputs.matrix) }}
|
||||
release: ${{ steps.check-release.outputs.release }}
|
||||
|
||||
steps:
|
||||
|
@ -120,7 +120,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
lang: ${{ fromJson(needs.build.outputs.matrix) }}
|
||||
lang: ${{ needs.build.outputs.matrix }}
|
||||
|
||||
env:
|
||||
GITHUB_PAGES_URL: ${{ needs.build.outputs.pages-url }}
|
||||
|
|
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
@ -18,7 +18,7 @@
|
|||
"request": "launch",
|
||||
"module": "hexdoc.hexdoc",
|
||||
"args": [
|
||||
"doc/properties.toml", "-o", "out",// "--allow-missing"
|
||||
"0.9.5/doc/properties.toml", "-o", "out", "--lang", "en_us",
|
||||
],
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": false
|
||||
|
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -15,4 +15,7 @@
|
|||
"[html][jinja-html]": {
|
||||
"editor.rulers": [120],
|
||||
},
|
||||
"files.associations": {
|
||||
"*.js.jinja": "javascript"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
- [x] GitHub Actions
|
||||
- [x] Pypi releasing
|
||||
- [x] API improvements (disable exporting, make it easier (possible?) to generate book for imported mods)
|
||||
- [ ] Unit test for mock addon book
|
||||
- [ ] Re-add edified wood recipe to [Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/edified.json](items/edified) when it actually exists
|
||||
- [x] Language
|
||||
- [x] Version
|
||||
- [x] Don't delete sitemap markers
|
||||
- [x] delete in dest, then copy, then traverse again to build sitemap from scratch
|
||||
- [x] Dropdowns for ^
|
||||
- [x] Dropdowns for ^
|
||||
- [ ] Rewrite the JS code in TypeScript, because I'm going insane trying to modify this
|
||||
- [ ] Unit test for mock addon book
|
||||
- [ ] Re-add edified wood recipe to [Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/edified.json](items/edified) when it actually exists
|
|
@ -40,7 +40,7 @@
|
|||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>{{ lang }} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" id="lang-dropdown"></ul>
|
||||
<ul class="dropdown-menu dropdown-menu-left" id="lang-dropdown"></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -16,5 +16,9 @@
|
|||
<b>Entries which are blurred are spoilers</b>. Click to reveal them, but be aware that they may spoil endgame
|
||||
progression. Alternatively, click <a href="?nospoiler">here</a> to get a version with all spoilers showing.
|
||||
</p>
|
||||
|
||||
{% if not is_bleeding_edge %}
|
||||
<div id="old-version-notice"></div>
|
||||
{% endif %}
|
||||
</blockquote>
|
||||
</div>
|
|
@ -101,6 +101,10 @@ canvas.spell-viz {
|
|||
--dark-mode: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu .divider {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background-color: #201a20;
|
||||
|
@ -142,9 +146,8 @@ canvas.spell-viz {
|
|||
min-width: 120px;
|
||||
}
|
||||
|
||||
.dropdown-menu-ltr {
|
||||
left: 0;
|
||||
right: auto;
|
||||
.dropdown-menu .divider {
|
||||
background-color: #080808;
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a {
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
</style>
|
||||
</noscript>
|
||||
|
||||
<script>
|
||||
<script type="module">
|
||||
{% filter indent(6) %}
|
||||
{%+ include "main.js.jinja" %}
|
||||
{% endfilter %}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
import semver from 'https://cdn.jsdelivr.net/npm/semver@7.5.4/+esm';
|
||||
|
||||
const speeds = [0, 0.25, 0.5, 1, 2, 4];
|
||||
const scrollThreshold = 100;
|
||||
const rfaQueue = [];
|
||||
|
@ -299,6 +301,7 @@ const PAGE_URL = "{{ page_url }}";
|
|||
const VERSION = "{{ version }}";
|
||||
const LANG = "{{ lang }}";
|
||||
|
||||
// Creates an element in the form `<li><a href=${href}>${text}</a></li>`
|
||||
function dropdownItem(text, href) {
|
||||
let a = document.createElement("a");
|
||||
a.href = href;
|
||||
|
@ -309,39 +312,88 @@ function dropdownItem(text, href) {
|
|||
return li;
|
||||
}
|
||||
|
||||
function fillDropdowns(sitemap) {
|
||||
let versionDropdown = document.getElementById("version-dropdown");
|
||||
let langDropdown = document.getElementById("lang-dropdown");
|
||||
function versionDropdownItem(sitemap, version) {
|
||||
const {defaultPath, langPaths} = sitemap[version];
|
||||
|
||||
// versions, linking to the current lang if possible
|
||||
for (const version of Object.keys(sitemap).sort().reverse()) {
|
||||
let {defaultPath, langPaths} = sitemap[version];
|
||||
|
||||
// link to the current language if available, else link to the default language
|
||||
let path;
|
||||
if (langPaths.hasOwnProperty(LANG)) {
|
||||
path = langPaths[LANG];
|
||||
} else {
|
||||
path = defaultPath;
|
||||
}
|
||||
|
||||
let item = dropdownItem(version, ROOT_URL + path);
|
||||
versionDropdown.appendChild(item);
|
||||
// link to the current language if available, else link to the default language
|
||||
let path;
|
||||
if (langPaths.hasOwnProperty(LANG)) {
|
||||
path = langPaths[LANG];
|
||||
} else {
|
||||
path = defaultPath;
|
||||
}
|
||||
|
||||
// langs for the current version
|
||||
let langPaths = sitemap[VERSION].langPaths;
|
||||
for (const lang of Object.keys(langPaths).sort()) {
|
||||
let item = dropdownItem(lang, ROOT_URL + langPaths[lang]);
|
||||
langDropdown.appendChild(item);
|
||||
}
|
||||
return dropdownItem(version, ROOT_URL + path);
|
||||
}
|
||||
|
||||
function versionDropdownItems(sitemap, versions) {
|
||||
return versions.map((version) => (
|
||||
versionDropdownItem(sitemap, version)
|
||||
));
|
||||
}
|
||||
|
||||
function dropdownSeparator() {
|
||||
let li = document.createElement("li");
|
||||
li.className = "divider";
|
||||
li.setAttribute("role", "separator");
|
||||
return li;
|
||||
}
|
||||
|
||||
// Like array.filter(predicate), but also returns the items which didn't match the filter.
|
||||
function partition(array, predicate) {
|
||||
let matched = [];
|
||||
let unmatched = [];
|
||||
|
||||
array.forEach((value, index) => {
|
||||
if (predicate(value, index, array)) {
|
||||
matched.push(value);
|
||||
} else {
|
||||
unmatched.push(value);
|
||||
}
|
||||
});
|
||||
|
||||
return [matched, unmatched];
|
||||
}
|
||||
|
||||
function sortSitemapVersions(sitemap) {
|
||||
let [versions, branches] = partition(Object.keys(sitemap), (v) => semver.valid(v) != null);
|
||||
|
||||
// branches ascending, versions descending
|
||||
// eg. ["dev", "main"], ["0.10.0", "0.9.0"]
|
||||
branches.sort();
|
||||
versions.sort(semver.rcompare);
|
||||
|
||||
return [branches, versions];
|
||||
}
|
||||
|
||||
// Fills the version dropdown menus and the "old version" message.
|
||||
function addDropdowns(sitemap) {
|
||||
let [branches, versions] = sortSitemapVersions(sitemap);
|
||||
|
||||
// versions
|
||||
document.getElementById("version-dropdown").append(
|
||||
...versionDropdownItems(sitemap, branches),
|
||||
dropdownSeparator(),
|
||||
...versionDropdownItems(sitemap, versions),
|
||||
);
|
||||
|
||||
// languages for the current version
|
||||
const langPaths = sitemap[VERSION].langPaths;
|
||||
const langs = Object.keys(langPaths).sort();
|
||||
|
||||
document.getElementById("lang-dropdown").append(
|
||||
...langs.map((lang) => dropdownItem(lang, ROOT_URL + langPaths[lang])),
|
||||
);
|
||||
|
||||
// return sitemap for chaining, i guess
|
||||
return sitemap
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
// fetch the sitemap from the root and use it to generate the navbar
|
||||
fetch(`${ROOT_URL}/meta/sitemap.json`)
|
||||
.then(r => r.json())
|
||||
.then(fillDropdowns)
|
||||
.then(addDropdowns)
|
||||
.catch(e => console.error(e))
|
||||
|
||||
document.querySelectorAll("details.spell-collapsible").forEach(hookLoad);
|
||||
|
|
|
@ -1,22 +1,28 @@
|
|||
import json
|
||||
import shutil
|
||||
from argparse import ArgumentParser
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
from typing import Self, Sequence, TypedDict
|
||||
from typing import Self, Sequence
|
||||
|
||||
from pydantic import Field, TypeAdapter
|
||||
|
||||
from hexdoc.hexdoc import MARKER_NAME, SitemapMarker
|
||||
from hexdoc.utils import HexdocModel
|
||||
from hexdoc.utils.model import DEFAULT_CONFIG
|
||||
from hexdoc.utils.path import write_to_path
|
||||
|
||||
|
||||
class SitemapItem(TypedDict):
|
||||
defaultPath: str
|
||||
langPaths: dict[str, str]
|
||||
class SitemapItem(HexdocModel):
|
||||
default_path: str = Field(alias="defaultPath", default="")
|
||||
lang_paths: dict[str, str] = Field(alias="langPaths", default_factory=dict)
|
||||
|
||||
def add_marker(self, marker: SitemapMarker):
|
||||
self.lang_paths[marker.lang] = marker.path
|
||||
if marker.is_default_lang:
|
||||
self.default_path = marker.path
|
||||
|
||||
|
||||
def strip_empty_lines(text: str) -> str:
|
||||
return "\n".join(s for s in text.splitlines() if s.strip())
|
||||
Sitemap = dict[str, SitemapItem]
|
||||
|
||||
|
||||
# CLI arguments
|
||||
|
@ -70,19 +76,17 @@ def main():
|
|||
shutil.copytree(args.src, args.dst, dirs_exist_ok=True)
|
||||
|
||||
# crawl the new tree to rebuild the sitemap
|
||||
sitemap = defaultdict[str, SitemapItem](
|
||||
lambda: SitemapItem(defaultPath="", langPaths={})
|
||||
)
|
||||
|
||||
sitemap: Sitemap = defaultdict(SitemapItem)
|
||||
for marker_path in args.dst.rglob(MARKER_NAME):
|
||||
marker = SitemapMarker.load(marker_path)
|
||||
version_item = sitemap[marker.version]
|
||||
sitemap[marker.version].add_marker(marker)
|
||||
|
||||
version_item["langPaths"][marker.lang] = marker.path
|
||||
if marker.is_default_lang:
|
||||
version_item["defaultPath"] = marker.path
|
||||
|
||||
write_to_path(args.dst / "meta" / "sitemap.json", json.dumps(sitemap))
|
||||
# dump the sitemap using a TypeAdapter so it serializes the items properly
|
||||
ta = TypeAdapter(Sitemap, config=DEFAULT_CONFIG)
|
||||
write_to_path(
|
||||
args.dst / "meta" / "sitemap.json",
|
||||
ta.dump_json(sitemap, by_alias=True),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
Loading…
Reference in a new issue