diff --git a/docs/sections/header.md b/docs/sections/header.md index c637a633..e979100d 100644 --- a/docs/sections/header.md +++ b/docs/sections/header.md @@ -6,7 +6,7 @@ If any of this configuration is set, then your header will show at the top of th ## Add components to the header navbar -There are three configuration options you can use in `html_theme_options`: +There are four configuration options you can use in `html_theme_options`: **`navbar_start`**: Adds components to the beginning of the header. **Visible on all screen sizes**. Use this for adding a logo that you want to persist over time. @@ -14,6 +14,8 @@ There are three configuration options you can use in `html_theme_options`: **`navbar_end`**: Adds components to the end of the header. **Moved to the sizebar on mobile**. Use this for extra social links or buttons. +**`navbar_persistent`**: Adds components to the end of the header that stay there on mobile rather than moving to the sidebar. + ## An example For example, you can add a button to the header like so: diff --git a/src/sphinx_book_theme/__init__.py b/src/sphinx_book_theme/__init__.py index 4c583c97..130959db 100644 --- a/src/sphinx_book_theme/__init__.py +++ b/src/sphinx_book_theme/__init__.py @@ -166,6 +166,15 @@ def update_mode_thebe_config(app): app.env.config.thebe_config = thebe_config +def update_navbar_defaults(app): + """Keep the top navbar empty unless the user asks for something in it. + + Without this, the pydata theme adds a search button to the navbar. + """ + theme_options = get_theme_options_dict(app) + theme_options.setdefault("navbar_persistent", []) + + def check_deprecation_keys(app): """Warns about the deprecated keys.""" @@ -218,6 +227,9 @@ def setup(app: Sphinx): app.add_message_catalog(MESSAGE_CATALOG_NAME, locale_dir) # Events + app.connect( + "builder-inited", update_navbar_defaults, priority=400 + ) # before pydata theme app.connect("builder-inited", update_mode_thebe_config) app.connect("builder-inited", check_deprecation_keys) app.connect("builder-inited", update_sourcename) diff --git a/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html b/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html index 0d56fc1f..d50761fc 100644 --- a/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html +++ b/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html @@ -1,6 +1,14 @@ {% extends "pydata_sphinx_theme/layout.html" %} {# ref: https://github.com/pydata/pydata-sphinx-theme/blob/master/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html #} +{# Skip
when no navbar area has any content in it. #} +{% block docs_navbar %} +{%- if theme_navbar_start or theme_navbar_center or theme_navbar_end or theme_navbar_persistent %} +{{ super() }} +{%- endif %} +{% endblock docs_navbar %} + + {% block docs_main %} {# A tiny helper pixel to detect if we've scrolled #}
diff --git a/tests/test_build.py b/tests/test_build.py index 360a01f0..5fb1c9f0 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -151,6 +151,26 @@ def test_navbar_options_home_page_in_toc(sphinx_build_factory): assert "Index with code in title" in str(li) +def test_no_navbar_by_default(sphinx_build_factory): + """The top navbar is opt-in, so nothing should be rendered for it.""" + sphinx_build = sphinx_build_factory("base").build(assert_pass=True) # type: SphinxBuild + index = sphinx_build.html_tree("index.html") + assert index.find(id="pst-header") is None + # The only search button is the one in the primary sidebar + search_buttons = index.select("button.search-button-field") + assert len(search_buttons) == 1 + assert search_buttons[0].find_parent(id="pst-primary-sidebar") is not None + + +def test_navbar_opt_in(sphinx_build_factory): + """Filling in any navbar area brings the top navbar back.""" + sphinx_build = sphinx_build_factory( + "base", + confoverrides={"html_theme_options.navbar_center": ["navbar-nav.html"]}, + ).build(assert_pass=True) # type: SphinxBuild + assert sphinx_build.html_tree("index.html").find(id="pst-header") is not None + + @pytest.mark.parametrize( "option,value", [