Skip to content

Commit

Permalink
fix merge conflict w/ upstream/main
Browse files Browse the repository at this point in the history
  • Loading branch information
drammock committed Jan 23, 2025
2 parents ec46d15 + 7c54d4a commit 8539bcc
Show file tree
Hide file tree
Showing 17 changed files with 306 additions and 51 deletions.
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ default_language_version:

repos:
- repo: "https://github.com/pycontribs/mirrors-prettier"
rev: v3.3.3
rev: v3.4.2
hooks:
- id: prettier
# Exclude the HTML, since it doesn't understand Jinja2
Expand All @@ -22,20 +22,20 @@ repos:
exclude: .+\.html|webpack\.config\.js|tests/test_a11y/

- repo: "https://github.com/astral-sh/ruff-pre-commit"
rev: "v0.8.1"
rev: "v0.8.6"
hooks:
- id: ruff
args: [--exit-non-zero-on-fix]
- id: ruff-format

- repo: "https://github.com/asottile/pyupgrade"
rev: v3.19.0
rev: v3.19.1
hooks:
- id: pyupgrade
args: [--py37-plus]

- repo: "https://github.com/Riverside-Healthcare/djLint"
rev: v1.36.3
rev: v1.36.4
hooks:
- id: djlint-jinja
types_or: ["html"]
Expand All @@ -56,7 +56,7 @@ repos:
- id: remove-metadata

- repo: "https://github.com/thibaudcolas/pre-commit-stylelint"
rev: v16.11.0
rev: v16.12.0
hooks:
- id: stylelint
# automatically fix .scss files where possible
Expand Down
12 changes: 6 additions & 6 deletions docs/_static/switcher.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
"url": "https://pydata-sphinx-theme.readthedocs.io/en/latest/"
},
{
"name": "0.16.1rc0",
"version": "v0.16.1rc0",
"url": "https://pydata-sphinx-theme.readthedocs.io/en/v0.16.1rc0/"
"name": "0.16.1 (stable)",
"version": "v0.16.1",
"url": "https://pydata-sphinx-theme.readthedocs.io/en/stable/",
"preferred": true
},
{
"name": "0.16.0 (stable)",
"name": "0.16.0",
"version": "v0.16.0",
"url": "https://pydata-sphinx-theme.readthedocs.io/en/stable/",
"preferred": true
"url": "https://pydata-sphinx-theme.readthedocs.io/en/v0.16.0/"
},
{
"name": "0.15.4",
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@
"version_match": version_match,
},
# "back_to_top_button": False,
"search_as_you_type": True,
}

