-
-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to generate a full-site Table of Contents when using aggregator. #46
Comments
I finally managed to create an MkDocs hook to create a table of contents and properly insert it into the site pages in a way that it is included in the aggregation. However, doing so exposed another missing feature. import markdown
from bs4 import BeautifulSoup
from mkdocs.structure.nav import get_navigation, Section
from mkdocs.config import Config
from mkdocs.structure.pages import Page
from mkdocs.structure.files import Files, File, InclusionLevel
def _get_page_toc(page: Page) -> str:
'''
Generate the HTML unordered list part of the Table of Contents for `page`.
Args:
page (Page): The page to create a Table of Contents from
Returns:
str: An HTML unordered list
'''
content = ''
url = page.file.abs_src_path
with open(url, 'r') as file:
# render markdown file
page_toc = markdown.Markdown(extensions=['toc', 'fenced_code', 'md_in_html', 'attr_list', 'meta'])
page_toc.convert(file.read())
content = page_toc.toc
# add page path to anchor links
content = content.replace('="#', '="' + page.file.dest_path + '#')
# extract only the unordered list
soup = BeautifulSoup(content, 'html.parser')
content = str(soup.find('ul'))
return content
def _nav_to_html(nav_items: list) -> str:
'''
Converts the MkDocs Navigation.items into an HTML string
Args:
nav_items (list): The contents of the `items` property of a Navigation object.
Returns:
str: A representation of the Navigation as an HTML string
'''
content = []
for item in nav_items:
if isinstance(item, Page):
if item.markdown is None:
item.markdown = ''
title = item.title
if title is not None:
content.append('<li><a href="' + item.url + '">' + title + '</a>')
content.append(_get_page_toc(item))
content.append('</li>')
if isinstance(item, Section):
content.append('<li>')
if isinstance(item.title, str):
content.append(item.title.capitalize())
content.append(_nav_to_html(item.children))
content.append('</li>')
content.insert(0, '<ul>')
content.append('</ul>')
return '\n'.join(content)
def on_files(files: Files, config: Config):
'''
Invoked when files are ready to be manipulated.
Args:
files (Files): The collection of files.
config (Config): The site configuration.
Returns:
Files: The files collection
'''
nav = get_navigation(files, config)
content = '<div class="toc"><span class="toctitle site_toc">Table of Contents</span>' + \
_nav_to_html(nav.items) + \
'</div>'
# Create a virtual file from generated text
file = File.generated(config, 'generated_site_toc.md', content=content, inclusion=InclusionLevel.INCLUDED)
# Add the virtual file to the site files
files.append(file)
# Add the virtual file to the site navigation with empty text for the title to hide it when viewing the website.
config.nav.insert(0, {'': 'generated_site_toc.md'})
return files |
The Python Markdown TOC plugin works well for individual pages, but is there a good way to add a full TOC after the first cover page that would list the entire site when using the aggregator? All other PDF generators I've tried for Material have included TOCs by default, but yours is easier to use and install while also actual supporting Javascript.
Potential Alternative Solutions:
Use another plugin to concatenate the entire site into one page instead of using the aggregator option. This seems part overkill and makes several nice features of your solution unusable (like page specific cover pages).The plugin I was considering isn't compatible with exporter and so would also need to be a custom hook...The text was updated successfully, but these errors were encountered: