PKֺ2X:]/]/pydata_sphinx_theme/__init__.py"""Bootstrap-based sphinx theme from the PyData community.""" import json from functools import partial from pathlib import Path from typing import Dict from urllib.parse import urlparse import requests from requests.exceptions import ConnectionError, HTTPError, RetryError from sphinx.application import Sphinx from sphinx.errors import ExtensionError from . import edit_this_page, logo, pygment, short_link, toctree, translator, utils __version__ = "0.15.2" def update_config(app): """Update config with new default values and handle deprecated keys.""" # By the time `builder-inited` happens, `app.builder.theme_options` already exists. # At this point, modifying app.config.html_theme_options will NOT update the # page's HTML context (e.g. in jinja, `theme_keyword`). # To do this, you must manually modify `app.builder.theme_options`. theme_options = utils.get_theme_options_dict(app) warning = partial(utils.maybe_warn, app) # TODO: deprecation; remove after 0.14 release if theme_options.get("logo_text"): logo = theme_options.get("logo", {}) logo["text"] = theme_options.get("logo_text") theme_options["logo"] = logo warning( "The configuration `logo_text` is deprecated. Use `'logo': {'text': }`." ) # TODO: DEPRECATE after 0.14 if theme_options.get("footer_items"): theme_options["footer_start"] = theme_options.get("footer_items") warning( "`footer_items` is deprecated. Use `footer_start` or `footer_end` instead." ) # TODO: DEPRECATE after v0.15 if theme_options.get("favicons"): warning( "The configuration `favicons` is deprecated. " "Use the sphinx-favicon extension instead." ) # TODO: in 0.15, set the default navigation_with_keys value to False and remove this deprecation notice if theme_options.get("navigation_with_keys", None) is None: warning( "The default value for `navigation_with_keys` will change to `False` in " "the next release. If you wish to preserve the old behavior for your site, " "set `navigation_with_keys=True` in the `html_theme_options` dict in your " "`conf.py` file. Be aware that `navigation_with_keys = True` has negative " "accessibility implications: " "https://github.com/pydata/pydata-sphinx-theme/issues/1492" ) theme_options["navigation_with_keys"] = False # Validate icon links if not isinstance(theme_options.get("icon_links", []), list): raise ExtensionError( "`icon_links` must be a list of dictionaries, you provided " f"type {type(theme_options.get('icon_links'))}." ) # Set the anchor link default to be # if the user hasn't provided their own if not utils.config_provided_by_user(app, "html_permalinks_icon"): app.config.html_permalinks_icon = "#" # check the validity of the theme switcher file is_dict = isinstance(theme_options.get("switcher"), dict) should_test = theme_options.get("check_switcher", True) if is_dict and should_test: theme_switcher = theme_options.get("switcher") # raise an error if one of these compulsory keys is missing json_url = theme_switcher["json_url"] theme_switcher["version_match"] # try to read the json file. If it's a url we use request, # else we simply read the local file from the source directory # display a log warning if the file cannot be reached reading_error = None if urlparse(json_url).scheme in ["http", "https"]: try: request = requests.get(json_url) request.raise_for_status() content = request.text except (ConnectionError, HTTPError, RetryError) as e: reading_error = repr(e) else: try: content = Path(app.srcdir, json_url).read_text() except FileNotFoundError as e: reading_error = repr(e) if reading_error is not None: warning( f'The version switcher "{json_url}" file cannot be read due to ' f"the following error:\n{reading_error}" ) else: # check that the json file is not illformed, # throw a warning if the file is ill formed and an error if it's not json switcher_content = json.loads(content) missing_url = any(["url" not in e for e in switcher_content]) missing_version = any(["version" not in e for e in switcher_content]) if missing_url or missing_version: warning( f'The version switcher "{json_url}" file is malformed; ' 'at least one of the items is missing the "url" or "version" key' ) # Add an analytics ID to the site if provided analytics = theme_options.get("analytics", {}) if analytics: # Plausible analytics plausible_domain = analytics.get("plausible_analytics_domain") plausible_url = analytics.get("plausible_analytics_url") # Ref: https://plausible.io/docs/plausible-script if plausible_domain and plausible_url: kwargs = { "loading_method": "defer", "data-domain": plausible_domain, "filename": plausible_url, } app.add_js_file(**kwargs) # Google Analytics gid = analytics.get("google_analytics_id") if gid: gid_js_path = f"https://www.googletagmanager.com/gtag/js?id={gid}" gid_script = f""" window.dataLayer = window.dataLayer || []; function gtag(){{ dataLayer.push(arguments); }} gtag('js', new Date()); gtag('config', '{gid}'); """ # Link the JS files app.add_js_file(gid_js_path, loading_method="async") app.add_js_file(None, body=gid_script) # Update ABlog configuration default if present fa_provided = utils.config_provided_by_user(app, "fontawesome_included") if "ablog" in app.config.extensions and not fa_provided: app.config.fontawesome_included = True # Handle icon link shortcuts shortcuts = [ ("twitter_url", "fa-brands fa-square-twitter", "Twitter"), ("bitbucket_url", "fa-brands fa-bitbucket", "Bitbucket"), ("gitlab_url", "fa-brands fa-square-gitlab", "GitLab"), ("github_url", "fa-brands fa-square-github", "GitHub"), ] # Add extra icon links entries if there were shortcuts present # TODO: Deprecate this at some point in the future? icon_links = theme_options.get("icon_links", []) for url, icon, name in shortcuts: if theme_options.get(url): # This defaults to an empty list so we can always insert icon_links.insert( 0, { "url": theme_options.get(url), "icon": icon, "name": name, "type": "fontawesome", }, ) theme_options["icon_links"] = icon_links # Prepare the logo config dictionary theme_logo = theme_options.get("logo") if not theme_logo: # In case theme_logo is an empty string theme_logo = {} if not isinstance(theme_logo, dict): raise ValueError(f"Incorrect logo config type: {type(theme_logo)}") theme_options["logo"] = theme_logo def update_and_remove_templates( app: Sphinx, pagename: str, templatename: str, context, doctree ) -> None: """Update template names and assets for page build.""" # Allow for more flexibility in template names template_sections = [ "theme_navbar_start", "theme_navbar_center", "theme_navbar_persistent", "theme_navbar_end", "theme_article_header_start", "theme_article_header_end", "theme_article_footer_items", "theme_content_footer_items", "theme_footer_start", "theme_footer_center", "theme_footer_end", "theme_primary_sidebar_end", "sidebars", ] for section in template_sections: if context.get(section): context[section] = utils._update_and_remove_templates( app=app, context=context, templates=context.get(section, []), section=section, templates_skip_empty_check=["sidebar-nav-bs.html", "navbar-nav.html"], ) # Remove a duplicate entry of the theme CSS. This is because it is in both: # - theme.conf # - manually linked in `webpack-macros.html` if "css_files" in context: theme_css_name = "_static/styles/pydata-sphinx-theme.css" for i in range(len(context["css_files"])): asset = context["css_files"][i] # TODO: eventually the contents of context['css_files'] etc should probably # only be _CascadingStyleSheet etc. For now, assume mixed with strings. asset_path = getattr(asset, "filename", str(asset)) if asset_path == theme_css_name: del context["css_files"][i] break # Add links for favicons in the topbar for favicon in context.get("theme_favicons", []): icon_type = Path(favicon["href"]).suffix.strip(".") opts = { "rel": favicon.get("rel", "icon"), "sizes": favicon.get("sizes", "16x16"), "type": f"image/{icon_type}", } if "color" in favicon: opts["color"] = favicon["color"] # Sphinx will auto-resolve href if it's a local file app.add_css_file(favicon["href"], **opts) # Add metadata to DOCUMENTATION_OPTIONS so that we can re-use later # Pagename to current page app.add_js_file(None, body=f"DOCUMENTATION_OPTIONS.pagename = '{pagename}';") if isinstance(context.get("theme_switcher"), dict): theme_switcher = context["theme_switcher"] json_url = theme_switcher["json_url"] version_match = theme_switcher["version_match"] # Add variables to our JavaScript for re-use in our main JS script js = f""" DOCUMENTATION_OPTIONS.theme_version = '{__version__}'; DOCUMENTATION_OPTIONS.theme_switcher_json_url = '{json_url}'; DOCUMENTATION_OPTIONS.theme_switcher_version_match = '{version_match}'; DOCUMENTATION_OPTIONS.show_version_warning_banner = {str(context["theme_show_version_warning_banner"]).lower()}; """ app.add_js_file(None, body=js) # Update version number for the "made with version..." component context["theme_version"] = __version__ def setup(app: Sphinx) -> Dict[str, str]: """Setup the Sphinx application.""" here = Path(__file__).parent.resolve() theme_path = here / "theme" / "pydata_sphinx_theme" app.add_html_theme("pydata_sphinx_theme", str(theme_path)) app.add_post_transform(short_link.ShortenLinkTransform) app.connect("builder-inited", translator.setup_translators) app.connect("builder-inited", update_config) app.connect("html-page-context", edit_this_page.setup_edit_url) app.connect("html-page-context", toctree.add_toctree_functions) app.connect("html-page-context", update_and_remove_templates) app.connect("html-page-context", logo.setup_logo_path) app.connect("html-page-context", utils.set_secondary_sidebar_items) app.connect("build-finished", pygment.overwrite_pygments_css) app.connect("build-finished", logo.copy_logo_images) # https://www.sphinx-doc.org/en/master/extdev/i18n.html#extension-internationalization-i18n-and-localization-l10n-using-i18n-api app.add_message_catalog("sphinx", here / "locale") # Include component templates app.config.templates_path.append(str(theme_path / "components")) return {"parallel_read_safe": True, "parallel_write_safe": False} PKֺ2X`/pydata_sphinx_theme/assets/scripts/bootstrap.js// Import and setup functions to control Bootstrap's behavior. import "@popperjs/core"; import * as bootstrap from "bootstrap"; import { documentReady } from "./mixin"; import "../styles/bootstrap.scss"; /******************************************************************************* * Trigger tooltips */ /** * Add tooltip to each element with the "tooltip" data-bs-toogle class */ function TriggerTooltip() { var tooltipTriggerList = [].slice.call( document.querySelectorAll('[data-bs-toggle="tooltip"]') ); tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl, { delay: { show: 500, hide: 100 }, }); }); } /******************************************************************************* * back to top button */ function backToTop() { var btn = document.getElementById("pst-back-to-top"); btn.addEventListener("click", function () { document.body.scrollTop = 0; document.documentElement.scrollTop = 0; }); } function showBackToTop() { var btn = document.getElementById("pst-back-to-top"); var header = document .getElementsByClassName("bd-header")[0] .getBoundingClientRect(); window.addEventListener("scroll", function () { if (this.oldScroll > this.scrollY && this.scrollY > header.bottom) { btn.style.display = "block"; } else { btn.style.display = "none"; } this.oldScroll = this.scrollY; }); } /******************************************************************************* * Call functions after document loading. */ documentReady(TriggerTooltip); documentReady(backToTop); documentReady(showBackToTop); window.bootstrap = bootstrap; PKֺ2X)|C}+pydata_sphinx_theme/assets/scripts/mixin.js/* define several functions to replace jQuery methods * inspired by https://tobiasahlin.com/blog/move-from-jquery-to-vanilla-javascript/ */ /** * Execute a method if DOM has finished loading * * @param {function} callback the method to execute */ export function documentReady(callback) { if (document.readyState != "loading") callback(); else document.addEventListener("DOMContentLoaded", callback); } PKֺ2XܛOO9pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js// Define the custom behavior of the page import { documentReady } from "./mixin"; import { compare, validate } from "compare-versions"; import "../styles/pydata-sphinx-theme.scss"; /******************************************************************************* * Theme interaction */ var prefersDark = window.matchMedia("(prefers-color-scheme: dark)"); /** * set the the body theme to the one specified by the user browser * * @param {event} e */ function autoTheme(e) { document.documentElement.dataset.theme = prefersDark.matches ? "dark" : "light"; } /** * Set the theme using the specified mode. * It can be one of ["auto", "dark", "light"] * * @param {str} mode */ function setTheme(mode) { if (mode !== "light" && mode !== "dark" && mode !== "auto") { console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`); mode = "auto"; } // get the theme var colorScheme = prefersDark.matches ? "dark" : "light"; document.documentElement.dataset.mode = mode; var theme = mode == "auto" ? colorScheme : mode; document.documentElement.dataset.theme = theme; // TODO: remove this line after Bootstrap upgrade // v5.3 has a colors mode: https://getbootstrap.com/docs/5.3/customize/color-modes/ document.querySelectorAll(".dropdown-menu").forEach((el) => { if (theme === "dark") { el.classList.add("dropdown-menu-dark"); } else { el.classList.remove("dropdown-menu-dark"); } }); // save mode and theme localStorage.setItem("mode", mode); localStorage.setItem("theme", theme); console.log(`[PST]: Changed to ${mode} mode using the ${theme} theme.`); // add a listener if set on auto prefersDark.onchange = mode == "auto" ? autoTheme : ""; } /** * Change the theme option order so that clicking on the btn is always a change * from "auto" */ function cycleMode() { const defaultMode = document.documentElement.dataset.defaultMode || "auto"; const currentMode = localStorage.getItem("mode") || defaultMode; var loopArray = (arr, current) => { var nextPosition = arr.indexOf(current) + 1; if (nextPosition === arr.length) { nextPosition = 0; } return arr[nextPosition]; }; // make sure the next theme after auto is always a change var modeList = prefersDark.matches ? ["auto", "light", "dark"] : ["auto", "dark", "light"]; var newMode = loopArray(modeList, currentMode); setTheme(newMode); } /** * add the theme listener on the btns of the navbar */ function addModeListener() { // the theme was set a first time using the initial mini-script // running setMode will ensure the use of the dark mode if auto is selected setTheme(document.documentElement.dataset.mode); // Attach event handlers for toggling themes colors document.querySelectorAll(".theme-switch-button").forEach((el) => { el.addEventListener("click", cycleMode); }); } /******************************************************************************* * TOC interactivity */ /** * TOC sidebar - add "active" class to parent list * * Bootstrap's scrollspy adds the active class to the link, * but for the automatic collapsing we need this on the parent list item. * * The event is triggered on "window" (and not the nav item as documented), * see https://github.com/twbs/bootstrap/issues/20086 */ function addTOCInteractivity() { window.addEventListener("activate.bs.scrollspy", function () { const navLinks = document.querySelectorAll(".bd-toc-nav a"); navLinks.forEach((navLink) => { navLink.parentElement.classList.remove("active"); }); const activeNavLinks = document.querySelectorAll(".bd-toc-nav a.active"); activeNavLinks.forEach((navLink) => { navLink.parentElement.classList.add("active"); }); }); } /******************************************************************************* * Scroll */ /** * Navigation sidebar scrolling to active page */ function scrollToActive() { // If the docs nav doesn't exist, do nothing (e.g., on search page) if (!document.querySelector(".bd-docs-nav")) { return; } var sidebar = document.querySelector("div.bd-sidebar"); // Remember the sidebar scroll position between page loads // Inspired on source of revealjs.com let storedScrollTop = parseInt( sessionStorage.getItem("sidebar-scroll-top"), 10 ); if (!isNaN(storedScrollTop)) { // If we've got a saved scroll position, just use that sidebar.scrollTop = storedScrollTop; console.log("[PST]: Scrolled sidebar using stored browser position..."); } else { // Otherwise, calculate a position to scroll to based on the lowest `active` link var sidebarNav = document.querySelector(".bd-docs-nav"); var active_pages = sidebarNav.querySelectorAll(".active"); if (active_pages.length > 0) { // Use the last active page as the offset since it's the page we're on var latest_active = active_pages[active_pages.length - 1]; var offset = latest_active.getBoundingClientRect().y - sidebar.getBoundingClientRect().y; // Only scroll the navbar if the active link is lower than 50% of the page if (latest_active.getBoundingClientRect().y > window.innerHeight * 0.5) { let buffer = 0.25; // Buffer so we have some space above the scrolled item sidebar.scrollTop = offset - sidebar.clientHeight * buffer; console.log("[PST]: Scrolled sidebar using last active link..."); } } } // Store the sidebar scroll position window.addEventListener("beforeunload", () => { sessionStorage.setItem("sidebar-scroll-top", sidebar.scrollTop); }); } /******************************************************************************* * Search */ /** * Find any search forms on the page and return their input element */ var findSearchInput = () => { let forms = document.querySelectorAll("form.bd-search"); if (!forms.length) { // no search form found return; } else { var form; if (forms.length == 1) { // there is exactly one search form (persistent or hidden) form = forms[0]; } else { // must be at least one persistent form, use the first persistent one form = document.querySelector( "div:not(.search-button__search-container) > form.bd-search" ); } return form.querySelector("input"); } }; /** * 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 = () => { // Find the search input to highlight let input = findSearchInput(); // 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 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) { input.blur(); } else { input.focus(); input.select(); input.scrollIntoView({ block: "center" }); } }; /** * 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 ( // Ignore if shift or alt are pressed !event.shiftKey && !event.altKey && // On Mac use ⌘, all other OS use Ctrl (useCommandKey ? event.metaKey && !event.ctrlKey : !event.metaKey && event.ctrlKey) && // Case-insensitive so the shortcut still works with caps lock /^k$/i.test(event.key) ) { event.preventDefault(); toggleSearchField(); } // also allow Escape key to hide (but not show) the dynamic search field else if (document.activeElement === input && /Escape/i.test(event.key)) { toggleSearchField(); } }, true ); }; /** * If the user is on a Mac, use command (⌘) instead of control (ctrl) key * * Note: `navigator.platform` is deprecated; however MDN still recommends using * it for the one specific use case of detecting whether a keyboard shortcut * should use control or command: * https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform#examples */ var useCommandKey = navigator.platform.indexOf("Mac") === 0 || navigator.platform === "iPhone"; /** * Change the search hint to `meta key` if we are a Mac */ var changeSearchShortcutKey = () => { let shortcuts = document.querySelectorAll(".search-button__kbd-shortcut"); if (useCommandKey) { shortcuts.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; } }; /******************************************************************************* * Version Switcher * Note that this depends on two variables existing that are defined in * and `html-page-context` hook: * * - DOCUMENTATION_OPTIONS.pagename * - DOCUMENTATION_OPTIONS.theme_switcher_url */ /** * Check if corresponding page path exists in other version of docs * and, if so, go there instead of the homepage of the other docs version * * @param {event} event the event that trigger the check */ async function checkPageExistsAndRedirect(event) { // ensure we don't follow the initial link event.preventDefault(); let currentFilePath = `${DOCUMENTATION_OPTIONS.pagename}.html`; let tryUrl = event.currentTarget.getAttribute("href"); let otherDocsHomepage = tryUrl.replace(currentFilePath, ""); try { let head = await fetch(tryUrl, { method: "HEAD" }); if (head.ok) { location.href = tryUrl; // the page exists, go there } else { location.href = otherDocsHomepage; } } catch (err) { // something went wrong, probably CORS restriction, fallback to other docs homepage location.href = otherDocsHomepage; } } /** * Load and parse the version switcher JSON file from an absolute or relative URL. * * @param {string} url The URL to load version switcher entries from. */ async function fetchVersionSwitcherJSON(url) { // first check if it's a valid URL try { var result = new URL(url); } catch (err) { if (err instanceof TypeError) { // assume we got a relative path, and fix accordingly. But first, we need to // use `fetch()` to follow redirects so we get the correct final base URL const origin = await fetch(window.location.origin, { method: "HEAD" }); result = new URL(url, origin.url); } else { // something unexpected happened throw err; } } // load and return the JSON const response = await fetch(result); const data = await response.json(); return data; } // Populate the version switcher from the JSON data function populateVersionSwitcher(data, versionSwitcherBtns) { const currentFilePath = `${DOCUMENTATION_OPTIONS.pagename}.html`; versionSwitcherBtns.forEach((btn) => { // Set empty strings by default so that these attributes exist and can be used in CSS selectors btn.dataset["activeVersionName"] = ""; btn.dataset["activeVersion"] = ""; }); // in case there are multiple entries with the same version string, this helps us // decide which entry's `name` to put on the button itself. Without this, it would // always be the *last* version-matching entry; now it will be either the // version-matching entry that is also marked as `"preferred": true`, or if that // doesn't exist: the *first* version-matching entry. data = data.map((entry) => { // does this entry match the version that we're currently building/viewing? entry.match = entry.version == DOCUMENTATION_OPTIONS.theme_switcher_version_match; entry.preferred = entry.preferred || false; // if no custom name specified (e.g., "latest"), use version string if (!("name" in entry)) { entry.name = entry.version; } return entry; }); const hasMatchingPreferredEntry = data .map((entry) => entry.preferred && entry.match) .some(Boolean); var foundMatch = false; // create links to the corresponding page in the other docs versions data.forEach((entry) => { // create the node const anchor = document.createElement("a"); anchor.setAttribute( "class", "dropdown-item list-group-item list-group-item-action py-1" ); anchor.setAttribute("href", `${entry.url}${currentFilePath}`); anchor.setAttribute("role", "option"); const span = document.createElement("span"); span.textContent = `${entry.name}`; anchor.appendChild(span); // Add dataset values for the version and name in case people want // to apply CSS styling based on this information. anchor.dataset["versionName"] = entry.name; anchor.dataset["version"] = entry.version; // replace dropdown button text with the preferred display name of the // currently-viewed version, rather than using sphinx's {{ version }} variable. // also highlight the dropdown entry for the currently-viewed version's entry let matchesAndIsPreferred = hasMatchingPreferredEntry && entry.preferred; let matchesAndIsFirst = !hasMatchingPreferredEntry && !foundMatch && entry.match; if (matchesAndIsPreferred || matchesAndIsFirst) { anchor.classList.add("active"); versionSwitcherBtns.forEach((btn) => { btn.innerText = entry.name; btn.dataset["activeVersionName"] = entry.name; btn.dataset["activeVersion"] = entry.version; }); foundMatch = true; } // There may be multiple version-switcher elements, e.g. one // in a slide-over panel displayed on smaller screens. document.querySelectorAll(".version-switcher__menu").forEach((menu) => { // we need to clone the node for each menu, but onclick attributes are not // preserved by `.cloneNode()` so we add onclick here after cloning. let node = anchor.cloneNode(true); node.onclick = checkPageExistsAndRedirect; // on click, AJAX calls will check if the linked page exists before // trying to redirect, and if not, will redirect to the homepage // for that version of the docs. menu.append(node); }); }); } /******************************************************************************* * Warning banner when viewing non-stable version of the docs. */ /** * Show a warning banner when viewing a non-stable version of the docs. * * adapted 2023-06 from https://mne.tools/versionwarning.js, which was * originally adapted 2020-05 from https://scikit-learn.org/versionwarning.js * * @param {Array} data The version data used to populate the switcher menu. */ function showVersionWarningBanner(data) { var version = DOCUMENTATION_OPTIONS.VERSION; // figure out what latest stable version is var preferredEntries = data.filter((entry) => entry.preferred); if (preferredEntries.length !== 1) { const howMany = preferredEntries.length == 0 ? "No" : "Multiple"; console.log( `[PST] ${howMany} versions marked "preferred" found in versions JSON, ignoring.` ); return; } const preferredVersion = preferredEntries[0].version; const preferredURL = preferredEntries[0].url; // if already on preferred version, nothing to do const versionsAreComparable = validate(version) && validate(preferredVersion); if (versionsAreComparable && compare(version, preferredVersion, "=")) { return; } // now construct the warning banner var outer = document.createElement("aside"); // TODO: add to translatable strings outer.setAttribute("aria-label", "Version warning"); const middle = document.createElement("div"); const inner = document.createElement("div"); const bold = document.createElement("strong"); const button = document.createElement("a"); // these classes exist since pydata-sphinx-theme v0.10.0 outer.classList = "bd-header-version-warning container-fluid"; middle.classList = "bd-header-announcement__content"; inner.classList = "sidebar-message"; button.classList = "sd-btn sd-btn-danger sd-shadow-sm sd-text-wrap font-weight-bold ms-3 my-1 align-baseline"; button.href = `${preferredURL}${DOCUMENTATION_OPTIONS.pagename}.html`; button.innerText = "Switch to stable version"; button.onclick = checkPageExistsAndRedirect; // add the version-dependent text inner.innerText = "This is documentation for "; const isDev = version.includes("dev") || version.includes("rc") || version.includes("pre"); const newerThanPreferred = versionsAreComparable && compare(version, preferredVersion, ">"); if (isDev || newerThanPreferred) { bold.innerText = "an unstable development version"; } else if (versionsAreComparable && compare(version, preferredVersion, "<")) { bold.innerText = `an old version (${version})`; } else if (!version) { bold.innerText = "an unknown version"; // e.g., an empty string } else { bold.innerText = `version ${version}`; } outer.appendChild(middle); middle.appendChild(inner); inner.appendChild(bold); inner.appendChild(document.createTextNode(".")); inner.appendChild(button); const skipLink = document.getElementById("pst-skip-link"); skipLink.after(outer); } /******************************************************************************* * MutationObserver to move the ReadTheDocs button */ /** * intercept the RTD flyout and place it in the rtd-footer-container if existing * if not it stays where on top of the page */ function initRTDObserver() { const mutatedCallback = (mutationList, observer) => { mutationList.forEach((mutation) => { // Check whether the mutation is for RTD, which will have a specific structure if (mutation.addedNodes.length === 0) { return; } if (mutation.addedNodes[0].data === undefined) { return; } if (mutation.addedNodes[0].data.search("Inserted RTD Footer") != -1) { mutation.addedNodes.forEach((node) => { document.getElementById("rtd-footer-container").append(node); }); } }); }; const observer = new MutationObserver(mutatedCallback); const config = { childList: true }; observer.observe(document.body, config); } // fetch the JSON version data (only once), then use it to populate the version // switcher and maybe show the version warning bar var versionSwitcherBtns = document.querySelectorAll( ".version-switcher__button" ); const hasSwitcherMenu = versionSwitcherBtns.length > 0; const hasVersionsJSON = DOCUMENTATION_OPTIONS.hasOwnProperty( "theme_switcher_json_url" ); const wantsWarningBanner = DOCUMENTATION_OPTIONS.show_version_warning_banner; if (hasVersionsJSON && (hasSwitcherMenu || wantsWarningBanner)) { const data = await fetchVersionSwitcherJSON( DOCUMENTATION_OPTIONS.theme_switcher_json_url ); populateVersionSwitcher(data, versionSwitcherBtns); if (wantsWarningBanner) { showVersionWarningBanner(data); } } /** * Fix bug #1603 */ function fixMoreLinksInMobileSidebar() { const dropdown = document.querySelector( ".bd-sidebar-primary [id^=pst-nav-more-links]" ); dropdown.classList.add("show"); } /******************************************************************************* * Call functions after document loading. */ documentReady(addModeListener); documentReady(scrollToActive); documentReady(addTOCInteractivity); documentReady(setupSearchButtons); documentReady(initRTDObserver); documentReady(fixMoreLinksInMobileSidebar); PKֺ2X]7 7 ?pydata_sphinx_theme/assets/styles/abstracts/_accessibility.scss// loading the math module @use "sass:math"; /** * Get color combinations that meet a minimum contrast ratio as per WCAG 2 */ // @param {color} $bg - Background color of the element // @param {color} optional $target-color-contrast-dark $target-color-contrast-light - Target text colors, defaul to our // $foundation-black and $foundation-white colors // @return {color} $max-ratio-color - The color that has the highest contrast ratio // @function a11y-combination( $bg, $target-color-contrast-dark: $foundation-black, $target-color-contrast-light: $foundation-white, $min-contrast-ratio: $min-contrast-ratio-4 ) { // will test against the specified foreground colors $foregrounds: $target-color-contrast-light, $target-color-contrast-dark; $max-ratio: 0; $max-ratio-color: null; @each $fg in $foregrounds { $contrast-ratio: get-contrast-ratio($bg, $fg); @if $contrast-ratio >= $min-contrast-ratio { @return $fg; } @else if $contrast-ratio > $max-ratio { $max-ratio: $contrast-ratio; $max-ratio-color: $fg; } } @warn "Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$bg}..."; @return $max-ratio-color; } @function get-contrast-ratio($bg, $foreground) { $l1: luminance($bg); $l2: luminance($foreground); // return the relative contrast ratio @if $l1 > $l2 { @return math.div(($l1 + 0.05), ($l2 + 0.05)); } @else { @return math.div(($l2 + 0.05), ($l1 + 0.05)); } } // Return WCAG2.1 relative luminance // See https://www.w3.org/TR/WCAG/#dfn-relative-luminance // See https://www.w3.org/TR/WCAG/#dfn-contrast-ratio // @function luminance($target-color) { $rgb-col: ( "r": red($target-color), "g": green($target-color), "b": blue($target-color), ); @each $channel, $value in $rgb-col { // here we get RsRGB, GsRGB, and BsRGB @if math.div($value, 255) <=0.03928 { $rgb-col: map-merge( $rgb-col, ( $channel: math.div(math.div($value, 255), 12.92), ) ); } @else { $rgb-col: map-merge( $rgb-col, ( $channel: math.pow(math.div((math.div($value, 255) + 0.055), 1.055), 2.4), ) ); } } @return ( 0.2126 * map-get($rgb-col, "r") + 0.7152 * map-get($rgb-col, "g") + 0.0722 * map-get($rgb-col, "b") ); } PKֺ2X֗rMM5pydata_sphinx_theme/assets/styles/abstracts/_all.scss@import "accessibility"; @import "color"; @import "mixins"; @import "links"; PKֺ2XSJ  7pydata_sphinx_theme/assets/styles/abstracts/_color.scss/** * Miscellaneous color functions and mixins **/ // loading the math module @use "sass:math"; // We must add ::before pseudo-element to some theme components (such as admonitions) // because users were instructed to customize the background color this way. @mixin legacy-backdrop-placeholder { &:before { content: ""; width: 100%; height: 100%; position: absolute; left: 0; top: 0; z-index: -1; // So that hovering over the text within background is still possible. // Otherwise the background overlays the text and you cannot click or select easily. // ref: https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events pointer-events: none; } } /** * Function to get items from nested maps */ // @param {Map} $map - Map // @param {Arglist} $keys - Keys to fetc // @return {*} @function map-deep-get($map, $keys...) { @each $key in $keys { $map: map-get($map, $key); } @return $map; } /** * Function to check if the color needs converting to a "color" type * if it is a string we cannot use other color manipulation functions * It is used to create the sphinx-design colours as these are often interpolated */ // @param {String/Color} $color - Color definition from map // @return {Color} - Color type (in hex) @function check-color($color) { @if type-of($color) == string { $color: from-hex($color); } @return $color; } /** * Function to convert the string representation of a color to a color type (hex) */ // @param {String} $string - String representation of a color @function from-hex($string) { $string-lower: to-lower-case($string); $r: ""; $g: ""; $b: ""; $hex: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f"; $length: str-length($string); $max: if($length == 4, 1, 2); // Check for length accuracy @if $length != 4 and $length != 7 { @return $string; } // Loop from the second character (omitting #) @for $i from 2 through $length { $c: str-slice($string-lower, $i, $i); // If wrong character, return @if index($hex, $c) == null { @return $string; } @if str-length($r) < $max { $r: $r + $c; } @else if str-length($g) < $max { $g: $g + $c; } @else if str-length($b) < $max { $b: $b + $c; } } @if $length == 4 { $r: $r + $r; $g: $g + $g; $b: $b + $b; } @return rgb(_hex-to-dec($r), _hex-to-dec($g), _hex-to-dec($b)); } @function _hex-to-dec($string) { $hex: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f"; $string: to-lower-case($string); $length: str-length($string); $dec: 0; @for $i from 1 through $length { $factor: 1 + (15 * ($length - $i)); $index: index($hex, str-slice($string, $i, $i)); $dec: $dec + $factor * ($index - 1); } @return $dec; } PKֺ2X$Xp7pydata_sphinx_theme/assets/styles/abstracts/_links.scss/** * Consistent styling for links **/ // Define some useful variables for links styling consistency // // Thickness of the underline for links // the default will be either: // - 1px // - 0.0625rem if it's thicker than 1px because the user has changed the text // size in their browser $link-underline-thickness: unquote("max(1px, .0625rem)") !default; // Offset of link underlines from text baseline // The default is 3px expressed as ems, as calculated against the default body // font size (on desktop). $link-underline-offset: 0.1578em !default; // Thickness of link underlines in hover state // The default for each link will be the thickest of the following: // - 3px // - 0.1875rem, if it's thicker than 3px because the user has changed the text // size in their browser // - 0.12em (relative to the link's text size) $link-hover-decoration-thickness: unquote("max(3px, .1875rem, .12em)") !default; // Ensures links have an underline decoration by default - needed to meet // WCAG SC 1.4.1 @mixin link-decoration { text-decoration: underline; @if $link-underline-thickness { text-decoration-thickness: $link-underline-thickness; } @if $link-underline-offset { text-underline-offset: $link-underline-offset; } } // Ensures links have an underline decoration on hover - distinct from the // default behaviour @mixin link-decoration-hover { @if $link-hover-decoration-thickness { text-decoration-thickness: $link-hover-decoration-thickness; // Disable ink skipping on underlines on hover. Browsers haven't // standardised on this part of the spec yet, so set both properties text-decoration-skip-ink: none; // Chromium, Firefox text-decoration-skip: none; // Safari } } // Simple hover style - can be used alone or in conjunction with other mixins // Add the text underline and change in thickness on hover @mixin link-style-hover { &:hover { @include link-decoration; @include link-decoration-hover; color: var(--pst-color-link-hover); } } // Default link styles // // Defines: default unvisited, visited, hover, and active. // TODO: @trallard to improve focus styles in subsequent PR @mixin link-style-default { // So that really long links don't spill out of their container word-wrap: break-word; color: var(--pst-color-link); @include link-decoration; &:hover { color: var(--pst-color-link-hover); @include link-decoration-hover; } // TODO: @trallard to add active styles in subsequent PR &:active { color: var(--pst-color-link); } // Visited should still be hoverable &:visited { color: var(--pst-color-link); &:hover { color: var(--pst-color-link-hover); } } @include focus-indicator; } // Text link styles // // Makes links use the muted text colour and removes the underline. // Use this mixin for navigation bar links. @mixin link-style-text { color: var(--pst-color-text-muted); text-decoration: none; &:hover { color: var(--pst-color-link-hover); @include link-decoration; @include link-decoration-hover; } @include focus-indicator; } // Sidebar and TOC links // // Makes links use the muted text colour and removes the underline. // Use this mixin for navigation the primary sidebar and table of contents. // Active and hover should work together rather than one overriding the other. @mixin link-sidebar { color: var(--pst-color-text-muted); text-decoration: none; &:hover { text-decoration: underline; background-color: transparent; color: var(--pst-color-link-hover); @include link-decoration-hover; } // TODO: @trallard to update active styles in subsequent PR &:active { color: var(--pst-color-link-hover); } } // Sidebar current page link styles // // Adds a vertical line on the left hand side of the link to indicate that // it's the current page. Note this is distinct from an active state. // Used on the primary sidebar and the TOC. // We want the side box shadow to have the same thickness as the hover underline @mixin link-sidebar-current { font-weight: 600; color: var(--pst-color-primary); @if $link-hover-decoration-thickness { box-shadow: inset $link-hover-decoration-thickness 0px 0px var(--pst-color-primary); } } // Navigation bar current page link styles // // Adds a bottom underline, this leaves enough space for the hover state without // cluttering the navbar. // We want the side box shadow to have the same thickness as the hover underline @mixin link-navbar-current { font-weight: 600; color: var(--pst-color-primary); @if $link-hover-decoration-thickness { border-bottom: $link-hover-decoration-thickness solid var(--pst-color-primary); } } // Navigation bar icon links hover styles // // Adds a bottom box-shadow - since there is no text we cannot use text-decoration // We want the side box shadow to have the same thickness as the hover underline @mixin icon-navbar-hover { &:hover { color: var(--pst-color-link-hover); @if $link-hover-decoration-thickness { box-shadow: 0px $link-hover-decoration-thickness 0px var(--pst-color-link-hover); } } } // Focus indicator @mixin focus-indicator { &:focus-visible { outline: 2px solid var(--pst-color-accent); } } PKֺ2X݅8pydata_sphinx_theme/assets/styles/abstracts/_mixins.scss/********************************************* * SASS Mixins *********************************************/ /** * A consistent box shadow style we apply across elements. */ @mixin box-shadow() { box-shadow: 0 0.2rem 0.5rem var(--pst-color-shadow), 0 0 0.0625rem var(--pst-color-shadow) !important; } /** * Set background of some cell outputs to white-ish to make sure colors work * This is because many libraries make output that only looks good on white */ @mixin cell-output-background { color: var(--pst-color-on-background); background-color: var(--pst-color-text-base); border-radius: 0.25rem; padding: 0.5rem; } PKֺ2XU&Ν1pydata_sphinx_theme/assets/styles/base/_base.scsshtml { font-size: var(--pst-font-size-base); scroll-padding-top: calc(var(--pst-header-height) + 1rem); } body { background-color: var(--pst-color-background); font-family: var(--pst-font-family-base); font-weight: 400; line-height: 1.65; color: var(--pst-color-text-base); min-height: 100vh; display: flex; flex-direction: column; // hack to avoid the black background on some browser including Safari &::-webkit-scrollbar-track { background: var(--pst-color-background); } } p { margin-bottom: 1.15rem; font-size: 1em; color: var(--pst-color-text-base); /* section header in docstring pages */ &.rubric { border-bottom: 1px solid var(--pst-color-border); } &.centered { text-align: center; } } a { @include link-style-default; // The # anchor that appears on hover over headings &.headerlink { color: var(--pst-color-secondary); opacity: 0.7; font-size: 0.8em; padding: 0 4px 0 4px; margin-left: 0.2em; text-decoration: none; transition: all 0.2s ease-out; user-select: none; &:hover { opacity: 1; } } // set up a icon next to the shorten links from github and gitlab &.github, &.gitlab { &::before { color: var(--pst-color-text-muted); font: var(--fa-font-brands); margin-right: 0.25rem; } } &.github::before { content: var(--pst-icon-github); } &.gitlab::before { content: var(--pst-icon-gitlab); } } .heading-style { margin: 2.75rem 0 1.05rem; font-family: var(--pst-font-family-heading); font-weight: var(--pst-font-weight-heading); line-height: 1.15; } h1 { @extend .heading-style; margin-top: 0; font-size: var(--pst-font-size-h1); color: var(--pst-heading-color); } h2 { @extend .heading-style; font-size: var(--pst-font-size-h2); color: var(--pst-heading-color); } h3 { @extend .heading-style; font-size: var(--pst-font-size-h3); color: var(--pst-heading-color); } h4 { @extend .heading-style; font-size: var(--pst-font-size-h4); color: var(--pst-heading-color); } h5 { @extend .heading-style; font-size: var(--pst-font-size-h5); color: var(--pst-color-text-base); } h6 { @extend .heading-style; font-size: var(--pst-font-size-h6); color: var(--pst-color-text-base); } small, .text_small { font-size: var(--pst-font-size-milli); } hr { border: 0; border-top: 1px solid var(--pst-color-border); } pre, code, kbd, samp { font-family: var(--pst-font-family-monospace); } kbd { // use theme negative background-color: var(--pst-color-on-background); color: var(--pst-color-text-muted); // Compound keyboard elements will have nested kbd in them, so this prevents double lines &:not(.compound) { border: 1px solid var(--pst-color-border); margin: 0 0.1rem; padding: 0.1rem 0.4rem; box-shadow: 1px 1px 1px var(--pst-color-shadow); } } code { color: var(--pst-color-inline-code); } pre { margin: 1.5em 0 1.5em 0; padding: 1rem; background-color: var(--pst-color-surface); color: var(--pst-color-text-base); line-height: 1.2em; border: 1px solid var(--pst-color-border); border-radius: $admonition-border-radius; .linenos { // minimum opacity to make the line numbers WCAG AA conformant opacity: 0.8; padding-right: 10px; } } // the back to top btn #pst-back-to-top { z-index: $zindex-tooltip; position: fixed; display: none; top: 90vh; left: 50vw; transform: translate(-50%); color: var(--pst-color-secondary-text); background-color: var(--pst-color-secondary); border: none; } PKֺ2XoZ0pydata_sphinx_theme/assets/styles/bootstrap.scss// create a specific css file to build bootstrap css // the objective is to split css coming from bootstrap from the one coming from // the theme itself @import "variables/bootstrap"; @import "~bootstrap/scss/bootstrap"; PKֺ2X.  >pydata_sphinx_theme/assets/styles/components/_breadcrumbs.scss/** * Breadcrumbs for parent pages meant for the article header */ ul.bd-breadcrumbs { list-style: none; padding-left: 0; display: flex; flex-wrap: wrap; // Font size slightly smaller to avoid cluttering up space too much font-size: 0.8rem; li.breadcrumb-item { display: flex; align-items: center; // Style should look like heavier in-page links // keeping visited in the default link colour font-weight: bold; a { @include link-style-text; } // Items that aren't the home have a caret to the left &:not(.breadcrumb-home):before { font: var(--fa-font-solid); font-size: 0.8rem; content: var(--pst-breadcrumb-divider); color: var(--pst-color-text-muted); padding: 0 0.5rem; } } } PKֺ2Xc;tک=pydata_sphinx_theme/assets/styles/components/_icon-links.scss/** * Icon links in the navbar */ .navbar-icon-links { display: flex; flex-direction: row; column-gap: 1rem; flex-wrap: wrap; // Remove the padding so that we can define it with flexbox gap above li.nav-item a.nav-link { padding-left: 0; padding-right: 0; @include icon-navbar-hover; } // Spacing and centering a span { display: flex; align-items: center; } // Icons styling i { &.fa-brands, &.fa-regular, &.fa-solid { vertical-align: middle; font-style: normal; font-size: var(--pst-font-size-icon); } /* Social media buttons hard-code the brand color */ &.fa-square-twitter:before { color: #55acee; } &.fa-square-gitlab:before { color: #548; } &.fa-bitbucket:before { color: #0052cc; } } // Force images to be icon-sized img.icon-link-image { height: 1.5em; border-radius: 0.2rem; } } PKֺ2X(|p6:pydata_sphinx_theme/assets/styles/components/_indices.scss.sidebar-indices-items { display: flex; flex-direction: column; border-top: 1px solid var(--pst-color-border); @include media-breakpoint-up($breakpoint-sidebar-primary) { border-top: none; } .sidebar-indices-items__title { font-weight: var(--pst-sidebar-header-font-weight); font-size: var(--pst-sidebar-header-font-size); color: var(--pst-color-text-base); margin-bottom: 0.5rem; } ul.indices-link { margin-right: -1rem; list-style: none; padding: 0; li > a { display: block; padding: 0.25rem 0; color: var(--pst-color-text-muted); &:hover { color: var(--pst-color-primary); text-decoration: none; background-color: transparent; } } } } PKֺ2Xp,?pydata_sphinx_theme/assets/styles/components/_navbar-links.scss/** * Navigation text links in the navbar */ .navbar-nav { ul { display: block; list-style: none; // Reduce padding of nested `ul` items a bit ul { padding: 0 0 0 1rem; } } // Navbar links - do not have an underline by default li { display: flex; flex-direction: column; a { display: flex; align-items: center; height: 100%; padding-top: 0.25rem; padding-bottom: 0.25rem; @include link-style-text; } } /** * Togglable expand/collapse * This is only applicable to the primary sidebar which has these checkboxes */ .toctree-checkbox { position: absolute; display: none; } .toctree-checkbox { ~ ul { display: none; } ~ label .fa-chevron-down { transform: rotate(0deg); } } .toctree-checkbox:checked { ~ ul { display: block; } ~ label .fa-chevron-down { transform: rotate(180deg); } } } PKֺ2X)?;pydata_sphinx_theme/assets/styles/components/_page-toc.scss/** * The list of in-page TOC links */ .page-toc { .section-nav { padding-left: 0; border-bottom: none; ul { padding-left: 1rem; } } // override bootstrap settings .nav-link { font-size: var(--pst-sidebar-font-size-mobile); @include media-breakpoint-up($breakpoint-sidebar-secondary) { font-size: var(--pst-sidebar-font-size); } } .onthispage { color: var(--pst-color-text-base); font-weight: var(--pst-sidebar-header-font-weight); margin-bottom: 0.5rem; } } PKֺ2X߾<pydata_sphinx_theme/assets/styles/components/_prev-next.scss/** * Previous / Next navigation buttons **/ .prev-next-area { width: 100%; p { margin: 0 0.3em; line-height: 1.3em; } i { font-size: 1.2em; } a { // So that buttons align with icons display: flex; align-items: center; border: none; padding: 10px; max-width: 45%; overflow-x: hidden; color: var(--pst-color-text-muted); text-decoration: none; p.prev-next-title { @include link-style-default; font-weight: var(--pst-admonition-font-weight-heading); font-size: 1.1em; } &:hover p.prev-next-title { @include link-style-hover; } // Exception here - keep visited in the default link colour // it still should hover on the default link hover colour &:visited p.prev-next-title { color: var(--pst-color-link); &:hover { color: var(--pst-color-link-hover); } } .prev-next-info { flex-direction: column; margin: 0 0.5em; .prev-next-subtitle { text-transform: capitalize; } } &.left-prev { float: left; } &.right-next { float: right; div.prev-next-info { text-align: right; } } } } PKֺ2X !!Gpydata_sphinx_theme/assets/styles/components/_readthedocs-switcher.scss.bd-sidebar-primary div#rtd-footer-container { position: sticky; bottom: -1rem; margin: -1rem; // ignore sidebar padding .rst-versions.rst-badge { position: unset; font-size: 0.9em; font-family: var(--pst-font-family-base); max-width: unset; .rst-current-version { display: flex; align-items: center; gap: 0.2rem; height: 2.5rem; transition: background-color 0.2s ease-out; background-color: var(--pst-color-background); color: var(--pst-color-success); border-top: 1px solid var(--pst-color-border); } .fa.fa-book { color: var(--pst-color-text-muted); margin-right: auto; &::after { color: var(--pst-color-text-base); content: "Read The Docs"; font-family: var(--pst-font-family-base); font-weight: var(--pst-admonition-font-weight-heading); } } .fa.fa-caret-down { color: var(--pst-color-text-muted); } } .rst-versions.rst-badge.shift-up { .rst-current-version { border-bottom: 1px solid var(--pst-color-border); } } .rst-other-versions { background-color: var(--pst-color-surface); color: var(--pst-color-text-base); dl { dd a { color: var(--pst-color-text-muted); } } hr { background-color: var(--pst-color-border); } small a { color: var(--pst-color-link); } input { padding-left: 0.5rem; border: 1px solid var(--pst-color-border); background-color: var(--pst-color-surface); } } } PKֺ2X?r9pydata_sphinx_theme/assets/styles/components/_search.scss/** * Search field **/ .bd-search { position: relative; padding-left: 0.5rem; gap: 0.5rem; background-color: var(--pst-color-background); border-radius: $admonition-border-radius; border: 1px solid var(--pst-color-border); color: var(--pst-color-text-base); // Background should always be same color regardless of active or not &:active { background-color: var(--pst-color-background); color: var(--pst-color-text-muted); } .icon { position: absolute; color: var(--pst-color-border); left: 25px; } .fa-solid.fa-magnifying-glass { position: absolute; left: calc((2.5rem - 0.7em) / 2); color: var(--pst-color-text-muted); } input { // Inner-text of the search bar &::placeholder { color: var(--pst-color-text-muted); } // Remove the little "x" that pops up when you start typing &::-webkit-search-cancel-button, &::-webkit-search-decoration { -webkit-appearance: none; appearance: none; } } // Shows off the keyboard shortcuts for the button .search-button__kbd-shortcut { display: flex; position: absolute; right: 0.5rem; color: var(--pst-color-border); } } .form-control { background-color: var(--pst-color-background); color: var(--pst-color-text-base); &:focus, &:focus-visible { border: none; box-shadow: none; outline: 3px solid var(--pst-color-accent); background-color: var(--pst-color-background); color: var(--pst-color-text-muted); } } /** * Search button - located in the navbar */ // Search link icon should be a bit bigger since it is separate from icon links .search-button { display: flex; align-items: center; align-content: center; color: var(--pst-color-text-muted); border-radius: 0; @include icon-navbar-hover; @include focus-indicator; i { font-size: 1.3rem; } } // __search-container will only show up when we use the search pop-up bar .search-button__search-container, .search-button__overlay { display: none; } .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; padding-top: 0; padding-bottom: 0; } // Font and input text a bit bigger svg, input { font-size: var(--pst-font-size-icon); } } /** * The search button component that looks like a field. * Lives at components/search-button-field.html */ .search-button-field { display: inline-flex; align-items: center; border: var(--pst-color-border) solid 1px; border-radius: 1.5em; color: var(--pst-color-text-muted); padding: 0.5em; background-color: var(--pst-color-surface); &:hover { border: 2px solid var(--pst-color-link-hover); } &:focus-visible { border: 2px solid var(--pst-color-accent); } // The keyboard shotcut text .search-button__default-text { font-size: var(--bs-nav-link-font-size); font-weight: var(--bs-nav-link-font-weight); margin-right: 0.5em; margin-left: 0.5em; } .kbd-shortcut__modifier { font-size: 0.75em; } // Ensures that all the text lines up in the middle > * { align-items: center; } // Only the icon should be visible on narrow screens > :not(svg) { display: none; @include media-breakpoint-up(lg) { display: flex; } } } PKֺ2Xk::<pydata_sphinx_theme/assets/styles/components/_searchbox.scss/** * The 'Hide Search Matches' button. * This only shows up when a person lands on a page after clicking a search result. * Clicking it removes the highlighting of the search term from the page. * We want it to behave like a button. */ div#searchbox { // Leave `#searchbox` rules empty so that it doesn't show at all when it is empty p.highlight-link { margin: 1rem 0; width: fit-content; // A bit more margin on wide screens to mimic article behavior @include media-breakpoint-up($breakpoint-sidebar-secondary) { margin-left: 2rem; } // Put outer shadow on this one so that we can darken the link w/ an inner shadow @include box-shadow(); // Style the button to look like a Sphinx Design button a { border-radius: 0.25rem; font-size: 1.25rem; padding: 0.75rem; background-color: var(--pst-color-primary); color: var(--pst-color-primary-text); text-decoration: none; // The box shadow is inset so that it darkens the button on hover transition: box-shadow 0.25s ease-out; &:hover { box-shadow: inset 0px 0px 50px 50px rgba(0, 0, 0, 0.25); } &:before { content: var(--pst-icon-search-minus); color: unset; font: var(--fa-font-solid); margin-right: 0.5rem; } } } } PKֺ2X[ӼApydata_sphinx_theme/assets/styles/components/_switcher-theme.scss/** * Light/dark theme switcher */ .theme-switch-button { // overide bootstrap settings margin: 0 -0.5rem; padding: 0; // We pad the `span` not the container color: var(--pst-color-text-muted); border-radius: 0; @include focus-indicator; span { display: none; padding: 0.5em; @include icon-navbar-hover; &:active { text-decoration: none; color: var(--pst-color-link-hover); } } } html[data-mode="auto"] .theme-switch-button span[data-mode="auto"] { display: flex; } html[data-mode="light"] .theme-switch-button span[data-mode="light"] { display: flex; } html[data-mode="dark"] .theme-switch-button span[data-mode="dark"] { display: flex; } PKֺ2X~Cpydata_sphinx_theme/assets/styles/components/_switcher-version.scssbutton.btn.version-switcher__button { border-color: var(--pst-color-border); color: var(--pst-color-text-base); // Add a margin on narrow screens to avoid feeling cramped margin-bottom: 1em; @include media-breakpoint-up($breakpoint-sidebar-primary) { margin-bottom: unset; } @include link-style-hover; @include focus-indicator; &:active { color: var(--pst-color-text-base); border-color: var(--pst-color-border); } } .version-switcher__menu { border-color: var(--pst-color-border); border-radius: var(--bs-dropdown-border-radius); a.list-group-item { background-color: var(--pst-color-on-background); color: var(--pst-color-text-base); padding: 0.75rem 1.25rem; &:not(:last-child) { border-bottom: 1px solid var(--pst-color-border); } @include link-style-hover; &:hover { background-color: var(--pst-color-surface); } &.active { @include link-sidebar-current; position: relative; z-index: 1; span:before { content: ""; width: 100%; height: 100%; position: absolute; z-index: -1; left: 0; top: 0; } } } } // Font behavior on mobile button.version-switcher__button, .version-switcher__menu { font-size: 1.1em; // A bit smaller than other menu font z-index: $zindex-modal; // higher than the sidebars @include media-breakpoint-up($breakpoint-sidebar-primary) { font-size: unset; } } PKֺ2XV=pydata_sphinx_theme/assets/styles/components/_toc-inpage.scss/* Collapsing of the TOC sidebar while scrolling */ /* Nav: hide second level (shown on .active) */ nav.page-toc { // A little extra space before the buttons margin-bottom: 1rem; } .bd-toc .nav, .list-caption { .nav { display: none; // So we can manually specify a level as visible in the config &.visible { display: block; } } > .active > ul { display: block; } } // Each entry of the in-page TOC .toc-entry { display: block; a > code { color: var(--pst-color-text-muted); } a.nav-link { display: block; padding: 0.125rem 0; // Padding w/ negative margin so the top TOC item highlight overlaps w/ the TOC border padding-left: 1rem; margin-left: -1rem; @include link-sidebar; &.active { @include link-sidebar-current; background-color: transparent; &:hover { color: var(--pst-color-link-hover); } } } } PKֺ2XzBpydata_sphinx_theme/assets/styles/components/_versionmodified.scssdiv.versionadded, div.versionchanged, div.deprecated { vertical-align: middle; margin: 1.5625em auto; padding: 0 0.6rem 0 0.6rem; overflow: hidden; page-break-inside: avoid; border-left: 0.2rem solid; border-color: var(--pst-color-info); border-radius: $admonition-border-radius; background-color: var(--pst-color-on-background); @include box-shadow(); position: relative; > p { margin-bottom: 0.6rem; margin-top: 0.6rem; } } div.versionadded { border-color: var(--pst-color-success); background-color: var(--pst-color-success-bg); } div.versionchanged { border-color: var(--pst-color-warning); background-color: var(--pst-color-warning-bg); } div.deprecated { border-color: var(--pst-color-danger); background-color: var(--pst-color-danger-bg); } span.versionmodified { font-weight: 600; &:before { margin-right: 0.6rem; color: var(--pst-color-info); font: var(--fa-font-solid); content: var(--pst-icon-versionmodified-default); } } span.versionmodified.added { &:before { color: var(--pst-color-success); content: var(--pst-icon-versionmodified-added); } } span.versionmodified.changed { &:before { color: var(--pst-color-warning); content: var(--pst-icon-versionmodified-changed); } } span.versionmodified.deprecated { &:before { color: var(--pst-color-danger); content: var(--pst-icon-versionmodified-deprecated); } } PKֺ2XwEpydata_sphinx_theme/assets/styles/components/header/_header-logo.scss/** * Logo in the navbar */ .navbar-brand { position: relative; height: var(--pst-header-height); max-height: var(--pst-header-height); padding: 0.5rem 0; width: auto; margin: 0; display: flex; // Ensure that the logo stays the same length while other content shrinks flex-shrink: 0; align-items: center; gap: 0.5rem; // If there's no logo image, we use a p element w/ the site title p { margin-bottom: 0; } // If there's a logo, it'll be in an img block img { max-width: 100%; height: 100%; width: auto; } // remove underline from brand title on default state a { text-decoration: none; } &:hover { @include link-style-hover; } &:visited { &:hover { @include link-style-hover; } } } PKֺ2XbxLL;pydata_sphinx_theme/assets/styles/content/_admonitions.scss/** * Admonitions and blocks of styled content. * Admonitions CSS originally inspired by https://squidfunk.github.io/mkdocs-material/getting-started/ */ $admonition-border-radius: 0.25rem; div.admonition, .admonition { margin: 1.5625em auto; padding: 0 0.6rem 0.8rem 0.6rem; overflow: hidden; page-break-inside: avoid; border-left: 0.2rem solid; border-color: var(--pst-color-info); border-radius: $admonition-border-radius; background-color: var(--pst-color-on-background); @include box-shadow(); // Last item should have no spacing since we'll control that w/ padding *:last-child { margin-bottom: 0; } // Items after the title should be indented p.admonition-title ~ * { margin-left: 1.4rem; margin-right: 1.4rem; } // Lists need to have left margin so they don't spill into it > ol, > ul { margin-left: 1em; } // Defaults for all admonitions > .admonition-title { margin: 0 -0.6rem; padding: 0.4rem 0.6rem 0.4rem 2rem; font-weight: var(--pst-admonition-font-weight-heading); position: relative; @include legacy-backdrop-placeholder; background-color: var(--pst-color-info-bg); // now that we use solid colors we want the title on top z-index: 1; &:after { position: absolute; left: 0.5rem; width: 1rem; height: 1rem; color: var(--pst-color-info); font: var(--fa-font-solid); line-height: inherit; content: var(--pst-icon-admonition-default); opacity: 1; } // Next element after title needs some extra upper-space + * { margin-top: 0.4em; } } &.attention { border-color: var(--pst-color-attention); > .admonition-title { background-color: var(--pst-color-attention-bg); &:after { color: var(--pst-color-attention); content: var(--pst-icon-admonition-attention); } } } &.caution { border-color: var(--pst-color-warning); > .admonition-title { background-color: var(--pst-color-warning-bg); &:after { color: var(--pst-color-warning); content: var(--pst-icon-admonition-caution); } } } &.warning { border-color: var(--pst-color-warning); > .admonition-title { background-color: var(--pst-color-warning-bg); &:after { color: var(--pst-color-warning); content: var(--pst-icon-admonition-warning); } } } &.danger { border-color: var(--pst-color-danger); > .admonition-title { background-color: var(--pst-color-danger-bg); &:after { color: var(--pst-color-danger); content: var(--pst-icon-admonition-danger); } } } &.error { border-color: var(--pst-color-danger); > .admonition-title { background-color: var(--pst-color-danger-bg); &:after { color: var(--pst-color-danger); content: var(--pst-icon-admonition-error); } } } &.hint { border-color: var(--pst-color-success); > .admonition-title { background-color: var(--pst-color-success-bg); &:after { color: var(--pst-color-success); content: var(--pst-icon-admonition-hint); } } } &.tip { border-color: var(--pst-color-success); > .admonition-title { background-color: var(--pst-color-success-bg); &:after { color: var(--pst-color-success); content: var(--pst-icon-admonition-tip); } } } &.important { border-color: var(--pst-color-attention); > .admonition-title { background-color: var(--pst-color-attention-bg); &:after { color: var(--pst-color-attention); content: var(--pst-icon-admonition-important); } } } &.note { border-color: var(--pst-color-info); > .admonition-title { background-color: var(--pst-color-info-bg); &:after { color: var(--pst-color-info); content: var(--pst-icon-admonition-note); } } } &.seealso { border-color: var(--pst-color-success); > .admonition-title { background-color: var(--pst-color-success-bg); &:after { color: var(--pst-color-success); content: var(--pst-icon-admonition-seealso); } } } &.admonition-todo { border-color: var(--pst-color-secondary); > .admonition-title { background-color: var(--pst-color-secondary-bg); &:after { color: var(--pst-color-secondary); content: var(--pst-icon-admonition-todo); } } } /** * Special-case for a `sidebar` class that makes the admonition float to * the right like the {sidebar} directive. */ &.sidebar { max-width: 40%; float: right; clear: both; margin-left: 0.5rem; margin-top: 0; // Undo the .sidebar directive border border-width: 0 0 0 0.2rem; // TODO: these semantic-color-names border-color rules might no longer be // needed when we drop support for Sphinx 4 / docutils 0.17 &.attention, &.important { border-color: var(--pst-color-attention); } &.caution, &.warning { border-color: var(--pst-color-warning); } &.danger, &.error { border-color: var(--pst-color-danger); } &.hint, &.tip, &.seealso { border-color: var(--pst-color-success); } &.note, &.todo { border-color: var(--pst-color-info); } // No inner margin since we have less horizontal space w/ the sidebar p.admonition-title ~ * { margin-left: 0rem; margin-right: 0rem; } } } /************************************************************** * Similar content blocks that are not technically admonitions. */ /** * Topics and the {contents} directive */ // Docutils <= 0.17 div.topic, div.topic.contents, // Docutils >= 0.18 nav.contents, aside.topic { display: flex; flex-direction: column; background-color: var(--pst-color-surface); border-color: var(--pst-color-border); border-radius: $admonition-border-radius; padding: 1rem 1.25rem; @include box-shadow(); .topic-title { margin: 0 0 0.5rem 0; } // Over-ride text color to ensure enough contrast p { color: var(--pst-color-on-surface) !important; } // Over-ride large default padding ul.simple { padding-left: 1rem; ul { // So that sub-lists will have a bit less padding padding-left: 2em; } } } /** * Sidebar directive */ aside.sidebar { border: 1px solid var(--pst-color-border); background-color: var(--pst-color-surface); border-radius: $admonition-border-radius; // to match the admonition-styled sidebars: margin-left: 0.5rem; padding: 0; > *:last-child { padding-bottom: 1rem; } p.sidebar-title { position: relative; margin-bottom: 0; padding-top: 0.5rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--pst-color-border); font-family: var(--pst-font-family-heading); font-weight: var(--pst-admonition-font-weight-heading); } // Add margin to the first non-`.sidebar-title` item > *:not(.sidebar-title):first-child, > p.sidebar-title + * { margin-top: 1rem; } > * { padding-left: 1rem; padding-right: 1rem; } } /** * Rubrics look kind of like section headers */ p.rubric { display: flex; flex-direction: column; } /** * Seealso is kind of like a vertically-collapsed admonition */ .seealso dd { margin-top: 0; margin-bottom: 0; } PKֺ2X2 3pydata_sphinx_theme/assets/styles/content/_api.scss// Style API docs from sphinx' autodoc / autosummary /******************************************************************************* * Styling for field lists */ /* grey highlighting of 'parameter' and 'returns' field */ table.field-list { border-collapse: separate; border-spacing: 10px; margin-left: 1px; th.field-name { padding: 1px 8px 1px 5px; white-space: nowrap; background-color: var(--pst-color-surface); } /* italic font for parameter types */ td.field-body { p { font-style: italic; > strong { font-style: normal; } } /* reduced space around parameter description */ blockquote { border-left: none; margin: 0em 0em 0.3em; padding-left: 30px; } } } /******************************************************************************* * Styling for autosummary tables */ .table.autosummary { // The first column (with the signature) should not wrap td:first-child { white-space: nowrap; } } /* overriding basic.css to use our own monospace font */ .sig { font-family: var(--pst-font-family-monospace); } /* C++ specific styling - overriding the basic.css to avoid custom colors*/ .sig-inline.c-texpr, .sig-inline.cpp-texpr { font-family: unset; } .sig.c .k, .sig.c .kt, .sig.cpp .k, .sig.cpp .kt { color: var(--pst-color-text-base); } .sig.c .m, .sig.cpp .m { color: var(--pst-color-text-base); } .sig.c .s, .sig.c .sc, .sig.cpp .s, .sig.cpp .sc { color: var(--pst-color-text-base); } // addition // .sig.c .sig-name .n, // .sig.cpp .sig-name .n { // color: var(--pst-color-inline-code); // } .sig-name { color: var(--pst-color-inline-code); } .sig-param .o, .sig-param .default_value { color: var(--pst-color-text-muted); font-weight: normal; } // change target color for dark theme dt:target, span.highlighted { background-color: var(--pst-color-target); } .viewcode-back { font-family: var(--pst-font-family-base); } .viewcode-block:target { border-top: 1px solid var(--pst-color-border); border-bottom: 1px solid var(--pst-color-border); position: relative; background-color: var(--pst-color-target); } /******************************************************************************* * Styling for autosummary titles like "parameters" and "returns" */ // the API selector // from https://github.com/pradyunsg/furo/blob/main/src/furo/assets/styles/content/_api.sass#L6) dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) { //increase margin bottom after the dl elements margin-bottom: 3rem; dd { margin-left: 2rem; // Fix until this will be solved to Sphinx https://github.com/sphinx-doc/sphinx/issues/10815 & > dl.simple > dt { display: flex; } } dl.field-list { display: grid; grid-template-columns: unset; } dt.field-odd, dt.field-even { margin-top: 0.2rem; margin-bottom: 0.1rem; background-color: var(--pst-color-surface); } } PKֺ2XJ4pydata_sphinx_theme/assets/styles/content/_code.scss/** * Code block styling * Note that we inherit a lot of styling from Bootstrap so not many rules here. */ // General code block behavior // Unset bootstrap behavior div[class*="highlight-"], div.highlight, div.literal-block-wrapper { display: flex; flex-direction: column; width: unset; border-radius: $admonition-border-radius; } // Code blocks with captions // There's a wrapper when the code block has a title div.literal-block-wrapper { border: 1px solid var(--pst-color-border); border-radius: $admonition-border-radius; // This is where the title goes div.code-block-caption { margin: 0; border-bottom: 1px solid var(--pst-color-border); padding: 0.5rem; font-size: 1rem; font-weight: var(--pst-font-weight-caption); a.headerlink { font-size: inherit; } } // Remove the upper border radius since we want it to connect with the title // Remove the box shadow so the wrapper gets the shadow instead div[class*="highlight-"] { margin: 0; border-radius: 0; pre { border: none; box-shadow: none; } } } /** * In-line code */ code.literal { padding: 0.1rem 0.25rem; background-color: var(--pst-color-surface); border: 1px solid var(--pst-color-border); border-radius: 0.25rem; } a > code { color: var(--pst-color-inline-code-links); } // Fix for Sphinx's "highlight" directive - this is an issue with our accessible pygments theme // and the colour we are using for the background of the code blocks. html[data-theme="light"] .highlight .nf { color: #0078a1 !important; } // Minimum opacity needed for linenos to be WCAG AA conformant span.linenos { opacity: 0.8 !important; } PKֺ2X~447pydata_sphinx_theme/assets/styles/content/_figures.scssfigure { a.headerlink { // So that header link doesn't push caption to be off-center. position: absolute; font-size: inherit; } // Default headerlink hover doesn't trigger on figures &:hover a.headerlink { visibility: visible; } figcaption { font-family: var(--pst-font-family-heading); font-weight: var(--pst-font-weight-caption); color: var(--pst-color-text-muted); margin-left: auto; margin-right: auto; table.table { width: fit-content; margin-left: auto; margin-right: auto; } } } PKֺ2X萨9pydata_sphinx_theme/assets/styles/content/_footnotes.scss// For consistency, add bracket around footnotes/citations which are // cited more than once. E.g. [Newton](1,2) instead of Newton(1,2) dt.label > span.brackets:not(:only-child):before { content: "["; } dt.label > span.brackets:not(:only-child):after { content: "]"; } // Make footnote as a superscript a.footnote-reference { vertical-align: super; font-size: small; } // Docutils 0.18 uses an `aside.footnote` container with different internal structure aside.footnote { margin-bottom: 0.5rem; &:last-child { margin-bottom: 1rem; } span.label, span.backrefs { font-weight: bold; } &:target { background-color: var(--pst-color-target); } } PKֺ2Xk75pydata_sphinx_theme/assets/styles/content/_hacks.scss/** * Hacky fixes that don't fit cleanly into other sections */ // Ensure user highlighting/selecting behaves properly // From https://stackoverflow.com/a/34372191 table.highlighttable td.linenos, span.linenos, div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */ user-select: none; -webkit-user-select: text; /* Safari fallback only */ -webkit-user-select: none; /* Chrome/Safari */ -moz-user-select: none; /* Firefox */ -ms-user-select: none; /* IE10+ */ } PKֺ2Xi5pydata_sphinx_theme/assets/styles/content/_lists.scss// Override bootstrap by restoring the basic theme default. dd { margin-top: 3px; margin-bottom: 10px; margin-left: 30px; } ol, ul { padding-inline-start: 2rem; li > p:first-child { margin-bottom: 0.25rem; margin-top: 0.25rem; } } PKֺ2XH^4pydata_sphinx_theme/assets/styles/content/_math.scss/** * Mathematics via MathJax. * * This is designed for MathJax v3 * ref: https://www.sphinx-doc.org/en/master/usage/extensions/math.html#module-sphinx.ext.mathjax */ // Applies to all math elements span.math, div.math { align-items: center; display: flex; max-width: 100%; // This will be over-ridden for the y-direction and divs overflow: hidden; } // Inline-only span.math { display: inline-flex; } // Block-level only div.math { gap: 0.5em; // So that the eqno shows up after the equation flex-direction: row-reverse; // The equation number / link span.eqno a.headerlink { position: relative; font-size: 1em; } // The math container mjx-container { flex-grow: 1; padding-bottom: 0.2rem; overflow: auto; // Set height to 0 so that it does not cause scrollbars to appear // ref: https://github.com/mathjax/MathJax/issues/2521 mjx-assistive-mml { height: 0; } } } PKֺ2X}{{6pydata_sphinx_theme/assets/styles/content/_quotes.scss// GitHub blockquote style blockquote { padding: 1em 1em; color: var(--pst-color-text-muted); border-left: 0.25em solid var(--pst-color-border); border-radius: $admonition-border-radius; position: relative; p { color: var(--pst-color-text-base); } // remove padding from included line-block to avoid duplication .line-block { margin: 0 0; } // remove margin bottom for the last p p:last-child { margin-bottom: 0; } @include legacy-backdrop-placeholder; background-color: var(--pst-color-surface); //hack to make the text in the blockquote selectable &:before { z-index: -1; } } PKֺ2X'+5pydata_sphinx_theme/assets/styles/content/_spans.scss/** * Span-level styling within content */ span.guilabel { border: 1px solid var(--pst-color-info); color: var(--pst-color-info); font-size: 80%; font-weight: 700; border-radius: 4px; padding: 2.4px 6px; margin: auto 2px; position: relative; @include legacy-backdrop-placeholder; background-color: var(--pst-color-info-bg); } a.reference.download:before { content: var(--pst-icon-download); font: var(--fa-font-solid); font-size: 0.8em; padding: 0 0.25em; color: var(--pst-color-text-muted); } PKֺ2Xg_16pydata_sphinx_theme/assets/styles/content/_tables.scss/** * Tables */ // ensure table will fit in the article width and make them y-scrollable table { display: table; overflow: auto; // default to table-center margin-left: auto; margin-right: auto; &.table-right { margin-right: 0; } &.table-left { margin-left: 0; } } // customize table caption from bootstrap // to display them on top and centered table caption { text-align: center; caption-side: top; color: var(--pst-color-text-muted); } // MyST Markdown tables use these classes to control alignment th, td { &.text-align\:left { text-align: left; } &.text-align\:right { text-align: right; } &.text-align\:center { text-align: center; } } // override bootstrap background colors .table { --bs-table-bg: transparent; } PKֺ2XI7pydata_sphinx_theme/assets/styles/content/_toctree.scss/** * Style the toctree component in pages (avoid modifying the navbars) */ .toctree-wrapper { p.caption { font-size: 1.5em; margin-bottom: 0em; } & > ul { padding-left: 0; } li[class^="toctree-l"] { list-style: none; margin-bottom: 0.2em; & > a { list-style: none; font-size: 1.1em; } & > ul { list-style: none; padding-inline-start: 1.5em; } } // slightly bigger font for l1 .toctree-l1 > a { font-size: 1.3em; } } div.topic.contents, // Docutils <= 0.17 nav.contents // Docutils >= 0.18 { // Style similarly to toctree ul.simple { list-style: none; padding-left: 0; } } PKֺ2X   8pydata_sphinx_theme/assets/styles/extensions/_ablog.scss/** * ABlog * ref: https://ablog.readthedocs.io/ */ /** * Sidebar template components */ .ablog-sidebar-item { h2, h3 { font-size: var(--pst-sidebar-header-font-size); // Remove unnecessary vertical whitespace margin-top: 0.5rem; // The headers are all links, but this makes them hard to parse // So we change the colors to make them look like headers a { color: var(--pst-color-text-base); } } ul { // No bullet points for the primary sidebar items list-style: none; padding-left: 0; // Otherwise a scrollbar randomly shows up overflow-y: hidden; // List of recent post items display: flex; flex-direction: column; gap: 0.5em; margin-bottom: 0; // The ablog cloud should move horizontally &.ablog-cloud { flex-direction: row; flex-flow: wrap; gap: 0.5rem; // Vertical-align tag clouds li { // Center the tag cloud items display: flex; align-items: center; } } } } /** * Previous / next buttons at the bottom */ .ablog__prev-next { font-size: 1.2em; display: flex; padding: 1rem 0; // The bottom previous / next arrows > span { // To ensure that the whole thing fits on one line even if there are long titles display: flex; max-width: 45%; // Links within each span have the collection of icon + text a { display: flex; align-items: center; margin-left: auto; gap: 1rem; line-height: 1.5rem; i:before { color: var(--pst-color-text-base); } } } // The first span is for the previous page and aligns to the left span.ablog__prev { i.fa-arrow-circle-left:before { content: var(--pst-icon-angle-left); } } // The second span is just an empty space so we remove it because we're // positioning with flex span.ablog__spacer { display: none; } // The third span is aligned to the right span.ablog__next { margin-left: auto; text-align: right; i.fa-arrow-circle-right:before { content: var(--pst-icon-angle-right); } } } /** * {postlist} directive and posts page */ .ablog__collection, .postlist { padding-left: 0; .ablog-post { list-style: none; // Post metadata tags (author, links ,etc) should be a bit smaller .ablog-archive { display: flex; flex-direction: row; flex-wrap: wrap; gap: 1rem; list-style: none; font-size: 0.75rem; padding-left: 0; } // Title line should be a bit bigger and bold to stand out .ablog-post-title { margin-top: 0; font-size: 1.25rem; a { font-weight: bold; } } // Read more button should be a bit bigger .ablog-post-expand { margin-bottom: 0.5rem; } } } PKֺ2X V<pydata_sphinx_theme/assets/styles/extensions/_bootstrap.scss/** * Special cases for Bootstrap functionality */ // Bootstrap adds margin to their general container class. However, sphinx/docutils // can also generate output with the container class, but in those cases we should // not add the margin from bootstrap. Same for max-width. .docutils.container { padding-left: unset; padding-right: unset; margin-left: unset; margin-right: unset; max-width: unset; width: unset; } PKֺ2X Wi=pydata_sphinx_theme/assets/styles/extensions/_copybutton.scss/** * Sphinx Copybutton * ref: https://sphinx-copybutton.readthedocs.io/ */ div.highlight button.copybtn { // Nicer spacing display: flex; align-items: center; justify-content: center; // Removes the button background so we more naturally blend with the code cell. background-color: unset; // Don't over-ride the success color &:not(.success) { color: var(--pst-color-muted); } border: none; background-color: var(--pst-color-surface); &:hover { &:not(.success) { color: var(--pst-color-text); background-color: var(--pst-color-shadow); } } // Tooltip styling &.o-tooltip--left:after { color: var(--pst-color-text); background-color: var(--pst-color-surface); } } PKֺ2X977>pydata_sphinx_theme/assets/styles/extensions/_ethical-ads.scss// adapt ethical ad to the theme #ethical-ad-placement { .ethical-sidebar a, .ethical-sidebar a:visited, .ethical-sidebar a:hover, .ethical-sidebar a:active, .ethical-footer a, .ethical-footer a:visited, .ethical-footer a:hover, .ethical-footer a:active { color: var(--pst-color-text-base); } .ethical-sidebar, .ethical-footer { background-color: var(--pst-color-background); border: 1px solid var(--pst-color-border); border-radius: 5px; color: var(--pst-color-text-base); font-size: 14px; line-height: 20px; } } PKֺ2X f<pydata_sphinx_theme/assets/styles/extensions/_execution.scss/** * Styles for various Sphinx execution libraries. * For now, where these define output sections, we simply revert their background * to be a "light theme" background. This ensures that inputs/outputs behave similarly, * because the CSS is often controlled by each package. * In the future, we might add dark theme support for specific packages. */ /****************************************************************************** * Jupyter Sphinx */ .bd-content div.jupyter_container { // We don't want borders around the whole container, just around code cells border: none; background-color: unset; box-shadow: none; // Code cells should have the same style as our other code objects div.output, div.highlight { border-radius: 0.25rem; } div.highlight { background-color: var(--pst-color-surface); } // Ensure the style is the same as our code cells. Jupyter Sphinx makes it tiny. .cell_input, .cell_output { border-radius: 0.25rem; pre { padding: 1rem; } } } PKֺ2XUE :pydata_sphinx_theme/assets/styles/extensions/_leaflet.scss/** * style for the various mapping libs based on leaflet (folium, geemap, ipyleaflet) * mainly ensure the good display of the maps in both themes and avoid the customization * of the tiles */ /** * avoid border override from pydata-sphinx-theme * minimal selctor to get the priority */ html[data-theme="dark"] .bd-content img.leaflet-tile.leaflet-tile-loaded { border-radius: 0; padding: 0; } PKֺ2X@0dLL<pydata_sphinx_theme/assets/styles/extensions/_notebooks.scss/** * Styles for various Sphinx execution libraries to display pre-executed notebooks. * For now, where these define output sections, we simply revert their background * to be a "light theme" background. This ensures that inputs/outputs behave similarly, * because the CSS is often controlled by each package. * In the future, we might add dark theme support for specific packages. */ /******************************************************************************* * nbsphinx */ html div.rendered_html // NBsphinx ipywidgets output selector html .jp-RenderedHTMLCommon { table { table-layout: auto; } } // Dark theme special-cases html[data-theme="dark"] .bd-content { .nboutput { .output_area.rendered_html { @include cell-output-background; } .output_area.stderr { background: var(--pst-color-danger); } } } // Add extra padding to the final item in an nbsphinx container div.nblast.container { margin-bottom: 1rem; } /******************************************************************************* * myst NB */ div.cell_output .output { max-width: 100%; overflow-x: auto; } // Dark theme special-cases html[data-theme="dark"] .bd-content { div.cell_output { img, .text_html { @include cell-output-background; } } } // Prevent tables from scrunching together .bd-content { div.cell_input { display: flex; flex-direction: column; justify-content: stretch; } div.cell_input, div.output { border-radius: $admonition-border-radius; } div.output { table { table-layout: auto; } } } PKֺ2Xk9pydata_sphinx_theme/assets/styles/extensions/_pydata.scss/** * Special-cases for packages in the PyData ecosystem */ // xarray output display in bootstrap .xr-wrap[hidden] { display: block !important; } PKֺ2Xz;A "!"!@pydata_sphinx_theme/assets/styles/extensions/_sphinx_design.scss/******************************************************************************* * Special-cases for the sphinx-design library, mainly to make it compatible * with the dark/light themes of pydata-sphinx-theme. * * NOTE: sphinx-design uses !important quite liberally, so here we must do the * same for our overrides to have any effect. */ @use "../variables/color" as pst-color; @use "sass:meta"; @use "sass:color"; /******************************************************************************* * Color and variables * * This is a list of the semantic color names from sphinx-design (we only * need to override variables that sphinx-design has actually defined). * https://github.com/executablebooks/sphinx-design/blob/9226a12a/style/_colors.scss#L31-L43 */ $sd-semantic-color-names: ( "primary", "secondary", "success", "info", "warning", "danger", "light", "muted", "dark", "black", "white" ); /** * Here we create some extra --pst-color-* variables and use * them to override the value of the corresponding sphinx-design variables. * This is easier than re-writing the sphinx-design rules. Even easier would be * directly assigning our values to the --sd-color-* variables, but then our * downstream users couldn't override *our* colors and have it affect buttons * and badges. * * First, define the extra keys needed to cover the full range of semantic * color names used in sphinx-design, then merge them with the names we * already define for our own needs. * see https://sphinx-design.readthedocs.io/en/latest/css_variables.html */ $extra-semantic-colors: ( "white": $foundation-white, "light": ( light: $foundation-light-gray, bg-light: color.scale($foundation-light-gray, $lightness: 30%), dark: $foundation-light-gray, bg-dark: color.scale($foundation-light-gray, $lightness: -30%), ), "muted": ( light: $foundation-muted-gray, bg-light: color.scale($foundation-muted-gray, $lightness: 30%), dark: $foundation-light-gray, bg-dark: color.scale($foundation-muted-gray, $lightness: -30%), ), "dark": $foundation-dark-gray, "black": $foundation-black, ); $all-colors: map-merge($pst-semantic-colors, $extra-semantic-colors); @mixin create-sd-colors($value, $name) { // define the pst variables, so that downstream user overrides will work --pst-color-#{$name}: #{$value}; // we are now using a11y-combination to calculate the text color - this is based // on the WCAG color contrast guidelines --pst-color-#{$name}-text: #{a11y-combination($value)}; //TODO: highlight seems to be used for buttons @trallard to fix on a11y follow-up work --pst-color-#{$name}-highlight: #{darken($value, 15%)}; // override the sphinx-design variables --sd-color-#{$name}: var(--pst-color-#{$name}); --sd-color-#{$name}-text: var(--pst-color-#{$name}-text); //TODO: highlight seems to be used for buttons @trallard to fix on a11y follow-up work --sd-color-#{$name}-highlight: var(--pst-color-#{$name}-highlight); } // Now we override the --sd-color-* variables. @each $mode in (light, dark) { html[data-theme="#{$mode}"] { // check if this color is defined differently for light/dark @each $name in $sd-semantic-color-names { $definition: map-get($all-colors, $name); @if type-of($definition) == map { @each $key, $value in $definition { @if str-index($key, $mode) != null { // since now we define the bg colours in the semantic colours and not // by changing opacity, we need to check if the key contains bg and the // correct mode (light/dark) @if str-index($key, "bg") != null { --sd-color-#{$name}-bg: #{$value}; // create local variable $bg-var: --sd-color-#{$name}-bg; $value: check-color($value); --sd-color-#{$name}-bg-text: #{a11y-combination($value)}; } @else { $value: check-color($value); @include create-sd-colors($value, $name); } } } } @else { $value: map-get($all-colors, $name); @include create-sd-colors($value, $name); } } } } // Make sure the color border variables are set using our variables @each $mode in (light, dark) { html[data-theme="#{$mode}"] { --sd-color-card-border: var(--pst-color-border); } } /******************************************************************************* * shadows */ html[data-theme="light"] { .sd-shadow-xs, .sd-shadow-sm, .sd-shadow-md, .sd-shadow-lg { @include box-shadow(); } } /******************************************************************************* * cards */ .bd-content .sd-card { border: 1px solid var(--pst-color-border); // TODO - --pst-color-panel-background is not defined... where is this coming from? .sd-card-header { background-color: var(--pst-color-panel-background); border-bottom: 1px solid var(--pst-color-border); } .sd-card-footer { background-color: var(--pst-color-panel-background); border-top: 1px solid var(--pst-color-border); } .sd-card-body { background-color: var(--pst-color-panel-background); } } /******************************************************************************* * tabs */ .bd-content .sd-tab-set { > input { // Active tab label &:checked + label { border-color: transparent transparent var(--pst-color-primary); // top LR bottom color: var(--pst-color-primary); } // Hover label &:not(:checked) + label:hover { border-color: var(--pst-color-secondary); color: var(--pst-color-secondary); } } // Tab label > label { color: var(--pst-color-text-muted); border-top: 0.125rem solid transparent; // so hover isn't just color change padding-top: 0.5em; // same as bottom padding, so hover overline looks OK // Hovered label html &:hover { color: var(--pst-color-secondary); border-color: var(--pst-color-secondary); } } } /******************************************************************************* * Dropdowns */ details.sd-dropdown { // Remove all borders to over-ride SD behavior, and we'll add our own later border: 0px !important; summary.sd-card-header { border: 0 !important; & + div.sd-summary-content { border: 0; } } // Drop shadow should behave same as admonitions @include box-shadow(); // Header is where the "clickable" box goes summary.sd-card-header { display: flex; align-items: center; position: relative; // So background color works font-weight: 600; padding-top: 0.5rem; padding-bottom: 0.5rem; // Set a variable that we can re-use for colors later // We must set this in the current and content sibling container // so that it is defined in both places --pst-sd-dropdown-color: var(--pst-gray-500); --pst-sd-dropdown-bg-color: var(--pst-color-surface); & + div.sd-summary-content { --pst-sd-dropdown-color: var(--sd-color-card-border); } @each $name in $sd-semantic-color-names { &.sd-bg-#{$name} { --pst-sd-dropdown-color: var(--sd-color-#{$name}); --pst-sd-dropdown-bg-color: var(--sd-color-#{$name}-bg); // Otherwise it won't be defined in the sibling element & + div.sd-summary-content { --pst-sd-dropdown-color: var(--sd-color-#{$name}); --pst-sd-dropdown-bg-color: var(--sd-color-#{$name}-bg); } } &.sd-bg-text-#{$name} { // Use the WCAG conformant text color color: var(--sd-color-#{$name}-bg-text) !important; } } @include legacy-backdrop-placeholder; background-color: var(--pst-sd-dropdown-bg-color) !important; // Add a left border with the same structure as our admonitions border-left: 0.2rem solid var(--pst-sd-dropdown-color) !important; & + div.sd-summary-content { border-left: 0.2rem solid var(--pst-sd-dropdown-color) !important; border-bottom-left-radius: calc(0.25rem - 1px); background-color: var(--pst-color-on-background); } span.sd-summary-icon { display: inline-flex; align-items: center; color: var(--pst-sd-dropdown-color) !important; svg { opacity: 1; } } // Positioning of the caret .sd-summary-up, .sd-summary-down { top: 0.7rem; } } } PKֺ2Xi7MM?pydata_sphinx_theme/assets/styles/extensions/_togglebutton.scss/** * Sphinx togglebutton */ .bd-content { // Admonition toggles .admonition { button.toggle-button { color: inherit; } } // Details buttons details.toggle-details { // Over-ride border color to re-use our primary color summary { border-left: 3px solid var(--pst-color-primary); } } } PKֺ2Xhw4pydata_sphinx_theme/assets/styles/pages/_search.scss/** * /search.html page special-cases */ .bd-search-container { /******************************************* * Search results */ // Whitespace div#search-results { > h2 { font-size: var(--pst-font-size-icon); margin-top: 0; } p.search-summary { color: var(--pst-color-text-muted); } } ul.search { margin: 0; list-style: none; li { background-image: none; padding: 1rem 0; margin: 1rem 0; border-top: 1px solid var(--pst-color-text-muted); // First link is the page title, it should be a bit bigger > a { font-size: 1.2em; } div.context, p.context { color: var(--pst-color-text-base); margin: 0.5em 0 0 0; // Add a # before page section titles to make it clear they are sections a:before { content: "#"; padding-right: 0.2em; color: var(--pst-color-text-muted); } } } } } PKֺ2X^^  :pydata_sphinx_theme/assets/styles/pydata-sphinx-theme.scss// Import Bootstrap core @import "~bootstrap/scss/functions"; @import "variables/bootstrap"; @import "~bootstrap/scss/variables"; @import "~bootstrap/scss/mixins"; // Variables @import "variables/layout"; @import "variables/fonts"; @import "variables/icons"; @import "variables/admonitions"; @import "variables/versionmodified"; @import "variables/color"; // re-usable SCSS functions / classes @import "abstracts/all"; // Basic styling applied throughout site @import "./base/base"; // Major theme layout, skeleton, and whitespace @import "./sections/skip-link"; @import "./sections/container"; @import "./sections/announcement"; @import "./sections/article"; @import "./sections/footer"; @import "./sections/footer-article"; @import "./sections/footer-content"; @import "./sections/header"; @import "./sections/header-article"; @import "./sections/sidebar-primary"; @import "./sections/sidebar-secondary"; @import "./sections/sidebar-toggle"; // Re-usable components across the theme @import "./components/breadcrumbs"; @import "./components/icon-links"; @import "./components/header/header-logo"; @import "./components/navbar-links"; @import "./components/page-toc"; @import "./components/prev-next"; @import "./components/search"; @import "./components/searchbox"; @import "./components/switcher-theme"; @import "./components/switcher-version"; @import "./components/toc-inpage"; @import "./components/versionmodified"; @import "./components/indices"; @import "./components/readthedocs-switcher"; // Content blocks in standard Sphinx @import "./content/admonitions"; @import "./content/api"; @import "./content/code"; @import "./content/figures"; @import "./content/footnotes"; @import "./content/hacks"; @import "./content/lists"; @import "./content/quotes"; @import "./content/spans"; @import "./content/tables"; @import "./content/toctree"; @import "./content/math"; // Content blocks from Sphinx extensions @import "./extensions/ablog"; @import "./extensions/bootstrap"; @import "./extensions/copybutton"; @import "./extensions/ethical-ads"; @import "./extensions/execution"; @import "./extensions/pydata"; @import "./extensions/sphinx_design"; @import "./extensions/togglebutton"; @import "./extensions/notebooks"; @import "./extensions/leaflet"; // Page-specific CSS @import "./pages/search"; PKֺ2X\~~=pydata_sphinx_theme/assets/styles/sections/_announcement.scss.bd-header-version-warning, .bd-header-announcement { min-height: 3rem; width: 100%; display: flex; position: relative; align-items: center; justify-content: center; text-align: center; padding: 0.5rem 12.5%; // Horizontal padding so the width is 75% // One breakpoint less than $breakpoint-sidebar-primary. See variables/_layout.scss for more info. @include media-breakpoint-down(lg) { // Announcements can take a bit more width on mobile padding: 0.5rem 2%; } p { font-weight: bold; margin: 0; } &:after { position: absolute; width: 100%; height: 100%; left: 0; top: 0; content: ""; z-index: -1; // So it doesn't hover over the content } &:empty { display: none; } // Ensure there is enough contrast against the background a { color: var(--pst-color-inline-code-links); } } // Bg color is now defined in the theme color palette - using our secondary color .bd-header-announcement { &:after { background-color: var(--pst-color-secondary-bg); } } .bd-header-version-warning { &:after { background-color: var(--pst-color-danger-bg); } } PKֺ2XW8pydata_sphinx_theme/assets/styles/sections/_article.scss/** * Main content area */ .bd-main { flex-grow: 1; flex-direction: column; display: flex; min-width: 0; .bd-content { display: flex; justify-content: center; height: 100%; .bd-article-container { justify-content: start; display: flex; flex-direction: column; // Max-width is slightly more than the W3 since our docs often have images. // We shoot for about 100 characters per line instead of 80. // ref: https://www.w3.org/WAI/tutorials/page-structure/styling/#line-length width: 100%; max-width: 60em; overflow-x: auto; // Prevent wide content from pushing off the secondary sidebar padding: 1rem; .bd-article { // Give a bit more verticle spacing on wide screens @include media-breakpoint-up($breakpoint-sidebar-secondary) { padding-top: 1.5rem; padding-left: 2rem; } } } } } PKֺ2XtSg:pydata_sphinx_theme/assets/styles/sections/_container.scss.bd-container { flex-grow: 1; display: flex; justify-content: center; .bd-container__inner { display: flex; } } .bd-page-width { width: 100%; @include media-breakpoint-up(lg) { max-width: $breakpoint-page-width; } } PKֺ2X*yy?pydata_sphinx_theme/assets/styles/sections/_footer-article.scss.bd-footer-article { margin-top: auto; .footer-article-items { display: flex; flex-direction: column; } } PKֺ2Xmzz?pydata_sphinx_theme/assets/styles/sections/_footer-content.scss.bd-footer-content { .footer-content-items { display: flex; flex-direction: column; margin-top: auto; } } PKֺ2XBn777pydata_sphinx_theme/assets/styles/sections/_footer.scss.bd-footer { width: 100%; border-top: 1px solid var(--pst-color-border); .bd-footer__inner { display: flex; flex-grow: 1; padding: 1rem; margin: auto; } .footer-items__start, .footer-items__center, .footer-items__end { display: flex; flex-direction: column; gap: 0.5rem; justify-content: center; flex-grow: 1; } .footer-items__center { text-align: center; } .footer-items__end { text-align: end; } // So that paragraphs don't take up extra room .footer-item p { margin-bottom: 0; } } PKֺ2XZ?pydata_sphinx_theme/assets/styles/sections/_header-article.scss.header-article__inner { display: flex; padding: 0 0.5rem; // The items define the height so that it disappears if there are no items .header-article-item { min-height: var(--pst-header-article-height); height: var(--pst-header-article-height); } .header-article-items__start, .header-article-items__end { display: flex; align-items: start; gap: 0.5rem; } .header-article-items__end { margin-left: auto; } } PKֺ2Xδt.7pydata_sphinx_theme/assets/styles/sections/_header.scss/** * Header at the top of the page * It includes the announcement bar and the navigation bar. */ // Styling for the Icon links can be found in components/_icon-links.scss // If we want the shadow to only point downward in the future, set // box-shadow to: 0 0.125rem 0.25rem -0.125rem rgba(0, 0, 0, 0.11); .bd-header { position: sticky; top: 0; z-index: $zindex-fixed; // Overrides bootstrap background: var(--pst-color-on-background) !important; box-shadow: 0 0.125rem 0.25rem 0 var(--pst-color-shadow); width: 100%; padding: 0; max-width: 100vw; justify-content: center; .bd-header__inner { display: flex; align-items: center; height: fit-content; padding-left: 1rem; padding-right: 1rem; } // These items will define the height of the header .navbar-item { height: var(--pst-header-height); max-height: var(--pst-header-height); display: flex; align-items: center; } // Hide the header items on mobile .navbar-header-items { display: none; flex-shrink: 1; @include media-breakpoint-up($breakpoint-sidebar-primary) { display: flex; flex-grow: 1; padding: 0 0 0 0.5rem; } } .navbar-header-items__end, .navbar-header-items__center, .navbar-header-items__start { display: flex; align-items: center; flex-flow: wrap; // In case we wrap our items to multiple rows on small screens row-gap: 0; } .navbar-header-items__end, .navbar-header-items__center { column-gap: 1rem; } // A little smaller because this is displayed by default on mobile .navbar-header-items__start { flex-shrink: 0; margin-right: auto; gap: 0.5rem; } .navbar-header-items__end { // End navbar items should snap to the right justify-content: end; } // Contains the navigation links within the navbar .navbar-nav { display: flex; @include media-breakpoint-up($breakpoint-sidebar-primary) { // Center align on wide screens so the dropdown button is centered properly align-items: center; } li a.nav-link { @include link-style-text; } // Current page is always underlined in the navbar > .current > .nav-link { @include link-navbar-current; } // Dropdowns for the extra links .dropdown { button { display: unset; color: var(--pst-color-text-muted); border: none; @include link-style-hover; @include focus-indicator; } .dropdown-menu { z-index: $zindex-popover; border: 1px solid var(--pst-color-border); box-shadow: 0 0 0.3rem 0.1rem var(--pst-color-shadow); background-color: var(--pst-color-on-background); padding: 0.5rem 0; margin: 0.5rem 0; min-width: 20rem; .dropdown-item { // Give the items in the dropdown some breathing room but let the hit // and hover area of the items extend to the edges of the menu padding: 0.25rem 1.5rem; // Override Bootstrap &:focus:not(:hover):not(:active) { background-color: inherit; } } // Hide the menu unless show has been clicked &:not(.show) { display: none; } } } } } // inline the element in the navbar as long as they fit and use display block when collapsing @include media-breakpoint-up($breakpoint-sidebar-primary) { .navbar-center-items .navbar-item { display: inline-block; } } .nav-link { @include link-style-hover; // Override Bootstrap transition: none; &.nav-external:after { font: var(--fa-font-solid); content: var(--pst-icon-external-link); font-size: 0.75em; margin-left: 0.3em; } } .bd-navbar-elements li.nav-item i { font-size: 0.7rem; padding-left: 2px; vertical-align: middle; } /** * Showing and hiding the sidebar toggle buttons and header items */ // Hide the header items on mobile .bd-header { // Toggle labels label { &.sidebar-toggle { display: flex; cursor: pointer; font-size: var(--pst-font-size-icon); align-items: center; color: var(--pst-color-muted); margin-bottom: 0; padding-bottom: 0.25rem; } &.primary-toggle { margin-right: 1rem; @include media-breakpoint-up($breakpoint-sidebar-primary) { display: none; } } &.secondary-toggle { margin-left: 1rem; @include media-breakpoint-up($breakpoint-sidebar-secondary) { display: none; } } @include icon-navbar-hover; @include focus-indicator; } // Hide the navbar header items on mobile because they're in the sidebar .navbar-header-items { display: none; @include media-breakpoint-up($breakpoint-sidebar-primary) { display: inherit; } } } // THe elements next to the hamburger menu only show on narrow screens .navbar-persistent--mobile { margin-left: auto; @include media-breakpoint-up($breakpoint-sidebar-primary) { display: none; } } // The navbar-persistent content should only show on wide screens .navbar-persistent--container { display: none; @include media-breakpoint-up($breakpoint-sidebar-primary) { display: flex; } } PKֺ2X_I  @pydata_sphinx_theme/assets/styles/sections/_sidebar-primary.scss/** * The primary sidebar on the left. * e.g., between-pages navigation. */ .bd-sidebar-primary { display: flex; flex-direction: column; gap: 1rem; max-height: calc(100vh - var(--pst-header-height)); position: sticky; top: var(--pst-header-height); @include make-col(3); // Borders padding and whitespace padding: 2rem 1rem 1rem 1rem; border-right: 1px solid var(--pst-color-border); background-color: var(--pst-color-background); overflow-y: auto; font-size: var(--pst-sidebar-font-size-mobile); @include media-breakpoint-up($breakpoint-sidebar-primary) { font-size: var(--pst-sidebar-font-size); } // override bootstrap when navlink are displayed in the sidebar .nav-link { font-size: var(--pst-sidebar-font-size-mobile); } &.no-sidebar { border-right: 0; } &.hide-on-wide { @include media-breakpoint-up($breakpoint-sidebar-primary) { display: none; } } // Headers shouldn't be colored in the sidebars and some extensions add headers h1, h2, h3, h4 { color: var(--pst-color-text-base); } .sidebar-primary-items__start, .sidebar-primary-items__end { .sidebar-primary-item { padding: 0.5rem 0; } } // Hide the sidebar header items on widescreen since they are visible in the header .sidebar-header-items { display: flex; flex-direction: column; .sidebar-header-items__title { font-weight: var(--pst-sidebar-header-font-weight); font-size: var(--pst-sidebar-header-font-size); color: var(--pst-color-text-base); margin-bottom: 0.5rem; } // The dropdown toggle for extra links just shows them all instead. .nav-item.dropdown { // On mobile, the dropdown behaves like any other link, no hiding button { display: none; } .dropdown-menu { display: flex; flex-direction: column; padding: 0; margin: 0; border: none; background-color: inherit; font-size: inherit; } } // Center header items get displayed vertically, end items are displayed horizontally .sidebar-header-items__center { display: flex; flex-direction: column; } // Positioning end items .sidebar-header-items__end { display: flex; align-items: center; gap: 0.5rem; } @include media-breakpoint-up($breakpoint-sidebar-primary) { display: none; } } .sidebar-primary-items__start { // Add a border on mobile to separate it from the header sidebar area border-top: 1px solid var(--pst-color-border); @include media-breakpoint-up($breakpoint-sidebar-primary) { border-top: none; } } .sidebar-primary-items__end { margin-top: auto; margin-bottom: 1em; } .list-caption { list-style: none; padding-left: 0px; } li { position: relative; // If it has children, add a bit more padding to wrap the content to avoid // overlapping with the PyData Sphinx Theme %(theme_version)s.Created using Sphinx %(sphinx_version)s.EditEdit on %(provider)sErrorGeneral IndexGlobal Module IndexHomeIndicesLast updated on %(last_updated)s.On this pagePlease activate JavaScript to enable the search functionality.Python Module IndexSearchSection NavigationShow SourceSite NavigationSkip to main contentlight/darknextnext pagepreviousprevious page© Copyright %(copyright)s.© Copyright %(copyright)s.Project-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2023-12-21 07:30-0700 PO-Revision-Date: 2023-04-14 14:57+0000 Last-Translator: Oriol Abril-Pla , 2023 Language: ca Language-Team: Catalan (https://app.transifex.com/12rambau/teams/166811/ca/) Plural-Forms: nplurals=2; plural=(n != 1) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.8.0 Ruta de navegacióConstruïda amb el Tema PyData Sphinx %(theme_version)s.Creada amb Sphinx %(sphinx_version)s.EditaEdita a %(provider)sErrorÍndex generalÍndex Global de MòdulsIniciÍndexsÚltima actualització el %(last_updated)s.Continguts de la pàginaActiveu JavaScript per habilitar la funcionalitat de cerca.Índex de Mòduls PythonCerca al webNavegació de la SeccióMostra el fitxer d'origenNavegació del llocSalta al contingut principalclar/foscsegüentpàgina següentanteriorpàgina anterior© Copyright %(copyright)s.© Copyright %(copyright)s.PKֺ2XIo''3pydata_sphinx_theme/locale/ca/LC_MESSAGES/sphinx.po# English translations for pydata-sphinx-theme. # Copyright (C) 2023 PyData developers # This file is distributed under the same license as the pydata-sphinx-theme # project. # # Translators: # Oriol Abril-Pla , 2023 msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2023-12-21 07:30-0700\n" "PO-Revision-Date: 2023-04-14 14:57+0000\n" "Last-Translator: Oriol Abril-Pla , 2023\n" "Language: ca\n" "Language-Team: Catalan " "(https://app.transifex.com/12rambau/teams/166811/ca/)\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.13.0\n" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:53 msgid "Skip to main content" msgstr "Salta al contingut principal" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:64 msgid "Back to top" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:7 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:28 msgid "Search" msgstr "Cerca al web" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:8 msgid "Error" msgstr "Error" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:9 msgid "Please activate JavaScript to enable the search functionality." msgstr "Activeu JavaScript per habilitar la funcionalitat de cerca." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:13 msgid "Breadcrumb" msgstr "Ruta de navegació" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:17 msgid "Home" msgstr "Inici" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:5 #, python-format msgid "© Copyright %(copyright)s." msgstr "© Copyright %(copyright)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:8 #, python-format msgid "© Copyright %(copyright)s." msgstr "© Copyright %(copyright)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:10 #, python-format msgid "Edit on %(provider)s" msgstr "Edita a %(provider)s" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:12 msgid "Edit" msgstr "Edita" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:4 msgid "Indices" msgstr "Índexs" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:11 msgid "General Index" msgstr "Índex general" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:15 msgid "Global Module Index" msgstr "Índex Global de Mòduls" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:19 msgid "Python Module Index" msgstr "Índex de Mòduls Python" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/last-updated.html:4 #, python-format msgid "Last updated on %(last_updated)s." msgstr "Última actualització el %(last_updated)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:6 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:7 msgid "Site Navigation" msgstr "Navegació del lloc" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/page-toc.html:8 msgid "On this page" msgstr "Continguts de la pàgina" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:6 msgid "previous page" msgstr "pàgina anterior" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:9 msgid "previous" msgstr "anterior" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:17 msgid "next page" msgstr "pàgina següent" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:19 msgid "next" msgstr "següent" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:3 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:4 msgid "Section Navigation" msgstr "Navegació de la Secció" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sourcelink.html:5 msgid "Show Source" msgstr "Mostra el fitxer d'origen" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sphinx-version.html:4 #, python-format msgid "" "Created using Sphinx " "%(sphinx_version)s." msgstr "" "Creada amb Sphinx " "%(sphinx_version)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-switcher.html:5 msgid "light/dark" msgstr "clar/fosc" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-version.html:3 #, python-format msgid "" "Built with the PyData Sphinx Theme " "%(theme_version)s." msgstr "" "Construïda amb el Tema PyData Sphinx " "%(theme_version)s." #~ msgid "Breadcrumbs" #~ msgstr "Rutes de navegació" #~ msgid "GitHub" #~ msgstr "GitHub" #~ msgid "GitLab" #~ msgstr "GitLab" #~ msgid "Bitbucket" #~ msgstr "Bitbucket" #~ msgid "Twitter" #~ msgstr "Twitter" PK2XqJW3pydata_sphinx_theme/locale/en/LC_MESSAGES/sphinx.mo$,-Project-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2023-12-21 07:30-0700 PO-Revision-Date: 2023-02-16 13:19-0500 Last-Translator: FULL NAME Language: en Language-Team: en Plural-Forms: nplurals=2; plural=(n != 1) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.8.0 PKֺ2X&Zg3pydata_sphinx_theme/locale/en/LC_MESSAGES/sphinx.po# English translations for pydata-sphinx-theme. # Copyright (C) 2023 PyData developers # This file is distributed under the same license as the pydata-sphinx-theme # project. # msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2023-12-21 07:30-0700\n" "PO-Revision-Date: 2023-02-16 13:19-0500\n" "Last-Translator: FULL NAME \n" "Language: en\n" "Language-Team: en \n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.13.0\n" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:53 msgid "Skip to main content" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:64 msgid "Back to top" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:7 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:28 msgid "Search" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:8 msgid "Error" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:9 msgid "Please activate JavaScript to enable the search functionality." msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:13 msgid "Breadcrumb" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:17 msgid "Home" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:5 #, python-format msgid "© Copyright %(copyright)s." msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:8 #, python-format msgid "© Copyright %(copyright)s." msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:10 #, python-format msgid "Edit on %(provider)s" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:12 msgid "Edit" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:4 msgid "Indices" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:11 msgid "General Index" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:15 msgid "Global Module Index" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:19 msgid "Python Module Index" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/last-updated.html:4 #, python-format msgid "Last updated on %(last_updated)s." msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:6 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:7 msgid "Site Navigation" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/page-toc.html:8 msgid "On this page" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:6 msgid "previous page" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:9 msgid "previous" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:17 msgid "next page" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:19 msgid "next" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:3 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:4 msgid "Section Navigation" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sourcelink.html:5 msgid "Show Source" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sphinx-version.html:4 #, python-format msgid "" "Created using Sphinx " "%(sphinx_version)s." msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-switcher.html:5 msgid "light/dark" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-version.html:3 #, python-format msgid "" "Built with the PyData Sphinx Theme " "%(theme_version)s." msgstr "" #~ msgid "Breadcrumbs" #~ msgstr "" #~ msgid "GitHub" #~ msgstr "" #~ msgid "GitLab" #~ msgstr "" #~ msgid "Bitbucket" #~ msgstr "" #~ msgid "Twitter" #~ msgstr "" PK2XRN"|/ / 3pydata_sphinx_theme/locale/es/LC_MESSAGES/sphinx.mo R\ ! >-l    2/K KWR07NTd0J6=Vi  2 BreadcrumbBuilt with the PyData Sphinx Theme %(theme_version)s.Created using Sphinx %(sphinx_version)s.EditEdit on %(provider)sErrorGeneral IndexGlobal Module IndexHomeIndicesLast updated on %(last_updated)s.On this pagePlease activate JavaScript to enable the search functionality.Python Module IndexSearchSection NavigationShow SourceSite NavigationSkip to main contentlight/darknextnext pagepreviousprevious page© Copyright %(copyright)s.© Copyright %(copyright)s.Project-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2023-12-21 07:30-0700 PO-Revision-Date: 2023-04-14 14:57+0000 Last-Translator: Rambaud Pierrick , 2023 Language: es Language-Team: Spanish (https://app.transifex.com/12rambau/teams/166811/es/) Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.8.0 Miga de panConstruido con el Tema PyData Sphinx %(theme_version)s.Creado usando Sphinx %(sphinx_version)s.EditarEditar en %(provider)sErrorÍndice GeneralÍndice Global de MódulosInicioÍndicesActualizado por última vez en %(last_updated)s.En esta páginaPor favor, active JavaScript para habilitar la funcionalidad de búsqueda.Índice de Módulos PythonBuscarNavegación del secciónMostrar el códigoNavegación del sitioSaltar al contenido principalclaro/oscurosiguientesiguiente páginaanteriorpágina anterior© Copyright %(copyright)s.© Copyright %(copyright)s.PKֺ2XW]]3pydata_sphinx_theme/locale/es/LC_MESSAGES/sphinx.po# English translations for pydata-sphinx-theme. # Copyright (C) 2023 PyData developers # This file is distributed under the same license as the pydata-sphinx-theme # project. # # Translators: # Rambaud Pierrick , 2023 msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2023-12-21 07:30-0700\n" "PO-Revision-Date: 2023-04-14 14:57+0000\n" "Last-Translator: Rambaud Pierrick , 2023\n" "Language: es\n" "Language-Team: Spanish " "(https://app.transifex.com/12rambau/teams/166811/es/)\n" "Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 " "? 1 : 2;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.13.0\n" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:53 msgid "Skip to main content" msgstr "Saltar al contenido principal" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:64 msgid "Back to top" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:7 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:28 msgid "Search" msgstr "Buscar" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:8 msgid "Error" msgstr "Error" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:9 msgid "Please activate JavaScript to enable the search functionality." msgstr "Por favor, active JavaScript para habilitar la funcionalidad de búsqueda." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:13 msgid "Breadcrumb" msgstr "Miga de pan" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:17 msgid "Home" msgstr "Inicio" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:5 #, python-format msgid "© Copyright %(copyright)s." msgstr "© Copyright %(copyright)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:8 #, python-format msgid "© Copyright %(copyright)s." msgstr "© Copyright %(copyright)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:10 #, python-format msgid "Edit on %(provider)s" msgstr "Editar en %(provider)s" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:12 msgid "Edit" msgstr "Editar" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:4 msgid "Indices" msgstr "Índices" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:11 msgid "General Index" msgstr "Índice General" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:15 msgid "Global Module Index" msgstr "Índice Global de Módulos" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:19 msgid "Python Module Index" msgstr "Índice de Módulos Python" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/last-updated.html:4 #, python-format msgid "Last updated on %(last_updated)s." msgstr "Actualizado por última vez en %(last_updated)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:6 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:7 msgid "Site Navigation" msgstr "Navegación del sitio" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/page-toc.html:8 msgid "On this page" msgstr "En esta página" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:6 msgid "previous page" msgstr "página anterior" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:9 msgid "previous" msgstr "anterior" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:17 msgid "next page" msgstr "siguiente página" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:19 msgid "next" msgstr "siguiente" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:3 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:4 msgid "Section Navigation" msgstr "Navegación del sección" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sourcelink.html:5 msgid "Show Source" msgstr "Mostrar el código" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sphinx-version.html:4 #, python-format msgid "" "Created using Sphinx " "%(sphinx_version)s." msgstr "" "Creado usando Sphinx " "%(sphinx_version)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-switcher.html:5 msgid "light/dark" msgstr "claro/oscuro" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-version.html:3 #, python-format msgid "" "Built with the PyData Sphinx Theme " "%(theme_version)s." msgstr "" "Construido con el Tema PyData Sphinx " "%(theme_version)s." #~ msgid "Breadcrumbs" #~ msgstr "Migas de pan" #~ msgid "GitHub" #~ msgstr "GitHub" #~ msgid "GitLab" #~ msgstr "GitLab" #~ msgid "Bitbucket" #~ msgstr "Bitbucket" #~ msgid "Twitter" #~ msgstr "Twitter" PK2Xn\MX X 3pydata_sphinx_theme/locale/fr/LC_MESSAGES/sphinx.mo  Rx  ! <>I    2K g r Xmv @D ]g   2 < Back to topBreadcrumbBuilt with the PyData Sphinx Theme %(theme_version)s.Created using Sphinx %(sphinx_version)s.EditEdit on %(provider)sErrorGeneral IndexGlobal Module IndexHomeIndicesLast updated on %(last_updated)s.On this pagePlease activate JavaScript to enable the search functionality.Python Module IndexSearchSection NavigationShow SourceSite NavigationSkip to main contentlight/darknextnext pagepreviousprevious page© Copyright %(copyright)s.© Copyright %(copyright)s.Project-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2023-12-21 07:30-0700 PO-Revision-Date: 2023-04-14 14:57+0000 Last-Translator: Rambaud Pierrick , 2024 Language: fr Language-Team: French (https://app.transifex.com/12rambau/teams/166811/fr/) Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.8.0 Haut de pageFil d'ArianeConstruit avec le Thème PyData Sphinx %(theme_version)s.Créé en utilisant Sphinx %(sphinx_version)s.ModifierModifier sur %(provider)sErreurIndex généralIndex général des modulesAccueilIndicesMis à jour le %(last_updated)s.Sur cette pageVeuillez activer le JavaScript pour que la recherche fonctionne.Index des modules PythonRechercheNavigation de la sectionMontrer le code sourceNavigation du sitePasser au contenu principalclair/sombresuivantepage suivanteprécédentepage précédente© Copyright %(copyright)s.© Copyright %(copyright)s.PKֺ2X&aegg3pydata_sphinx_theme/locale/fr/LC_MESSAGES/sphinx.po# English translations for pydata-sphinx-theme. # Copyright (C) 2023 PyData developers # This file is distributed under the same license as the pydata-sphinx-theme # project. # # Translators: # Rambaud Pierrick , 2024 # msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2023-12-21 07:30-0700\n" "PO-Revision-Date: 2023-04-14 14:57+0000\n" "Last-Translator: Rambaud Pierrick , 2024\n" "Language-Team: French (https://app.transifex.com/12rambau/teams/166811/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.13.0\n" "Language: fr\n" "Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:53 msgid "Skip to main content" msgstr "Passer au contenu principal" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:64 msgid "Back to top" msgstr "Haut de page" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:7 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:28 msgid "Search" msgstr "Recherche" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:8 msgid "Error" msgstr "Erreur" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:9 msgid "Please activate JavaScript to enable the search functionality." msgstr "Veuillez activer le JavaScript pour que la recherche fonctionne." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:13 msgid "Breadcrumb" msgstr "Fil d'Ariane" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:17 msgid "Home" msgstr "Accueil" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:5 #, python-format msgid "© Copyright %(copyright)s." msgstr "© Copyright %(copyright)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:8 #, python-format msgid "© Copyright %(copyright)s." msgstr "© Copyright %(copyright)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:10 #, python-format msgid "Edit on %(provider)s" msgstr "Modifier sur %(provider)s" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:12 msgid "Edit" msgstr "Modifier" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:4 msgid "Indices" msgstr "Indices" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:11 msgid "General Index" msgstr "Index général" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:15 msgid "Global Module Index" msgstr "Index général des modules" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:19 msgid "Python Module Index" msgstr "Index des modules Python" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/last-updated.html:4 #, python-format msgid "Last updated on %(last_updated)s." msgstr "Mis à jour le %(last_updated)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:6 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:7 msgid "Site Navigation" msgstr "Navigation du site" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/page-toc.html:8 msgid "On this page" msgstr "Sur cette page" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:6 msgid "previous page" msgstr "page précédente" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:9 msgid "previous" msgstr "précédente" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:17 msgid "next page" msgstr "page suivante" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:19 msgid "next" msgstr "suivante" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:3 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:4 msgid "Section Navigation" msgstr "Navigation de la section" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sourcelink.html:5 msgid "Show Source" msgstr "Montrer le code source" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sphinx-version.html:4 #, python-format msgid "" "Created using Sphinx " "%(sphinx_version)s." msgstr "" "Créé en utilisant Sphinx " "%(sphinx_version)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-switcher.html:5 msgid "light/dark" msgstr "clair/sombre" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-version.html:3 #, python-format msgid "" "Built with the PyData Sphinx Theme " "%(theme_version)s." msgstr "" "Construit avec le Thème PyData Sphinx " "%(theme_version)s." #~ msgid "Breadcrumbs" #~ msgstr "Fils d'Ariane" #~ msgid "GitHub" #~ msgstr "GitHub" #~ msgid "GitLab" #~ msgstr "GitLab" #~ msgid "Bitbucket" #~ msgstr "Bitbucket" #~ msgid "Twitter" #~ msgstr "Twitter" PK2X/Z 3pydata_sphinx_theme/locale/ru/LC_MESSAGES/sphinx.mo RL ! >Tho    2b3g[, 06g9v["+ N Y ,t " 9   #% I %T ;z " BreadcrumbBuilt with the PyData Sphinx Theme %(theme_version)s.Created using Sphinx %(sphinx_version)s.EditEdit on %(provider)sErrorGeneral IndexGlobal Module IndexHomeLast updated on %(last_updated)s.On this pagePlease activate JavaScript to enable the search functionality.Python Module IndexSearchSection NavigationShow SourceSite NavigationSkip to main contentlight/darknextnext pagepreviousprevious page© Copyright %(copyright)s.© Copyright %(copyright)s.Project-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2023-12-21 07:30-0700 PO-Revision-Date: 2023-04-14 14:57+0000 Last-Translator: Rambaud Pierrick , 2023 Language: ru Language-Team: Russian (https://app.transifex.com/12rambau/teams/166811/ru/) Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.8.0 Хлебная крошкаСобрано с использованием темы PyData Sphinx %(theme_version)s.Создано с помощью Sphinx %(sphinx_version)s.РедактироватьРедактировать на %(provider)sОшибкаОбщий указательГлобальный индекс модулейГлавнаяПоследнее обновление %(last_updated)s.На этой страницеАктивируйте JavaScript, чтобы включить функцию поиска.Индекс модулей PythonПоискВ этом разделеПросмотр исходного кодаНавигация по сайтуПерейти к основному содержаниюсветлая/темнаядалееследующая страницаназадпредыдущая страница© Копирайт %(copyright)s.© Копирайт %(copyright)s.PKֺ2XnL~FF3pydata_sphinx_theme/locale/ru/LC_MESSAGES/sphinx.po# English translations for pydata-sphinx-theme. # Copyright (C) 2023 PyData developers # This file is distributed under the same license as the pydata-sphinx-theme # project. # # Translators: # Rambaud Pierrick , 2023 msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2023-12-21 07:30-0700\n" "PO-Revision-Date: 2023-04-14 14:57+0000\n" "Last-Translator: Rambaud Pierrick , 2023\n" "Language: ru\n" "Language-Team: Russian " "(https://app.transifex.com/12rambau/teams/166811/ru/)\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) " "|| (n%100>=11 && n%100<=14)? 2 : 3);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.13.0\n" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:53 msgid "Skip to main content" msgstr "Перейти к основному содержанию" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:64 msgid "Back to top" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:7 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:28 msgid "Search" msgstr "Поиск" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:8 msgid "Error" msgstr "Ошибка" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:9 msgid "Please activate JavaScript to enable the search functionality." msgstr "Активируйте JavaScript, чтобы включить функцию поиска." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:13 msgid "Breadcrumb" msgstr "Хлебная крошка" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:17 msgid "Home" msgstr "Главная" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:5 #, python-format msgid "© Copyright %(copyright)s." msgstr "© Копирайт %(copyright)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:8 #, python-format msgid "© Copyright %(copyright)s." msgstr "© Копирайт %(copyright)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:10 #, python-format msgid "Edit on %(provider)s" msgstr "Редактировать на %(provider)s" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:12 msgid "Edit" msgstr "Редактировать" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:4 msgid "Indices" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:11 msgid "General Index" msgstr "Общий указатель" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:15 msgid "Global Module Index" msgstr "Глобальный индекс модулей" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:19 msgid "Python Module Index" msgstr "Индекс модулей Python" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/last-updated.html:4 #, python-format msgid "Last updated on %(last_updated)s." msgstr "Последнее обновление %(last_updated)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:6 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:7 msgid "Site Navigation" msgstr "Навигация по сайту" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/page-toc.html:8 msgid "On this page" msgstr "На этой странице" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:6 msgid "previous page" msgstr "предыдущая страница" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:9 msgid "previous" msgstr "назад" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:17 msgid "next page" msgstr "следующая страница" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:19 msgid "next" msgstr "далее" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:3 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:4 msgid "Section Navigation" msgstr "В этом разделе" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sourcelink.html:5 msgid "Show Source" msgstr "Просмотр исходного кода" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sphinx-version.html:4 #, python-format msgid "" "Created using Sphinx " "%(sphinx_version)s." msgstr "" "Создано с помощью Sphinx " "%(sphinx_version)s." #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-switcher.html:5 msgid "light/dark" msgstr "светлая/темная" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-version.html:3 #, python-format msgid "" "Built with the PyData Sphinx Theme " "%(theme_version)s." msgstr "" "Собрано с использованием темы PyData Sphinx " "%(theme_version)s." #~ msgid "Breadcrumbs" #~ msgstr "Навигационная цепочка" #~ msgid "GitHub" #~ msgstr "GitHub" #~ msgid "GitLab" #~ msgstr "GitLab" #~ msgid "Bitbucket" #~ msgstr "Bitbucket" #~ msgid "Twitter" #~ msgstr "Twitter" PKֺ2X)%pydata_sphinx_theme/locale/sphinx.pot# Translations template for PROJECT. # Copyright (C) 2023 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # FIRST AUTHOR , 2023. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2023-12-21 07:30-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.13.0\n" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:53 msgid "Skip to main content" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html:64 msgid "Back to top" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button-field.html:7 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-button.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:5 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:28 msgid "Search" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:8 msgid "Error" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html:9 msgid "Please activate JavaScript to enable the search functionality." msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:13 msgid "Breadcrumb" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html:17 msgid "Home" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:5 #, python-format msgid "© Copyright %(copyright)s." msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html:8 #, python-format msgid "© Copyright %(copyright)s." msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:10 #, python-format msgid "Edit on %(provider)s" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html:12 msgid "Edit" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:4 msgid "Indices" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:11 msgid "General Index" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:15 msgid "Global Module Index" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html:19 msgid "Python Module Index" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/last-updated.html:4 #, python-format msgid "Last updated on %(last_updated)s." msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:6 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/navbar-nav.html:7 msgid "Site Navigation" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/page-toc.html:8 msgid "On this page" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:6 msgid "previous page" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:9 msgid "previous" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:17 msgid "next page" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/prev-next.html:19 msgid "next" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:3 #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sidebar-nav-bs.html:4 msgid "Section Navigation" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sourcelink.html:5 msgid "Show Source" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/sphinx-version.html:4 #, python-format msgid "" "Created using Sphinx " "%(sphinx_version)s." msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-switcher.html:5 msgid "light/dark" msgstr "" #: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/theme-version.html:3 #, python-format msgid "" "Built with the PyData Sphinx Theme " "%(theme_version)s." msgstr "" PKֺ2X8H H pydata_sphinx_theme/logo.py"""customize events for logo management. we use one event to copy over custom logo images to _static and another even to link them in the html context """ from functools import partial from pathlib import Path from docutils.nodes import Node from sphinx.application import Sphinx from sphinx.errors import ExtensionError from sphinx.util import isurl from sphinx.util.fileutil import copy_asset_file from .utils import get_theme_options_dict, maybe_warn def setup_logo_path( app: Sphinx, pagename: str, templatename: str, context: dict, doctree: Node ) -> None: """Set up relative paths to logos in our HTML templates. In Sphinx, the context["logo"] is a path to the `html_logo` image now in the output `_static` folder. If logo["image_light"] and logo["image_dark"] are given, we must modify them to follow the same pattern. They have already been copied to the output folder in the `update_config` event. """ # get information from the context "logo_url" for sphinx>=6, "logo" sphinx<6 pathto = context.get("pathto") logo = context.get("logo_url") or context.get("logo") theme_logo = context.get("theme_logo", {}) # Define the final path to logo images in the HTML context theme_logo["image_relative"] = {} for kind in ["light", "dark"]: image_kind_logo = theme_logo.get(f"image_{kind}") # If it's a URL the "relative" path is just the URL # else we need to calculate the relative path to a local file if image_kind_logo: if not isurl(image_kind_logo): image_kind_name = Path(image_kind_logo).name image_kind_logo = pathto(f"_static/{image_kind_name}", resource=True) theme_logo["image_relative"][kind] = image_kind_logo # If there's no custom logo for this kind, just use `html_logo` # If `logo` is also None, then do not add this key to context. elif isinstance(logo, str) and len(logo) > 0: theme_logo["image_relative"][kind] = logo # Update our context logo variables with the new image paths context["theme_logo"] = theme_logo def copy_logo_images(app: Sphinx, exception=None) -> None: """Copy logo image to the _static directory. If logo image paths are given, copy them to the `_static` folder Then we can link to them directly in an html_page_context event. """ warning = partial(maybe_warn, app) logo = get_theme_options_dict(app).get("logo", {}) staticdir = Path(app.builder.outdir) / "_static" for kind in ["light", "dark"]: path_image = logo.get(f"image_{kind}") if not path_image or isurl(path_image): continue if (staticdir / Path(path_image).name).exists(): # file already exists in static dir e.g. because a theme has # bundled the logo and installed it there continue if not (Path(app.srcdir) / path_image).exists(): warning(f"Path to {kind} image logo does not exist: {path_image}") # Ensure templates cannot be passed for logo path to avoid security vulnerability if path_image.lower().endswith("_t"): raise ExtensionError( f"The {kind} logo path '{path_image}' looks like a Sphinx template; " "please provide a static logo image." ) copy_asset_file(path_image, staticdir) PKֺ2X,,pydata_sphinx_theme/pygment.py"""Handle pygment css. inspired by the Furo theme https://github.com/pradyunsg/furo/blob/main/src/furo/__init__.py """ from functools import partial from pathlib import Path from pygments.formatters import HtmlFormatter from pygments.styles import get_all_styles from sphinx.application import Sphinx from .utils import get_theme_options_dict, maybe_warn def _get_styles(formatter: HtmlFormatter, prefix: str) -> None: """Get styles out of a formatter, where everything has the correct prefix.""" for line in formatter.get_linenos_style_defs(): yield f"{prefix} {line}" yield from formatter.get_background_style_defs(prefix) yield from formatter.get_token_style_defs(prefix) def get_pygments_stylesheet(light_style: str, dark_style: str) -> str: """Generate the theme-specific pygments.css. There is no way to tell Sphinx how the theme handles modes. """ light_formatter = HtmlFormatter(style=light_style) dark_formatter = HtmlFormatter(style=dark_style) lines = [] light_prefix = 'html[data-theme="light"] .highlight' lines.extend(_get_styles(light_formatter, prefix=light_prefix)) dark_prefix = 'html[data-theme="dark"] .highlight' lines.extend(_get_styles(dark_formatter, prefix=dark_prefix)) return "\n".join(lines) def overwrite_pygments_css(app: Sphinx, exception=None): """Overwrite pygments.css to allow dynamic light/dark switching. Sphinx natively supports config variables `pygments_style` and `pygments_dark_style`. However, quoting from www.sphinx-doc.org/en/master/development/theming.html#creating-themes The pygments_dark_style setting [...is used] when the CSS media query (prefers-color-scheme: dark) evaluates to true. This does not allow for dynamic switching by the user, so at build time we overwrite the pygment.css file so that it embeds 2 versions: - the light theme prefixed with "[data-theme="light"]" - the dark theme prefixed with "[data-theme="dark"]" Fallbacks are defined in this function in case the user-requested (or our theme-specified) pygments theme is not available. """ if exception is not None: return assert app.builder theme_options = get_theme_options_dict(app) warning = partial(maybe_warn, app) pygments_styles = list(get_all_styles()) fallbacks = dict(light="tango", dark="monokai") for light_or_dark, fallback in fallbacks.items(): # make sure our fallbacks work; if not fall(further)back to "default" if fallback not in pygments_styles: fallback = pygments_styles[0] # should resolve to "default" # see if user specified a light/dark pygments theme: style_key = f"pygment_{light_or_dark}_style" style_name = theme_options.get(style_key, None) # if not, use the one we set in `theme.conf`: if style_name is None and hasattr(app.builder, "theme"): style_name = app.builder.theme.get_options()[style_key] # make sure we can load the style if style_name not in pygments_styles: # only warn if user asked for a highlight theme that we can't find if style_name is not None: warning( f"Highlighting style {style_name} not found by pygments, " f"falling back to {fallback}." ) style_name = fallback # assign to the appropriate variable if light_or_dark == "light": light_theme = style_name else: dark_theme = style_name # re-write pygments.css pygment_css = Path(app.builder.outdir) / "_static" / "pygments.css" with pygment_css.open("w") as f: f.write(get_pygments_stylesheet(light_theme, dark_theme)) PKֺ2X5{!pydata_sphinx_theme/short_link.py"""A custom Transform object to shorten github and gitlab links.""" from urllib.parse import ParseResult, urlparse, urlunparse from docutils import nodes from sphinx.transforms.post_transforms import SphinxPostTransform from sphinx.util.nodes import NodeMatcher from .utils import traverse_or_findall class ShortenLinkTransform(SphinxPostTransform): """Shorten link when they are coming from github or gitlab and add an extra class to the tag for further styling. Before: .. code-block:: html https://github.com/2i2c-org/infrastructure/issues/1329 After: .. code-block:: html 2i2c-org/infrastructure#1329 """ default_priority = 400 formats = ("html",) supported_platform = {"github.com": "github", "gitlab.com": "gitlab"} platform = None def run(self, **kwargs): """run the Transform object.""" matcher = NodeMatcher(nodes.reference) # TODO: just use "findall" once docutils min version >=0.18.1 for node in traverse_or_findall(self.document, matcher): uri = node.attributes.get("refuri") text = next(iter(node.children), None) # only act if the uri and text are the same # if not the user has already customized the display of the link if uri is not None and text is not None and text == uri: uri = urlparse(uri) # only do something if the platform is identified self.platform = self.supported_platform.get(uri.netloc) if self.platform is not None: node.attributes["classes"].append(self.platform) node.children[0] = nodes.Text(self.parse_url(uri)) def parse_url(self, uri: ParseResult) -> str: """Parse the content of the url with respect to the selected platform. Args: uri: the link to the platform content Returns: the reformated url title """ path = uri.path if path == "": # plain url passed, return platform only return self.platform # if the path is not empty it contains a leading "/", which we don't want to # include in the parsed content path = path.lstrip("/") # check the platform name and read the information accordingly # as "/#" # or "//…//#" if self.platform == "github": # split the url content parts = path.split("/") if parts[0] == "orgs" and "/projects" in path: # We have a projects board link # ref: `orgs/{org}/projects/{project-id}` text = f"{parts[1]}/projects#{parts[3]}" else: # We have an issues, PRs, or repository link if len(parts) > 0: text = parts[0] # organisation if len(parts) > 1: text += f"/{parts[1]}" # repository if len(parts) > 2: if parts[2] in ["issues", "pull", "discussions"]: text += f"#{parts[-1]}" # element number elif self.platform == "gitlab": # cp. https://docs.gitlab.com/ee/user/markdown.html#gitlab-specific-references if "/-/" in path and any( map(uri.path.__contains__, ["issues", "merge_requests"]) ): group_and_subgroups, parts, *_ = path.split("/-/") parts = parts.split("/") url_type, element_number, *_ = parts if url_type == "issues": text = f"{group_and_subgroups}#{element_number}" elif url_type == "merge_requests": text = f"{group_and_subgroups}!{element_number}" else: # display the whole uri (after "gitlab.com/") including parameters # for example "///" text = uri._replace(netloc="", scheme="") # remove platform text = urlunparse(text)[1:] # combine to string and strip leading "/" return text PKֺ2X8 |jjIpydata_sphinx_theme/theme/pydata_sphinx_theme/components/breadcrumbs.html{# Displays (and links to) the parent section(s) of the currently viewed page. #} {%- block breadcrumbs %} {# If we have more than 3 parents (excluding the home page) then we remove The ones in the middle and add an ellipsis. #} {% if parents|length>2 %} {% set parents=[parents[0], {"title": ''}, parents[-1]] %} {% endif %} {#- Hide breadcrumbs on the home page #} {% if title and pagename != root_doc %} {% endif %} {%- endblock %} PKֺ2XxqGpydata_sphinx_theme/theme/pydata_sphinx_theme/components/copyright.html{# Displays the copyright information (which is defined in conf.py). #} {% if show_copyright and copyright %} {% endif %} PKֺ2XC]҉Lpydata_sphinx_theme/theme/pydata_sphinx_theme/components/edit-this-page.html{# Displays a link to the edit interface of the page source in the specified Version Control System. #} {% if sourcename is defined and theme_use_edit_page_button==true and page_source_suffix %} {% set src = sourcename.split('.') %} {% endif %} PKֺ2XajHpydata_sphinx_theme/theme/pydata_sphinx_theme/components/icon-links.html{# Displays icon-links as list items. #} {%- macro icon_link_nav_item(url, icon, name, type, attributes='') -%} {%- if url | length > 2 %} {%- endif -%} {%- endmacro -%} {%- if theme_icon_links -%} {%- endif -%} PKֺ2X5 C||Epydata_sphinx_theme/theme/pydata_sphinx_theme/components/indices.html{# Displays links to the Sphinx-generated indices (genindex, modindex, py-modindex). #} {%- set indices_navigation_heading_id = unique_html_id("pst-indices-navigation-heading") -%} PKֺ2X:sJpydata_sphinx_theme/theme/pydata_sphinx_theme/components/last-updated.html{# Displays the date and time that the documentation was last built. #} {%- if last_updated -%}

{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}

{%- endif -%} PKֺ2X