Optimized subfolders

This commit is contained in:
Kevin Veen-Birkenbach 2025-03-17 01:42:01 +01:00
parent d36fc0c916
commit 5677a91e82
No known key found for this signature in database
GPG Key ID: 44D8F11FD62F878E
2 changed files with 38 additions and 24 deletions

View File

@ -13,7 +13,19 @@
{% if local_md_headings %}
<div class="local-md-headings">
<h3>Overview</h3>
<h3>Current Folder</h3>
{{ render_headings(local_md_headings) }}
</div>
{% endif %}
{% if local_subfolders %}
<div class="local-subfolders">
<h3>Subfolders</h3>
<ul>
{% for item in local_subfolders %}
<li><a href="{{ pathto(item.link) }}">{{ item.text }}</a></li>
{% endfor %}
</ul>
</div>
{% endif %}

View File

@ -1,7 +1,6 @@
import os
import re
from sphinx.util import logging
from docutils.parsers.rst import Directive
from .nav_utils import natural_sort_key, extract_headings_from_file, group_headings, sort_tree, MAX_HEADING_LEVEL, DEFAULT_MAX_NAV_DEPTH
logger = logging.getLogger(__name__)
@ -9,9 +8,11 @@ logger = logging.getLogger(__name__)
def collect_subfolder_tree(dir_path, base_url, current_depth, max_depth):
"""
Recursively collects navigation items from subdirectories.
For each subfolder, it looks for a candidate file (prefer "index.rst" then "README.md")
and extracts its first level1 heading as the title. If no candidate or heading is found,
the folder name is used.
For each subfolder, it looks for a candidate file (prefer "index.rst" then "README.md").
Only subfolders with such a file will be included.
If a candidate is found, the first level1 heading from that file is used as the title;
if no heading is found, the folder name is used.
The link is built pointing directly to the candidate file (by its base name) rather than the folder.
Returns a list representing the subfolder tree.
"""
items = []
@ -24,32 +25,34 @@ def collect_subfolder_tree(dir_path, base_url, current_depth, max_depth):
if os.path.isfile(candidate_path):
candidate = candidate_path
break
# Only include the folder if a candidate file was found.
if candidate:
headings = extract_headings_from_file(candidate, max_level=MAX_HEADING_LEVEL)
title = headings[0]['text'] if headings else item
else:
title = item
link = os.path.join(base_url, item)
entry = {
'level': 1,
'text': title,
'link': link,
'anchor': '',
'priority': 0,
'filename': item
}
if current_depth < max_depth:
children = collect_subfolder_tree(full_path, os.path.join(base_url, item), current_depth + 1, max_depth)
if children:
entry['children'] = children
items.append(entry)
# Use the candidate file's base name as link target.
candidate_base = os.path.splitext(os.path.basename(candidate))[0]
link = os.path.join(base_url, item, candidate_base)
entry = {
'level': 1,
'text': title,
'link': link,
'anchor': '',
'priority': 0,
'filename': item
}
if current_depth < max_depth:
children = collect_subfolder_tree(full_path, os.path.join(base_url, item), current_depth + 1, max_depth)
if children:
entry['children'] = children
items.append(entry)
return items
def add_local_subfolders(app, pagename, templatename, context, doctree):
"""
Collects a tree of subfolder navigation items from the current directory.
For each subfolder, the title is determined by scanning for a candidate file (prefer "index.rst" then "README.md")
and extracting its first level1 heading, or using the folder name if none is found.
For each subfolder, the title is determined by scanning for a candidate file
(prefer "index.rst" then "README.md") and extracting its first level1 heading,
or using the folder name if none is found.
The resulting tree is stored in context['local_subfolders'].
"""
srcdir = app.srcdir
@ -66,6 +69,5 @@ def add_local_subfolders(app, pagename, templatename, context, doctree):
context['local_subfolders'] = subfolder_tree
def setup(app):
# Do not add the config value here to avoid conflicts.
app.connect('html-page-context', add_local_subfolders)
return {'version': '0.1', 'parallel_read_safe': True}