diff --git a/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py b/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py index 11345e11871..f3a55270cd7 100644 --- a/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py +++ b/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py @@ -23,7 +23,7 @@ class PEPBanner(rst.Directive): admonition_post_text = "" admonition_class = nodes.important - css_classes = ["pep-banner"] + css_classes = [] def run(self) -> list[nodes.admonition]: @@ -48,7 +48,7 @@ def run(self) -> list[nodes.admonition]: source_lines = [pre_text] + list(self.content or []) + [post_text] admonition_node = self.admonition_class( - "\n".join(source_lines), classes=self.css_classes) + "\n".join(source_lines), classes=["pep-banner"] + self.css_classes) admonition_node.append(pre_text_node) if self.content: @@ -75,7 +75,7 @@ class CanonicalDocBanner(PEPBanner): "See :pep:`1` for how to propose changes." ) - css_classes = [*PEPBanner.css_classes, "canonical-doc"] + css_classes = ["canonical-doc", "sticky-banner"] @@ -97,5 +97,6 @@ class CanonicalPyPASpecBanner(PEPBanner): "`__ " "for how to propose changes." ) + admonition_class = nodes.attention - css_classes = [*PEPBanner.css_classes, "canonical-pypa-spec"] + css_classes = ["canonical-pypa-spec", "sticky-banner"] diff --git a/pep_sphinx_extensions/pep_theme/static/sticky_banner.js b/pep_sphinx_extensions/pep_theme/static/sticky_banner.js new file mode 100644 index 00000000000..cc2ceb3dd0c --- /dev/null +++ b/pep_sphinx_extensions/pep_theme/static/sticky_banner.js @@ -0,0 +1,28 @@ +"use strict"; + +// Inject a style element into the document head that adds scroll-margin-top to +// all elements with an id attribute. This is used to offset the scroll position +// when clicking on a link to an element with an id attribute. The offset is +// equal to the height of the sticky banner. +document.addEventListener("DOMContentLoaded", () => { + const stickyBanners = document.getElementsByClassName("sticky-banner"); + if (!stickyBanners.length) { + return; + } + + const stickyBanner = stickyBanners[0]; + const node = document.createElement("style"); + node.id = "sticky-banner-style"; + document.head.appendChild(node); + + function adjustBannerMargin() { + const text = document.createTextNode( + ":target { scroll-margin-top: " + stickyBanner.offsetHeight + "px; }" + ); + node.replaceChildren(text); + } + + adjustBannerMargin(); + document.addEventListener("resize", adjustBannerMargin); + document.addEventListener("load", adjustBannerMargin); +}); diff --git a/pep_sphinx_extensions/pep_theme/static/style.css b/pep_sphinx_extensions/pep_theme/static/style.css index 999e638e037..6ee8f8e654c 100644 --- a/pep_sphinx_extensions/pep_theme/static/style.css +++ b/pep_sphinx_extensions/pep_theme/static/style.css @@ -321,10 +321,10 @@ div.error { div.warning { background-color: var(--colour-warning); } +div.attention, div.caution { background-color: var(--colour-caution); } -div.attention, div.important { background-color: var(--colour-attention); } @@ -405,3 +405,9 @@ dl.footnote > dd { white-space: nowrap !important; border: 0 !important; } + +/* Sticky banners */ +.sticky-banner { + top: 0; + position: sticky; +} diff --git a/pep_sphinx_extensions/pep_theme/templates/page.html b/pep_sphinx_extensions/pep_theme/templates/page.html index 6902e559264..7daf060cfd5 100644 --- a/pep_sphinx_extensions/pep_theme/templates/page.html +++ b/pep_sphinx_extensions/pep_theme/templates/page.html @@ -51,5 +51,6 @@

Contents

+