Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,6 @@ jobs:
- name: Run repository checks
if: always()
run: pre-commit run --all-files --show-diff-on-failure
- name: Check with mypy
if: always()
run: hatch run types:check

package:
runs-on: ubuntu-latest
Expand Down
9 changes: 8 additions & 1 deletion mkdocs/commands/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
get_files,
set_exclusions,
)
from mkdocs.structure.nav import Navigation, get_navigation
from mkdocs.structure.nav import (
Navigation,
_set_section_titles_from_index_pages,
get_navigation,
)
from mkdocs.structure.pages import Page
from mkdocs.utils import DuplicateFilter # noqa: F401 - legacy re-export
from mkdocs.utils import templates
Expand Down Expand Up @@ -351,6 +355,9 @@ def build(
+ "\n - ".join(excluded)
)

# Update auto-generated section titles from index page titles.
_set_section_titles_from_index_pages(nav.items)

# Run `env` plugin events.
env = config.plugins.on_env(env, config=config, files=files)

Expand Down
25 changes: 24 additions & 1 deletion mkdocs/structure/nav.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ def _get_by_type(nav, t: type[T]) -> list[T]:

def _add_parent_links(nav) -> None:
for item in nav:
if item.is_section:
if isinstance(item, Section):
for child in item.children:
child.parent = item
_add_parent_links(item.children)
Expand All @@ -265,3 +265,26 @@ def _add_previous_and_next_links(pages: list[Page]) -> None:
zipped = zip(bookended[:-2], pages, bookended[2:])
for page0, page1, page2 in zipped:
page1.previous_page, page1.next_page = page0, page2


def _set_section_titles_from_index_pages(items: list[StructureItem]) -> None:
"""
For auto-generated navigation, update section titles to use the index
page's title instead of the directory name.

When `nav` is not explicitly configured, MkDocs generates section names
from directory names (e.g. "about" for an "about/" directory). If the
section contains an index page (e.g. "about/index.md"), this function
uses that page's title as the section title instead.

This only applies when `page.title` is not None (i.e. the page has
been read/rendered, so its title is known from metadata or headings).
"""
for item in items:
if not isinstance(item, Section):
continue
for child in item.children:
if isinstance(child, Page) and child.is_index and child.title is not None:
item.title = child.title
break
_set_section_titles_from_index_pages(item.children)
37 changes: 36 additions & 1 deletion mkdocs/tests/structure/nav_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
import unittest

from mkdocs.structure.files import File, Files, set_exclusions
from mkdocs.structure.nav import Section, _get_by_type, get_navigation
from mkdocs.structure.nav import (
Section,
_get_by_type,
_set_section_titles_from_index_pages,
get_navigation,
)
from mkdocs.structure.pages import Page
from mkdocs.tests.base import dedent, load_config

Expand Down Expand Up @@ -608,3 +613,33 @@ def test_get_by_type_nested_sections(self):
files = Files(fs)
site_navigation = get_navigation(files, cfg)
self.assertEqual(len(_get_by_type(site_navigation, Section)), 2)

def test_smart_section_titles_from_index_pages(self):
"""Section titles use index page titles instead of directory names."""
cfg = load_config(site_url="http://example.com/")
fs = [
"index.md",
"about/index.md",
"about/license.md",
"api-guide/index.md",
"api-guide/running.md",
]
files = Files(
[File(s, cfg.docs_dir, cfg.site_dir, cfg.use_directory_urls) for s in fs]
)
site_navigation = get_navigation(files, cfg)

# Before update: sections use directory names
about_section = site_navigation.items[1]
api_section = site_navigation.items[2]
self.assertEqual(about_section.title, "About")
self.assertEqual(api_section.title, "Api guide")

# Set titles on index pages (as if they were read/rendered)
about_section.children[0].title = "About This Project"
api_section.children[0].title = "API Reference"

_set_section_titles_from_index_pages(site_navigation.items)

self.assertEqual(about_section.title, "About This Project")
self.assertEqual(api_section.title, "API Reference")
Loading