CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-sphinx-book-theme

A clean book theme for scientific explanations and documentation with Sphinx

Overview
Eval results
Files

transforms.mddocs/

Content Transforms

Post-processing transforms that modify document structure after parsing. The primary transform converts footnotes to margin/side notes for enhanced book-style presentation.

Capabilities

Footnote to Sidenote Transform

The main transform class that converts standard footnotes into interactive margin notes.

class HandleFootnoteTransform(SphinxPostTransform):
    """
    Transform footnotes into side/margin notes for book-style presentation.
    
    Converts standard reStructuredText footnotes into interactive
    margin content that appears beside the main text on desktop
    and below on mobile devices.
    """
    
    default_priority: int = 1  # Transform priority
    formats: tuple = ("html",)  # Only applies to HTML output
    
    def run(self, **kwargs: Any) -> None:
        """
        Execute the footnote transformation.
        
        Process:
        1. Check if sidenotes are enabled in theme options
        2. Find all footnote references in the document
        3. Locate corresponding footnote definitions
        4. Convert footnotes to SideNoteNode instances
        5. Handle marginnotes (starting with {-}) differently from sidenotes
        6. Position notes appropriately in document structure
        7. Remove original footnote definitions
        
        Parameters:
        - kwargs: Additional keyword arguments from Sphinx
        """

Compatibility Utilities

Utility functions for cross-version compatibility with docutils.

def findall(node: Element, *args, **kwargs) -> Iterator[Element]:
    """
    Compatibility wrapper for docutils node traversal.
    
    Uses findall() in newer docutils versions, falls back to traverse()
    in older versions.
    
    Parameters:
    - node: Document node to search
    - args: Arguments passed to findall/traverse
    - kwargs: Keyword arguments passed to findall/traverse
    
    Returns:
    Iterator over matching nodes
    """

Usage Examples

Enabling Sidenote Transform

# In Sphinx conf.py
html_theme_options = {
    "use_sidenotes": True  # Enable footnote to sidenote conversion
}

Standard Footnote Usage

In reStructuredText source:

This is regular text with a footnote reference [#note1]_.

This is text with a margin note [#margin1]_.

.. [#note1] This will become a sidenote with a number.

.. [#margin1] {-} This will become a marginnote without a number.

Transform Registration

from sphinx.application import Sphinx
from sphinx_book_theme._transforms import HandleFootnoteTransform

def setup(app: Sphinx):
    # Register the post-transform
    app.add_post_transform(HandleFootnoteTransform)
    
    return {"parallel_read_safe": True}

Custom Transform Implementation

from sphinx_book_theme._transforms import HandleFootnoteTransform
from sphinx_book_theme._compat import findall
from docutils import nodes as docutil_nodes

class CustomFootnoteTransform(HandleFootnoteTransform):
    """Custom footnote transform with additional processing."""
    
    def run(self, **kwargs):
        # Get theme options
        theme_options = get_theme_options_dict(self.app)
        
        if not theme_options.get("use_sidenotes", False):
            return None
            
        # Use compatibility function for node traversal
        for ref_node in findall(self.document, docutil_nodes.footnote_reference):
            # Custom processing logic here
            pass

Manual Node Traversal

from sphinx_book_theme._compat import findall
from docutils import nodes

# Find all emphasis nodes in a document
for emphasis in findall(document, nodes.emphasis):
    print(f"Emphasized text: {emphasis.astext()}")

# Find nodes with specific attributes
for node in findall(document, nodes.paragraph):
    if 'highlight' in node.attributes.get('classes', []):
        print(f"Highlighted paragraph: {node.astext()}")

Transform Behavior

Sidenote Processing

  1. Detection: Finds footnote references like [#note1]_
  2. Matching: Locates corresponding footnote definitions .. [#note1] content
  3. Classification:
    • Regular sidenotes: Show with number
    • Marginnotes: Content starts with {-}, no number shown
  4. Positioning: Places notes adjacent to references in document structure
  5. Nested Handling: Handles footnotes inside containers (admonitions, etc.)

HTML Output Structure

Sidenote Output

<label for='sidenote-role-1' class='margin-toggle'>
  <span class='sidenote'>
    <sup>1</sup>
    Sidenote content here
  </span>
</label>
<input type='checkbox' id='sidenote-role-1' class='margin-toggle'>

Marginnote Output

<label for='marginnote-role-1' class='margin-toggle marginnote-label'>
</label>
<input type='checkbox' id='marginnote-role-1' class='margin-toggle'>

Configuration Options

# Theme options affecting transform behavior
html_theme_options = {
    "use_sidenotes": True,  # Enable/disable the transform
}

Install with Tessl CLI

npx tessl i tessl/pypi-sphinx-book-theme

docs

configuration.md

core-setup.md

directives-nodes.md

header-buttons.md

index.md

page-enhancement.md

transforms.md

tile.json