html_sidebars = {
Expand Down
11 changes: 11 additions & 0 deletions docs/user_guide/search.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,14 @@ following configuration to your ``conf.py`` file:
html_theme_options = {
"search_bar_text": "Your text here..."
}
Configure the inline search results (search-as-you-type) feature
----------------------------------------------------------------

Set the ``search_as_you_type`` HTML theme option to ``True``.

.. code:: python
html_theme_options = {
"search_as_you_type": True
}
9 changes: 5 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion src/pydata_sphinx_theme/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from . import edit_this_page, logo, pygments, short_link, toctree, translator, utils


__version__ = "0.16.1rc0"
__version__ = "0.16.1"


def update_config(app):
Expand Down Expand Up @@ -241,6 +241,12 @@ def update_and_remove_templates(
"""
app.add_js_file(None, body=js)

# Specify whether search-as-you-type should be used or not.
search_as_you_type = str(context["theme_search_as_you_type"]).lower()
app.add_js_file(
None, body=f"DOCUMENTATION_OPTIONS.search_as_you_type = {search_as_you_type};"
)

# Update version number for the "made with version..." component
context["theme_version"] = __version__

Expand Down
166 changes: 166 additions & 0 deletions src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ var addEventListenerForSearchKeyboard = () => {
// also allow Escape key to hide (but not show) the dynamic search field
else if (document.activeElement === input && /Escape/i.test(event.key)) {
toggleSearchField();
resetSearchAsYouTypeResults();
}
},
true,
Expand Down Expand Up @@ -332,6 +333,170 @@ var setupSearchButtons = () => {
searchDialog.addEventListener("click", closeDialogOnBackdropClick);
};

/*******************************************************************************
* Inline search results (search-as-you-type)
*
* Immediately displays search results under the search query textbox.
*
* The search is conducted by Sphinx's built-in search tools (searchtools.js).
* Usually searchtools.js is only available on /search.html but
* pydata-sphinx-theme (PST) has been modified to load searchtools.js on every
* page. After the user types something into PST's search query textbox,
* searchtools.js executes the search and populates the results into
* the #search-results container. searchtools.js expects the results container
* to have that exact ID.
*/
var setupSearchAsYouType = () => {
if (!DOCUMENTATION_OPTIONS.search_as_you_type) {
return;
}

// Don't interfere with the default search UX on /search.html.
if (window.location.pathname.endsWith("/search.html")) {
return;
}

// Bail if the Search class is not available. Search-as-you-type is
// impossible without that class. layout.html should ensure that
// searchtools.js loads.
//
// Search class is defined in upstream Sphinx:
// https://github.com/sphinx-doc/sphinx/blob/6678e357048ea1767daaad68e7e0569786f3b458/sphinx/themes/basic/static/searchtools.js#L181
if (!Search) {
return;
}

// Destroy the previous search container and create a new one.
resetSearchAsYouTypeResults();
let timeoutId = null;
let lastQuery = "";
const searchInput = document.querySelector(
"#pst-search-dialog input[name=q]",
);

// Initiate searches whenever the user types stuff in the search modal textbox.
searchInput.addEventListener("keyup", () => {
const query = searchInput.value;

// Don't search when there's nothing in the query textbox.
if (query === "") {
resetSearchAsYouTypeResults(); // Remove previous results.
return;
}

// Don't search if there is no detectable change between
// the last query and the current query. E.g. the user presses
// Tab to start navigating the search results.
if (query === lastQuery) {
return;
}

// The user has changed the search query. Delete the old results
// and start setting up the new container.
resetSearchAsYouTypeResults();

// Debounce so that the search only starts when the user stops typing.
const delay_ms = 300;
lastQuery = query;
if (timeoutId) {
window.clearTimeout(timeoutId);
}
timeoutId = window.setTimeout(() => {
Search.performSearch(query);
document.querySelector("#search-results").classList.remove("empty");
timeoutId = null;
}, delay_ms);
});
};

// Delete the old search results container (if it exists) and set up a new one.
//
// There is some complexity around ensuring that the search results links are
// correct because we're extending searchtools.js past its assumed usage.
// Sphinx assumes that searches are only executed from /search.html and
// therefore it assumes that all search results links should be relative to
// the root directory of the website. In our case the search can now execute
// from any page of the website so we must fix the relative URLs that
// searchtools.js generates.
var resetSearchAsYouTypeResults = () => {
if (!DOCUMENTATION_OPTIONS.search_as_you_type) {
return;
}
// If a search-as-you-type results container was previously added,
// remove it now.
let results = document.querySelector("#search-results");
if (results) {
results.remove();
}

// Create a new search-as-you-type results container.
results = document.createElement("section");
results.classList.add("empty");
// Remove the container element from the tab order. Individual search
// results are still focusable.
results.tabIndex = -1;
// When focus is on a search result, make sure that pressing Escape closes
// the search modal.
results.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
event.preventDefault();
event.stopPropagation();
toggleSearchField();
resetSearchAsYouTypeResults();
}
});
// IMPORTANT: The search results container MUST have this exact ID.
// searchtools.js is hardcoded to populate into the node with this ID.
results.id = "search-results";
let modal = document.querySelector("#pst-search-dialog");
modal.appendChild(results);

// Get the relative path back to the root of the website.
const root =
"URL_ROOT" in DOCUMENTATION_OPTIONS
? DOCUMENTATION_OPTIONS.URL_ROOT // Sphinx v6 and earlier
: document.documentElement.dataset.content_root; // Sphinx v7 and later

// As Sphinx populates the search results, this observer makes sure that
// each URL is correct (i.e. doesn't 404).
const linkObserver = new MutationObserver(() => {
const links = Array.from(
document.querySelectorAll("#search-results .search a"),
);
// Check every link every time because the timing of when new results are
// added is unpredictable and it's not an expensive operation.
links.forEach((link) => {
link.tabIndex = 0; // Use natural tab order for search results.
// Don't use the link.href getter because the browser computes the href
// as a full URL. We need the relative URL that Sphinx generates.
const href = link.getAttribute("href");
if (href.startsWith(root)) {
// No work needed. The root has already been prepended to the href.
return;
}
link.href = `${root}${href}`;
});
});

// The node that linkObserver watches doesn't exist until the user types
// something into the search textbox. This second observer (resultsObserver)
// just waits for #search-results to exist and then registers
// linkObserver on it.
let isObserved = false;
const resultsObserver = new MutationObserver(() => {
if (isObserved) {
return;
}
const container = document.querySelector("#search-results .search");
if (!container) {
return;
}
linkObserver.observe(container, { childList: true });
isObserved = true;
});
resultsObserver.observe(results, { childList: true });
};

/*******************************************************************************
* Version Switcher
* Note that this depends on two variables existing that are defined in
Expand Down Expand Up @@ -857,6 +1022,7 @@ documentReady(addModeListener);
documentReady(scrollToActive);
documentReady(addTOCInteractivity);
documentReady(setupSearchButtons);
documentReady(setupSearchAsYouType);
documentReady(setupMobileSidebarKeyboardHandlers);

// Determining whether an element has scrollable content depends on stylesheets,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@
$rgb-col: map.merge(
$rgb-col,
(
$channel:
math.pow(math.div((math.div($value, 255) + 0.055), 1.055), 2.4),
$channel: math.pow(
math.div((math.div($value, 255) + 0.055), 1.055),
2.4
),
)
);
}
Expand Down
11 changes: 7 additions & 4 deletions src/pydata_sphinx_theme/assets/styles/base/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -72,33 +72,36 @@ a {
line-height: 1.15;
}

// From 0.16.1, the preferred variable for headings is --pst-color-heading
// if you have --pst-heading-color, this variable will be used, otherwise the default
// --pst-color-heading will be used.
h1 {
@extend %heading-style;

margin-top: 0;
font-size: var(--pst-font-size-h1);
color: var(--pst-color-heading);
color: var(--pst-heading-color, --pst-color-heading);
}

h2 {
@extend %heading-style;

font-size: var(--pst-font-size-h2);
color: var(--pst-color-heading);
color: var(--pst-heading-color, --pst-color-heading);
}

h3 {
@extend %heading-style;

font-size: var(--pst-font-size-h3);
color: var(--pst-color-heading);
color: var(--pst-heading-color, --pst-color-heading);
}

h4 {
@extend %heading-style;

font-size: var(--pst-font-size-h4);
color: var(--pst-color-heading);
color: var(--pst-heading-color, --pst-color-heading);
}

h5 {
Expand Down
Loading

0 comments on commit 8539bcc

Please sign in to comment.