pydata / pydata-sphinx-theme

A clean, three-column Sphinx theme with Bootstrap for the PyData community
https://pydata-sphinx-theme.readthedocs.io
BSD 3-Clause "New" or "Revised" License
623 stars 322 forks source link

Generate a single sidebar HTML file and insert it into each page in an iframe #762

Open gilbertbw opened 2 years ago

gilbertbw commented 2 years ago

As requested by @choldgraf here https://github.com/pydata/pydata-sphinx-theme/issues/364#issuecomment-1167171565 I have pulled this comment https://github.com/pydata/pydata-sphinx-theme/issues/364#issuecomment-1167151422 out into its own issue and clarified the proposal.


We are looking to use sphinx-book-theme to document our product, moving from a .chm file produced using Help and Manual. sphinx-book-theme is based off of pydata-sphinx-theme.

We have two issues with inserting the sidebar into every page:

  1. It takes a long time, increasing the build time of our help from 2 minutes with alabaster, to 10 minutes with sphinx-book-theme
  2. It increases the build size massively. In our project each page ends up around 0.25 MB. This is with around 1500 help topics. The whole help ends up around 380 MB, compared to around 3 MB for the .chm file this is replacing.

I have been discussing this on the sphinx-book-theme repo here https://github.com/executablebooks/sphinx-book-theme/issues/561

Current Workaround

These issues seem to be reported by many users, currently the recommendation, here, is to reduce the number of pages in the sidebar. This is not a good solution for us, as want the UX of being able to browse through the tree before moving page.

Proposal

Looking into this, I have come up with the following proposal (first discussed here https://github.com/executablebooks/sphinx-book-theme/issues/561#issuecomment-1165438532):

Support outputting the sidebar once, into its own file, then including the sidebar with an <iframe/> in each page.

To still show the relevant subsection of the tree on each page, without javascript:

  1. update generate_nav_tree https://github.com/pydata/pydata-sphinx-theme/blob/26554f2bceb856c78a22e00677892a3d58ceb201/src/pydata_sphinx_theme/__init__.py#L155 to optionally write unique classes for each page <li> in the tree.
  2. add a new toctree function to write out the <style>...</style> to show the current page.
  3. Maybe add helpers to add the <iframe>? Not sure if the implementer of the theme should be responsible for this?
  4. Maybe add documentation about using this alternative method for the sidebar? I am not sure you would want to make this the default?

I want to discuss how these changed would be received, before I open a PR.

Example

With a tree like this, where the class is on the <li>

on the page Top 1 add

<style>
#site-navigation .t1>a { color: rgba(var(--pst-color-link),1); }
#site-navigation .t1>ul { display:block; }
</style>

or on Top 2 Child 3 Child 2 add

<style>
#site-navigation .t2>a { color: rgba(var(--pst-color-link),1); }
#site-navigation .t2>ul { display:block; }

#site-navigation .t2c3>a { color: rgba(var(--pst-color-link),1); }
#site-navigation .t2c3>ul { display:block; }

#site-navigation .t2c3c3>a { color: rgba(var(--pst-color-link),1); }
</style>

e.t.c.

choldgraf commented 2 years ago

I think a challenge that you're going to run into here is that the relative links will change for each page (Sphinx makes all of its cross-reference links relative to the current document). For example, here's an example of a link in the header:

<a class="reference internal nav-link" href="../demo/index.html">
  Demo site
 </a>

So to define a single HTML structure you'd need to either hard-code absolute paths in the links (which I don't think is possible in Sphinx), or you'd need to ensure that your documentation is all in a single folder so that relative paths are the same everywhere.

gilbertbw commented 2 years ago

Good point! We would be happy to flatten the output into one folder. I'm not familiar enough with sphinx to know whether that can/should be done by the theme, or if we will need a pre-processing step e.g. in an extension.

Alternatively, for our use case, we could possibly set an absolute path as the <base> in the sidebar html, substituted in as a full path as part of our software installation.

Playing around a bit, it looks like a block like <base href="./" target="_top"/> in the sidebar.html seems to make the links relative to it, rather than relative to the page that includes it with an <iframe>.

choldgraf commented 2 years ago

My feeling is that re-working this theme to embed an <html> block via an iframe would be too much customization for this theme specifically, as this is a pretty particular use-case. What I'd recommend doing is writing your own sidebar-primary.html template via creating your own section template here:

https://github.com/pydata/pydata-sphinx-theme/blob/main/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/sidebar-primary.html

That could then replace the pydata sphinx theme sidebar in its entirety and you could add whatever HTML mechanism you'd like. Then in your build conf.py file, you could add the code to generate the HTML you'd like to insert into the sidebar.

That way you could have full flexibility over the sidebar.

12rambau commented 2 years ago

@gilbertbw did you had the time to check this solution ?