A clean book theme for scientific explanations and documentation with Sphinx
Custom reStructuredText directives and docutils nodes for enhanced content presentation. Provides margin notes and sidenote functionality for book-style layouts.
A custom reStructuredText directive for creating content that appears in the page margin.
class Margin(Sidebar):
"""
Directive for content that appears in the right margin of the page.
Inherits from docutils Sidebar directive with custom styling.
"""
optional_arguments: int = 1 # Optional title argument
required_arguments: int = 0 # No required arguments
def run(self) -> list:
"""
Process the directive and return docutils nodes.
Returns:
List of docutils nodes with 'margin' CSS class applied
"""A custom docutils node for rendering side notes and margin notes in HTML output.
class SideNoteNode(nodes.Element):
"""
Custom docutils node for side/margin note content in HTML output.
Generates required HTML structure for both desktop and mobile
presentation of marginal content.
"""
def __init__(self, rawsource="", *children, **attributes):
"""
Initialize the SideNoteNode.
Parameters:
- rawsource: Raw source text (optional)
- children: Child nodes
- attributes: Node attributes
"""
@classmethod
def add_node(cls, app: Sphinx) -> None:
"""
Register the node with a Sphinx application.
Parameters:
- app: Sphinx application instance
"""HTML rendering functions for the SideNoteNode.
def visit_SideNoteNode(self, node):
"""
HTML visitor function called when entering a SideNoteNode.
Generates opening HTML tags based on node type:
- For marginnotes: Creates marginnote-label class
- For sidenotes: Creates label with span wrapper
Parameters:
- self: HTML writer instance
- node: SideNoteNode being processed with 'names' attribute
"""
def depart_SideNoteNode(self, node):
"""
HTML visitor function called when leaving a SideNoteNode.
Generates closing HTML tags and interactive checkbox input:
- Closes span tags for sidenotes
- Adds checkbox input for toggle behavior
- Uses node names for element IDs
Parameters:
- self: HTML writer instance
- node: SideNoteNode being processed with 'names' attribute
"""In reStructuredText content:
Regular paragraph content here.
.. margin:: Optional Title
This content will appear in the right margin alongside the
regular content. It's perfect for side notes, additional
information, or commentary.
More regular content continues here.from sphinx_book_theme.nodes import SideNoteNode
from docutils import nodes
# Create a sidenote node
sidenote = SideNoteNode()
sidenote.attributes["names"] = ["sidenote-role-1"]
# Add content to the sidenote
content = nodes.inline()
content.attributes["classes"] = ["sidenote"]
content += nodes.Text("This is a side note.")
sidenote.append(content)from sphinx.application import Sphinx
from sphinx_book_theme.nodes import SideNoteNode
# In a Sphinx extension setup function
def setup(app: Sphinx):
# Register the custom node
SideNoteNode.add_node(app)
return {"parallel_read_safe": True}from sphinx.application import Sphinx
from sphinx_book_theme.directives import Margin
# Register the directive
def setup(app: Sphinx):
app.add_directive("margin", Margin)
return {"parallel_read_safe": True}<label for='sidenote-role-1' class='margin-toggle'>
<span>Sidenote content with number</span>
</label>
<input type='checkbox' id='sidenote-role-1' name='sidenote-role-1' class='margin-toggle'><label for='marginnote-role-1' class='margin-toggle marginnote-label'>
</label>
<input type='checkbox' id='marginnote-role-1' name='marginnote-role-1' class='margin-toggle'>Install with Tessl CLI
npx tessl i tessl/pypi-sphinx-book-theme