From a92dec5dd9f08353d6217c5b82d195f2ec540371 Mon Sep 17 00:00:00 2001 From: Alasdair Wilson Date: Mon, 23 Jun 2025 20:17:11 +0100 Subject: [PATCH 1/5] feat: add nested submenus in docs dropdown --- docs/conf.py | 2 +- src/sunpy_sphinx_theme/__init__.py | 38 +++++-- src/sunpy_sphinx_theme/conf.py | 6 +- .../theme/sunpy/components/navbar_center.html | 100 ++++++++++++++---- .../theme/sunpy/static/js/submenu-toggle.js | 35 ++++++ .../theme/sunpy/static/sunpy_style.css | 19 ++++ 6 files changed, 168 insertions(+), 32 deletions(-) create mode 100644 src/sunpy_sphinx_theme/theme/sunpy/static/js/submenu-toggle.js diff --git a/docs/conf.py b/docs/conf.py index c08486bd..a29b1b78 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,7 +18,7 @@ project = "sunpy-sphinx-theme test docs" author = "The SunPy Community" -copyright = f"{datetime.datetime.now(datetime.UTC).year}, {author}" # NOQA: A001 +copyright = f"{datetime.datetime.now(datetime.timezone.utc).year}, {author}" # NOQA: A001 extensions = [ "sphinx_automodapi.automodapi", "sphinx_automodapi.smart_resolver", diff --git a/src/sunpy_sphinx_theme/__init__.py b/src/sunpy_sphinx_theme/__init__.py index 17ff3c33..0a7ddfbc 100644 --- a/src/sunpy_sphinx_theme/__init__.py +++ b/src/sunpy_sphinx_theme/__init__.py @@ -34,23 +34,39 @@ def default_navbar(): ], ), ( - "Documentation", +"Documentation", [ + # Core packages shown directly ("sunpy", "https://docs.sunpy.org/", 3), - ("ndcube", "https://docs.sunpy.org/projects/ndcube/", 3), + ("aiapy", "https://aiapy.readthedocs.io/", 3), ("drms", "https://docs.sunpy.org/projects/drms/", 3), - ("sunraster", "https://docs.sunpy.org/projects/sunraster/", 3), + ("dkist", "https://docs.dkist.nso.edu/projects/python-tools", 3), + ("ndcube", "https://docs.sunpy.org/projects/ndcube/", 3), + ("roentgen", "https://roentgen.readthedocs.io/", 3), ("sunkit-image", "https://docs.sunpy.org/projects/sunkit-image/", 3), - ("aiapy", "https://aiapy.readthedocs.io/", 3), + ("sunkit-instruments", "https://docs.sunpy.org/projects/sunkit-instruments/", 3), + ("sunkit-magex", "https://docs.sunpy.org/projects/sunkit-magex/", 3), ("sunpy-soar", "https://docs.sunpy.org/projects/soar/", 3), - ("roentgen", "https://roentgen.readthedocs.io/", 3), - ("sunkit-instruments ", "https://docs.sunpy.org/projects/sunkit-instruments/", 3), - ("demcmc", "https://demcmc.readthedocs.io/en/latest/", 3), - ("dkist", "https://docs.dkist.nso.edu/projects/python-tools", 3), ("solarmach", "https://solarmach.readthedocs.io/en/stable/", 3), - ("sunkit-magex", "https://docs.sunpy.org/projects/sunkit-magex/", 3), - ("pyflct", "https://pyflct.readthedocs.io/", 3), - ("radiospectra", "https://docs.sunpy.org/projects/radiospectra/", 3), + ("sunraster", "https://docs.sunpy.org/projects/sunraster/", 3), + # Provisional packages submenu + ( + "Provisional", + [ + ("pyflct", "https://pyflct.readthedocs.io/", 3), + ("radiospectra", "https://docs.sunpy.org/projects/radiospectra/", 3), + ] + ), + # Tools submenu + ( + "Tools", + [ + ("ablog", "https://ablog.readthedocs.io/en/stable/", 3), + ("demcmc", "https://demcmc.readthedocs.io/en/stable/", 3), + ("mpl-animators", "https://docs.sunpy.org/projects/mpl-animators/", 3), + ("streamtracer", "https://docs.sunpy.org/projects/streamtracer/", 3), + ], + ), ], ), ("Packages", "affiliated/", 2), diff --git a/src/sunpy_sphinx_theme/conf.py b/src/sunpy_sphinx_theme/conf.py index 81c1909e..e6271afd 100644 --- a/src/sunpy_sphinx_theme/conf.py +++ b/src/sunpy_sphinx_theme/conf.py @@ -26,8 +26,12 @@ "svg_icon", ] +html_js_files = [ + 'js/submenu-toggle.js', +] + html_theme = "sunpy" html_theme_options = {} html_theme_path = [str(get_html_theme_path())] -html_static_path = [str(get_html_theme_path() / "static")] +html_static_path = [str(get_html_theme_path() / "static")] \ No newline at end of file diff --git a/src/sunpy_sphinx_theme/theme/sunpy/components/navbar_center.html b/src/sunpy_sphinx_theme/theme/sunpy/components/navbar_center.html index 51f7136e..b4456d31 100644 --- a/src/sunpy_sphinx_theme/theme/sunpy/components/navbar_center.html +++ b/src/sunpy_sphinx_theme/theme/sunpy/components/navbar_center.html @@ -8,31 +8,93 @@ {% set toggle="collapse" %} {% set list_class="collapse" %} {% endif %} +{% macro render_nav_item(item, depth=0) %} + {% set is_leaf = item[1] is string %} + {% set is_nested = item[1] is iterable and (item[1]|length > 0) and (item[1][0] is sequence or item[1][0] is mapping) %} + + {% if is_leaf %} + + + {% elif is_nested %} + {% set submenu_id = item[0]|replace(" ", "_")|lower %} + + {% endif %} +{% endmacro %} + + \ No newline at end of file diff --git a/src/sunpy_sphinx_theme/theme/sunpy/static/js/submenu-toggle.js b/src/sunpy_sphinx_theme/theme/sunpy/static/js/submenu-toggle.js new file mode 100644 index 00000000..f2933265 --- /dev/null +++ b/src/sunpy_sphinx_theme/theme/sunpy/static/js/submenu-toggle.js @@ -0,0 +1,35 @@ + +document.addEventListener("DOMContentLoaded", function () { + const triggers = document.querySelectorAll('.dropdown-submenu > .dropdown-toggle'); + + triggers.forEach(function (trigger, i) { + // Prevent multiple listeners + trigger.dataset.bound = "true"; + trigger.addEventListener('click', function (e) { + + if (trigger.dataset.processing === "true") { + // Defensive double-bind check to avoid multiple event listeners triggering + return; + } + trigger.dataset.processing = "true"; + setTimeout(() => delete trigger.dataset.processing, 100); + + // stop bootstrap from using this click to close the parent dropdown + e.preventDefault(); + e.stopPropagation(); + + const submenu = trigger.nextElementSibling; + // Close other submenus + const parent = trigger.closest('.dropdown-menu'); + if (parent) { + parent.querySelectorAll('.dropdown-menu.show').forEach(function (open) { + if (open !== submenu) { + open.classList.remove('show'); + } + }); + } + + submenu.classList.toggle('show'); + }); + }); +}); diff --git a/src/sunpy_sphinx_theme/theme/sunpy/static/sunpy_style.css b/src/sunpy_sphinx_theme/theme/sunpy/static/sunpy_style.css index 268635e9..9ac22b11 100644 --- a/src/sunpy_sphinx_theme/theme/sunpy/static/sunpy_style.css +++ b/src/sunpy_sphinx_theme/theme/sunpy/static/sunpy_style.css @@ -412,3 +412,22 @@ html[data-theme="dark"] .search-button-field:hover { align-items: center; } } + +/* Position submenu beside parent */ +.dropdown-submenu { + position: relative; +} + +/* Initially hidden */ +.dropdown-submenu > .dropdown-menu { + position: absolute; + top: 0; + left: 100%; + display: none; + z-index: 1000; +} + +/* Show when toggled by JS */ +.dropdown-submenu > .dropdown-menu.show { + display: block; +} From d2f9f945601281039b7018b2e1a6272942296c5d Mon Sep 17 00:00:00 2001 From: Alasdair Wilson Date: Mon, 23 Jun 2025 22:12:01 +0100 Subject: [PATCH 2/5] l.i.n.t. --- src/sunpy_sphinx_theme/__init__.py | 4 +- src/sunpy_sphinx_theme/conf.py | 4 +- .../theme/sunpy/components/navbar_center.html | 6 +- .../theme/sunpy/static/js/submenu-toggle.js | 56 +++++++++---------- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/sunpy_sphinx_theme/__init__.py b/src/sunpy_sphinx_theme/__init__.py index 0a7ddfbc..835eb131 100644 --- a/src/sunpy_sphinx_theme/__init__.py +++ b/src/sunpy_sphinx_theme/__init__.py @@ -34,7 +34,7 @@ def default_navbar(): ], ), ( -"Documentation", + "Documentation", [ # Core packages shown directly ("sunpy", "https://docs.sunpy.org/", 3), @@ -55,7 +55,7 @@ def default_navbar(): [ ("pyflct", "https://pyflct.readthedocs.io/", 3), ("radiospectra", "https://docs.sunpy.org/projects/radiospectra/", 3), - ] + ], ), # Tools submenu ( diff --git a/src/sunpy_sphinx_theme/conf.py b/src/sunpy_sphinx_theme/conf.py index e6271afd..6c605d2e 100644 --- a/src/sunpy_sphinx_theme/conf.py +++ b/src/sunpy_sphinx_theme/conf.py @@ -27,11 +27,11 @@ ] html_js_files = [ - 'js/submenu-toggle.js', + "js/submenu-toggle.js", ] html_theme = "sunpy" html_theme_options = {} html_theme_path = [str(get_html_theme_path())] -html_static_path = [str(get_html_theme_path() / "static")] \ No newline at end of file +html_static_path = [str(get_html_theme_path() / "static")] diff --git a/src/sunpy_sphinx_theme/theme/sunpy/components/navbar_center.html b/src/sunpy_sphinx_theme/theme/sunpy/components/navbar_center.html index b4456d31..5f93dd6e 100644 --- a/src/sunpy_sphinx_theme/theme/sunpy/components/navbar_center.html +++ b/src/sunpy_sphinx_theme/theme/sunpy/components/navbar_center.html @@ -51,7 +51,7 @@ {{ render_nav_item(navlink) }} {% endfor %} {% endif %} - + {% if theme_external_links %} {% for external_link in theme_external_links %}