An awesome theme for the Sphinx documentation generator with enhanced features, custom code highlighting, and modern responsive design
Comprehensive HTML modification pipeline that enhances the generated Sphinx HTML with interactive features, improved navigation, accessibility enhancements, and modern web behaviors using BeautifulSoup for precise DOM manipulation.
Track which documents have changed to optimize post-processing.
def changed_docs(app: Sphinx, env: BuildEnvironment, docnames: list[str]) -> None:
"""
Add a list of changed docs to the environment.
This is useful to make sure postprocessing only runs on changed files,
improving build performance by avoiding unnecessary HTML modifications.
Parameters:
- app (Sphinx): The Sphinx application instance
- env (BuildEnvironment): The Sphinx build environment
- docnames (list[str]): List of document names that have changed
"""Utility function for finding HTML files in the output directory.
def get_html_files(outdir: pathlib.Path | str) -> list[str]:
"""
Get a list of HTML files in the output directory.
Recursively searches the output directory for all files with .html extension.
Parameters:
- outdir (pathlib.Path | str): Output directory to search
Returns:
list[str]: List of HTML file paths
"""Core function that orchestrates the HTML enhancement process for all changed documents.
def post_process_html(app: Sphinx, exc: Exception | None) -> None:
"""
Modify the HTML after building.
Makes changes that are easier to do in the final HTML rather than
the tree of nodes. Only processes files that have changed.
Parameters:
- app (Sphinx): The Sphinx application instance
- exc (Exception | None): Build exception if any occurred
"""Core HTML document modification function that applies all enhancements.
def modify_html(html_filename: str, app: Sphinx) -> None:
"""
Modify a single HTML document.
1. Parse the HTML document into a BeautifulSoup tree
2. Apply modifications in order and in place
3. Write the modified HTML back to the file
Parameters:
- html_filename (str): Path to the HTML file to modify
- app (Sphinx): The Sphinx application instance
"""Transform static navigation into interactive, collapsible navigation with Alpine.js directives.
def collapsible_nav(tree: BeautifulSoup) -> None:
"""
Make navigation links with children collapsible.
Adds Alpine.js directives for interactive behavior:
- x-data for state management
- @click for toggle behavior
- x-show for visibility control
- :class for dynamic styling
Parameters:
- tree (BeautifulSoup): The parsed HTML document tree
"""Transform header links into clipboard-copy functionality with user feedback.
def headerlinks(tree: BeautifulSoup) -> None:
"""
Make headerlinks copy their URL on click.
Adds Alpine.js click handler that:
- Copies the link URL to clipboard
- Shows "Copied!" feedback message
- Resets to original message after 2 seconds
Parameters:
- tree (BeautifulSoup): The parsed HTML document tree
"""Add scroll-based navigation highlighting for table of contents.
def scrollspy(tree: BeautifulSoup) -> None:
"""
Add an active class to current TOC links in the right sidebar.
Uses Alpine.js intersection observer to:
- Track which section is currently visible
- Update activeSection variable
- Apply data-current attribute to matching TOC links
Parameters:
- tree (BeautifulSoup): The parsed HTML document tree
"""Enhance external links with security attributes and visual indicators.
def external_links(tree: BeautifulSoup) -> None:
"""
Add rel="nofollow noopener" to external links and append icons.
Enhances security by:
- Adding rel attributes to prevent page hijacking
- Appending visual icons to identify external links
Parameters:
- tree (BeautifulSoup): The parsed HTML document tree
"""Remove unnecessary elements and optimize HTML structure.
def remove_empty_toctree(tree: BeautifulSoup) -> None:
"""
Remove empty toctree divs.
If you include a toctree with the hidden option, an empty div is
inserted. This function removes these empty divs that contain only
whitespace characters.
Parameters:
- tree (BeautifulSoup): The parsed HTML document tree
"""
def strip_comments(tree: BeautifulSoup) -> None:
"""
Remove HTML comments from documents.
Cleans up the final HTML by removing all HTML comment nodes,
reducing file size and eliminating unnecessary markup.
Parameters:
- tree (BeautifulSoup): The parsed HTML document tree
"""Pre-defined SVG icons used throughout the post-processing pipeline.
@dataclass(frozen=True)
class Icons:
"""Icons from Material Design as SVG strings."""
external_link: str = '<svg xmlns="http://www.w3.org/2000/svg"...'>
"""External link icon SVG"""
chevron_right: str = '<svg xmlns="http://www.w3.org/2000/svg"...'>
"""Right chevron icon for navigation"""
permalinks_icon: str = '<svg xmlns="http://www.w3.org/2000/svg"...'>
"""Permalink icon for header links"""The post-processing pipeline applies modifications in this order:
Enable post-processing features through theme options:
html_theme_options = {
"awesome_external_links": True, # Enable external link enhancement
"awesome_headerlinks": True, # Enable header link clipboard copy
}The post-processing system heavily integrates with Alpine.js for reactive behavior:
<!-- Navigation state management -->
<li x-data="{ expanded: $el.classList.contains('current') ? true : false }">
<a @click="expanded = !expanded" :class="{ 'expanded' : expanded }">...</a>
<ul x-show="expanded">...</ul>
</li>
<!-- Scroll spy tracking -->
<h2 x-intersect.margin.0%.0%.-70%.0%="activeSection = '#section-id'">...</h2>
<a :data-current="activeSection === '#section-id'">...</a>
<!-- Clipboard copy -->
<a @click.prevent="navigator.clipboard.writeText($el.href)">...</a>The post-processing enhancements use modern web APIs:
Graceful degradation is provided for older browsers.
Install with Tessl CLI
npx tessl i tessl/pypi-sphinxawesome-theme