lukasgeiter / mkdocs-awesome-pages-plugin

An MkDocs plugin that simplifies configuring page titles and their order
MIT License
453 stars 35 forks source link

Idea: Option to generate TOC in pages using placeholder? #39

Closed Andre601 closed 3 years ago

Andre601 commented 3 years ago

Not sure if this would be either out of scope, or even impossible to implement, but how about having a way to generate a TOC inside a page, by using a specific placeholder for it?

Example

The following structure is present:

docs/
├ index.md
├ assets/
│  ├ css/ # Some CSS assets
│  │  └ ...
│  └ img/ # Some images
│     └ ...
└ posts/
   ├ index.md # Content shown below
   ├ post1.md
   ├ post2.md
   └ archive/
      └ post3.md

I now set up a .pages.yml file in assets to ignore the folder and one in posts with the following structure:

title: Posts
nav:
- My Posts: index.md
- ...

Finally, do I add the following to my index.md:

# My Posts
Below can you find a list of all posts I made so far.

## Pages
{nav} <!-- Just an example. Not sure how the placeholder should look like -->

The {nav} placeholder would now take all pages it can find in the posts directory and also go through any additional directories found there. It will however skip the file it is used in.

Once it has all pages, will it generate a list that could look like this:

# My Posts
Below can you find a list of all posts I made so far.

## Pages
- [Post1](post1.md)
- [Post2](post2.md)
- [Archived](archive)
  - [Post3](archive/post3.md)

It would take the names to display from either the nav-section in the .pages file, or from the pages themself.

Why?

This plugin is useful for when you want to have the nav updated without needing to always set it yourself, but won't obviously work for when you have a manual nav inside a specific file.

For me is that the case with a blog I have. While I no longer need to update the nav myself do I always have to update the list in the index.md of my posts directory, which is frustrating sometimes.

Having a way to automate this using a placeholder or similar would really help a lot.

I hope this is somewhat doable.

lukasgeiter commented 3 years ago

That's an interesting idea. However, I think it is indeed outside of the scope of this plugin. The good news is that since awesome-pages simply modifies the existing MkDocs nav structure, building a new plugin on top of it shouldn't be too hard. In fact I already put together a little prototype which seems to work quite well:

from mkdocs.plugins import BasePlugin
from mkdocs.utils import normalize_url

class InlineNavigationPlugin(BasePlugin):

    def on_nav(self, nav, config, files):
        self.nav = nav

    def on_post_page(self, output, page, config):
        if '{nav}' in output:
            children = page.parent.children if page.parent else self.nav.items
            siblings = [child for child in children if child != page]
            return output.replace('{nav}', self._format_links(siblings, page, config))

    def _format_links(self, items, page, config):
        result = '<ul>'

        for item in items:
            result += '<li>'

            if item.is_section:
                result += item.title
                result += self._format_links(item.children, page, config)
            else:
                url = normalize_url(item.url, page)
                result += f'<a href="{url}">{item.title}</a>'

            result += '</li>'

        result += '</ul>'

        return result

I won't be publishing this as a package - I've already got enough on my hands. But feel free to use the code, modify it or even publish it as a plugin yourself. Refer to the MkDocs documentation on developing plugins.

Andre601 commented 3 years ago

Okay thanks.

What would be the easiest setup to import this using pip? I recall pip having a git+ option to directly retrieve the data from a Git repository if I understood it correctly. But I'm not 100% sure what the required info is for everything to work.

I quickly created a github repository with some basic setup: https://github.com/Andre601/mkdocs-pagenav-generator

lukasgeiter commented 3 years ago

Yeah you should be able to just install from a git repo:

pip install git+https://github.com/Andre601/mkdocs-pagenav-generator.git
Andre601 commented 3 years ago

Seems to not work. I get the error that "pagenav-generator" isn't installed.

The setup.py should be correct as aI have a pagenav-generator = mkdocs_pagenav_generator.plugin:NavGeneratorPlugin which does exist in the repository

lukasgeiter commented 3 years ago

You're missing the packages argument in setup.py. For example:

packages=find_packages(exclude=['*.tests', '*.tests.*'])
Andre601 commented 3 years ago

Still not working. Same error: "Config value: 'plugins'. Error: The "pagenav-generator" plugin is not installed"

I did add the packages part: https://github.com/Andre601/mkdocs-pagenav-generator/blob/main/setup.py#L23

lukasgeiter commented 3 years ago

Strange, I get a different error:

ModuleNotFoundError: No module named 'mkdocs_pagenav_generator'

What you're definitely still missing is an empty __init__.py file in the mkdocs_pagenav_generator folder. This marks it as a python module and should fix the error I am seeing.

Andre601 commented 3 years ago

Still getting the same issue. What about you? Also, maybe your mkdocs.yml is different? Or how you download the file? I use a requirements.txt and netlify for build previews

EDIT: I'm dumb! I have a typo. pagenav-generaor instead of pagenav-generator

Andre601 commented 3 years ago

Yes!

The system works! Thank you so much for the assistance here (And the code of course!). It works nicely.

EDIT: Added it to the mkdocs plugins page on their wiki. Of course with proper credit. image

Andre601 commented 3 years ago

One last question: If I want to show a live demo of the plugin alongside the raw doc stuff, how could I exclude the entire docs folder, mkdocs.yml, requirements.txt and .github folder from any download in the setup.py?

I assume I add all the folders and files to the packages=find_packages(exclude=['*.tests', '*.tests.*']) but I'm not sure about the pattern to use here...

lukasgeiter commented 3 years ago

One last question: If I want to show a live demo of the plugin alongside the raw doc stuff, how could I exclude the entire docs folder, mkdocs.yml, requirements.txt and .github folder from any download in the setup.py?

I don't know. All unnecessary files get removed from my package when I publish it to PyPI. No idea how it would work when installing from a git repo.


Another thing: The plugin does not actually depend on awesome-pages. It also works with the navigation that MkDocs produces out of the box.

oprypin commented 3 years ago

FYI https://github.com/oprypin/mkdocs-literate-nav is a more direct approach to this. The end result is the same: you get both an actual nav and also have it displayed as part of the page. The difference is that the approach is opposite: you write the nav as part of the page in the first place.

Andre601 commented 3 years ago

FYI https://github.com/oprypin/mkdocs-literate-nav is a more direct approach to this. The end result is the same: you get both an actual nav and also have it displayed as part of the page. The difference is that the approach is opposite: you write the nav as part of the page in the first place.

Yeah and that's the issue. As soon as I add a new page will I need to add it to the other page. With this can I just add a newpage and done

oprypin commented 3 years ago

If you will never care about the order of those posts, and will not care about browseability of that page on GitHub, sure.