diff --git a/src/pydata_sphinx_theme/assets/scripts/index.js b/src/pydata_sphinx_theme/assets/scripts/index.js index 9b2da474d..03b7cfbdb 100644 --- a/src/pydata_sphinx_theme/assets/scripts/index.js +++ b/src/pydata_sphinx_theme/assets/scripts/index.js @@ -168,19 +168,8 @@ function scrollToActive() { /******************************************************************************* * Search */ -var changeShortcutText = () => { - // Change the search hint to `meta key` if we are a Mac - let forms = document.querySelectorAll("form.bd-search"); - var isMac = window.navigator.platform.toUpperCase().indexOf("MAC") >= 0; - if (isMac) { - forms.forEach( - (f) => (f.querySelector("kbd.kbd-shortcut__modifier").innerText = "⌘") - ); - } -}; - +/** Find any search forms on the page and return their input element */ var findSearchInput = () => { - // find the search form(s) on the page let forms = document.querySelectorAll("form.bd-search"); if (!forms.length) { // no search form found @@ -200,18 +189,21 @@ var findSearchInput = () => { } }; +/** + * Activate the search field on the page. + * - If there is a search field already visible it will be activated. + * - If not, then a search field will pop up. + */ var toggleSearchField = () => { - // focus/unfocus the search field (and if it's an auto-hiding one, - // show/hide it too) + // Find the search input to highlight let input = findSearchInput(); - let button = document.getElementById("bd-search-button"); + // if the input field is the hidden one (the one associated with the // search button) then toggle the button state (to show/hide the field) - let hidden_input = document.querySelector( - ".search-button__search-container input" - ); - if (input === hidden_input) { - button.classList.toggle("show"); + let searchPopupWrapper = document.querySelector(".search-button__wrapper"); + let hiddenInput = searchPopupWrapper.querySelector("input"); + if (input === hiddenInput) { + searchPopupWrapper.classList.toggle("show"); } // when toggling off the search field, remove its focus if (document.activeElement === input) { @@ -223,31 +215,49 @@ var toggleSearchField = () => { } }; -// Add an event listener for toggleSearchField() for Ctrl/Cmd + K -window.addEventListener( - "keydown", - (event) => { - let input = findSearchInput(); - // toggle on Ctrl+k or ⌘+k - if ((event.ctrlKey || event.metaKey) && event.code == "KeyK") { - event.preventDefault(); - toggleSearchField(); - } - // also allow Escape key to hide (but not show) the dynamic search field - else if (document.activeElement === input && event.code == "Escape") { - toggleSearchField(); - } - }, - true -); - -window.onload = function () { - changeShortcutText(); - let button = document.getElementById("bd-search-button"); - let overlay = document.querySelector("div.search-button__overlay"); - if (button) { - button.onclick = toggleSearchField; +/** Add an event listener for toggleSearchField() for Ctrl/Cmd + K */ +var addEventListenerForSearchKeyboard = () => { + window.addEventListener( + "keydown", + (event) => { + let input = findSearchInput(); + // toggle on Ctrl+k or ⌘+k + if ((event.ctrlKey || event.metaKey) && event.code == "KeyK") { + event.preventDefault(); + toggleSearchField(); + } + // also allow Escape key to hide (but not show) the dynamic search field + else if (document.activeElement === input && event.code == "Escape") { + toggleSearchField(); + } + }, + true + ); +}; + +/** Change the search hint to `meta key` if we are a Mac */ +var changeSearchShortcutKey = () => { + let forms = document.querySelectorAll("form.bd-search"); + var isMac = window.navigator.platform.toUpperCase().indexOf("MAC") >= 0; + if (isMac) { + forms.forEach( + (f) => (f.querySelector("kbd.kbd-shortcut__modifier").innerText = "⌘") + ); } +}; + +/** Activate callbacks for search button popup */ +var setupSearchButtons = () => { + changeSearchShortcutKey(); + addEventListenerForSearchKeyboard(); + + // Add the search button trigger event callback + document.querySelectorAll(".search-button__button").forEach((btn) => { + btn.onclick = toggleSearchField; + }); + + // Add the search button overlay event callback + let overlay = document.querySelector(".search-button__overlay"); if (overlay) { overlay.onclick = toggleSearchField; } @@ -262,3 +272,4 @@ window.onload = function () { $(addModeListener); $(scrollToActive); $(addTOCInteractivity); +$(setupSearchButtons); diff --git a/src/pydata_sphinx_theme/assets/styles/components/_search.scss b/src/pydata_sphinx_theme/assets/styles/components/_search.scss index cfc4392e8..bdd8164b8 100644 --- a/src/pydata_sphinx_theme/assets/styles/components/_search.scss +++ b/src/pydata_sphinx_theme/assets/styles/components/_search.scss @@ -69,18 +69,36 @@ } // __search-container will only show up when we use the search pop-up bar -.search-button__search-container { +.search-button__search-container, +.search-button__overlay { display: none; - // Center in middle of screen just underneath header - position: fixed; - z-index: $zindex-fixed; - top: 30%; - left: 50%; - transform: translate(-50%, -50%); - right: 1rem; - margin-top: 0.5rem; - width: 90%; - max-width: 800px; +} +.search-button__wrapper.show { + .search-button__search-container { + display: flex; + // Center in middle of screen just underneath header + position: fixed; + z-index: $zindex-modal; + top: 30%; + left: 50%; + transform: translate(-50%, -50%); + right: 1rem; + margin-top: 0.5rem; + width: 90%; + max-width: 800px; + } + + .search-button__overlay { + display: flex; + position: fixed; + z-index: $zindex-modal-backdrop; + background-color: black; + opacity: 0.5; + width: 100%; + height: 100%; + top: 0px; + left: 0px; + } form.bd-search { flex-grow: 1; @@ -95,23 +113,22 @@ } } -.search-button__overlay { - display: none; -} +/** + * Button behavior on mobile / wide so it shows up in the header on mobile. + */ -#bd-search-button.show { - ~ .search-button__search-container { +// The navbar end version should only show on wide screens +.navbar-end__search-button-container { + display: none; + @include media-breakpoint-up($breakpoint-header) { display: flex; } +} - ~ .search-button__overlay { - display: flex; - position: fixed; - background-color: black; - opacity: 0.5; - width: 100%; - height: 100%; - top: 0px; - left: 0px; +// The one next to the hamburger menu only shows on narrow screens +.search-button-container--mobile { + margin-left: auto; + @include media-breakpoint-up($breakpoint-header) { + display: none; } } diff --git a/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button.html b/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button.html index 07ced2e4a..5483feac4 100644 --- a/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button.html +++ b/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button.html @@ -1,14 +1,4 @@ -{# Search page has its own UI / UX for search #} - -{% set containerClass="search-button__search-container" %} - - - - -{#- This will be hidden by default until click -#} -
-
- {% include "../components/search-field.html" %} -
diff --git a/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html b/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html index 4bb6ef41e..09f4ffa6b 100644 --- a/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html +++ b/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html @@ -51,6 +51,15 @@ + + +
+
+
+ {% include "../components/search-field.html" %} +
+
+ {% include "sections/announcement.html" %} {% block docs_navbar %} diff --git a/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/header.html b/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/header.html index 193c414e3..9f139abb8 100644 --- a/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/header.html +++ b/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/header.html @@ -6,6 +6,11 @@ {% endfor %} + {# A search button to show up only on mobile #} +
+ {%- include "../components/search-button.html" %} +
+ @@ -21,6 +26,9 @@