fix: respect navigation title precedence (#906)

Signed-off-by: squidfunk <martin.donath@squidfunk.com>
This commit is contained in:
squidfunk
2026-09-03 12:24:56 +02:00
parent d7a5d384ef
commit 05f297e530
7 changed files with 237 additions and 33 deletions
+65 -1
View File
@@ -52,7 +52,7 @@ def _write_template(root: Path) -> None:
{% macro render(items, depth) %}
{% for item in items %}
<item depth="{{ depth }}" title="{{ item.title or '' }}"
url="{{ item.url or '' }}" />
url="{{ item.url or '' }}" index="{{ item.is_index }}" />
{{ render(item.children, depth + 1) }}
{% endfor %}
{% endmacro %}
@@ -81,6 +81,17 @@ def _items_or_none(root: Path) -> list[tuple[int, str, str]] | None:
return None
def _index_flags(root: Path) -> list[bool]:
"""Extract whether each normalized navigation item is an index page."""
output_path = root / "site" / "index.html"
if not output_path.exists():
output_path = next((root / "site").rglob("*.html"))
soup = BeautifulSoup(output_path.read_text(), "html.parser")
return [
str(item["index"]).lower() == "true" for item in soup.find_all("item")
]
def _write_config(root: Path, plugin: str = "awesome-nav") -> Path:
config = root / "mkdocs.yml"
config.write_text(
@@ -218,6 +229,59 @@ def test_default_navigation_prefers_index_over_readme(tmp_path: Path) -> None:
]
def test_nested_index_is_classified_for_theme_section_merging(
tmp_path: Path,
) -> None:
"""Nested index paths retain the index marker used by Material's theme."""
docs = tmp_path / "docs"
section = docs / "tech-stack"
section.mkdir(parents=True)
_write_template(tmp_path)
(section / "index.md").write_text(
"# Tech-Stack Home Page Title\n", encoding="utf-8"
)
(section / "page.md").write_text("# Page\n", encoding="utf-8")
(section / ".nav.yaml").write_text(
"title: Tech-Stack\nnav: ['*']\n", encoding="utf-8"
)
zensical.build(
str(_write_config(tmp_path, "awesome-nav:\n filename: .nav.yaml")),
_BUILD_OPTIONS,
)
assert _items(tmp_path) == [
(0, "Tech-Stack", ""),
(1, "Tech-Stack Home Page Title", "tech-stack/"),
(1, "Page", "tech-stack/page/"),
]
assert _index_flags(tmp_path) == [False, True, False]
def test_explicit_page_title_precedes_metadata_and_heading(
tmp_path: Path,
) -> None:
"""Awesome Nav titles become MkDocs-compatible page titles."""
docs = tmp_path / "docs"
docs.mkdir()
overrides = tmp_path / "overrides"
overrides.mkdir()
(overrides / "main.html").write_text(
"{{ page.title }}", encoding="utf-8"
)
(docs / "index.md").write_text(
"---\ntitle: Metadata title\n---\n\n# Heading title\n",
encoding="utf-8",
)
(docs / ".nav.yml").write_text(
"nav:\n - Configured title: index.md\n", encoding="utf-8"
)
zensical.build(str(_write_config(tmp_path)), _BUILD_OPTIONS)
assert (tmp_path / "site" / "index.html").read_text() == "Configured title"
def test_pattern_options_hide_directories_flatten_and_sort_by_metadata(
tmp_path: Path,
) -> None:
+22
View File
@@ -129,6 +129,28 @@ def test_symlinked_config_anchors_relative_paths_to_its_target(
assert not (alias_dir / "site").exists()
def test_navigation_title_precedes_metadata_and_heading(tmp_path: Path) -> None:
"""Configured titles have the same highest precedence as in MkDocs."""
config = _make_yml_project(
tmp_path,
yml_extra=(
" custom_dir: overrides\n"
"nav:\n"
" - Configured title: index.md"
),
)
(tmp_path / "docs" / "index.md").write_text(
"---\ntitle: Metadata title\n---\n\n# Heading title\n",
encoding="utf-8",
)
custom = _make_custom_dir(tmp_path)
(custom / "main.html").write_text("{{ page.title }}", encoding="utf-8")
_build(config)
assert (tmp_path / "site" / "index.html").read_text() == "Configured title"
# ---------------------------------------------------------------------------
# Theme loading: both zensical.toml and mkdocs.yml
# ---------------------------------------------------------------------------
+6 -6
View File
@@ -112,7 +112,7 @@ def test_search_artifacts_match_mkdocs_contract(tmp_path: Path) -> None:
"level": 1,
"title": "Landing",
"text": "<p>Intro with <small>fine print</small>.</p>",
"path": ["Landing"],
"path": ["Home"],
"tags": ["alpha", "beta"],
},
{
@@ -120,15 +120,15 @@ def test_search_artifacts_match_mkdocs_contract(tmp_path: Path) -> None:
"level": 2,
"title": "Overview",
"text": "<p>Overview body.</p>",
"path": ["Landing"],
"path": ["Home"],
"tags": ["alpha", "beta"],
},
{
"location": "guide/topic.html",
"level": 1,
"title": "Metadata title",
"title": "Topic",
"text": "<p>Preface before a heading.</p>",
"path": ["Guides", "Metadata title"],
"path": ["Guides", "Topic"],
"tags": ["guide"],
},
{
@@ -136,7 +136,7 @@ def test_search_artifacts_match_mkdocs_contract(tmp_path: Path) -> None:
"level": 2,
"title": "Details",
"text": "<p>Detailed body.</p>",
"path": ["Guides", "Metadata title"],
"path": ["Guides", "Topic"],
"tags": ["guide"],
},
],
@@ -234,7 +234,7 @@ def test_search_rebuild_replaces_changed_and_removed_pages(
"level": 1,
"title": "Changed",
"text": "<p>Fresh body.</p>",
"path": ["Changed"],
"path": ["Home"],
"tags": [],
}
]