Skip to content

Commit bbe3e57

Browse files
gabalafouCarreau
andauthored
Animate remotely loaded banners together (#1808)
The banner animation felt a little funky to me, even after the improvements made in #1693. My hunch is that because the two banners are stacked on top of each other and the height of one affects the layout/position of the other, trying to animate the height of both of them at the same time causes the browser to stutter. Or maybe it was just because they could each load at different but often only slightly offset times. Whatever the case, I decided to do a little code clean up and change it so that they both come in together. In the process of working on this PR it also made sense to address a TODO, and add "Version warning" to the list of translatable strings. * pybabel extract . -F babel.cfg -o src/pydata_sphinx_theme/locale/sphinx.pot -k '_ __ l_ lazy_gettext' * pybabel update -i src/pydata_sphinx_theme/locale/sphinx.pot -d src/pydata_sphinx_theme/locale -D sphinx * Update src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html * incorporate #1755 --------- Co-authored-by: M Bussonnier <[email protected]>
1 parent c42ee47 commit bbe3e57

File tree

13 files changed

+215
-131
lines changed

13 files changed

+215
-131
lines changed

docs/user_guide/announcements.rst

+14-6
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,20 @@ For example, the following configuration tells the theme to load the ``custom-te
4444
Update or remove announcement banner
4545
------------------------------------
4646

47-
To update or remove the announcement banner, you can change the value of
48-
``html_theme_options["announcement"]`` in your ``conf.py`` or you can edit the
49-
contents of the ``custom-template.html`` file directly. For example, if you have a
50-
temporary announcement that you want to remove without rebuilding your
51-
documentation pages, you can use an empty ``custom-template.html`` file and the
52-
banner will be hidden.
47+
If you set ``html_theme_options["announcement"]`` to plain text or HTML, then to
48+
update the announcement banner you need to modify this string and rebuild your
49+
documentation pages. To remove the announcement banner, set this value to an
50+
empty string and rebuild your documentation pages.
51+
52+
If you set ``html_theme_options["announcement"]`` to a URL string (starts with
53+
``http``), then you can edit the file at that URL to update the announcement
54+
banner. Saving an empty file at that URL will remove the announcement banner.
55+
That's the main advantage of using a URL--you can change the announcement banner
56+
without rebuilding and redeploying all of your documentation pages. For example,
57+
if you point the announcement to the URL of a file in your repo, as we do on
58+
this documentation site (see previous section), then you can edit, save and push
59+
your changes to just that file (empty file = remove announcement) without
60+
rebuilding and redeploying all your docs.
5361

5462
.. _version-warning-banners:
5563

src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js

+85-49
Original file line numberDiff line numberDiff line change
@@ -488,16 +488,13 @@ function showVersionWarningBanner(data) {
488488
return;
489489
}
490490
// now construct the warning banner
491-
var outer = document.createElement("aside");
492-
// TODO: add to translatable strings
493-
outer.setAttribute("aria-label", "Version warning");
491+
const banner = document.querySelector(".bd-header-version-warning");
494492
const middle = document.createElement("div");
495493
const inner = document.createElement("div");
496494
const bold = document.createElement("strong");
497495
const button = document.createElement("a");
498496
// these classes exist since pydata-sphinx-theme v0.10.0
499497
// the init class is used for animation
500-
outer.classList = "bd-header-version-warning container-fluid init";
501498
middle.classList = "bd-header-announcement__content";
502499
inner.classList = "sidebar-message";
503500
button.classList =
@@ -522,35 +519,12 @@ function showVersionWarningBanner(data) {
522519
} else {
523520
bold.innerText = `version ${version}`;
524521
}
525-
outer.appendChild(middle);
522+
banner.appendChild(middle);
526523
middle.appendChild(inner);
527524
inner.appendChild(bold);
528525
inner.appendChild(document.createTextNode("."));
529526
inner.appendChild(button);
530-
const skipLink = document.getElementById("pst-skip-link");
531-
skipLink.after(outer);
532-
// At least 3rem height
533-
const autoHeight = Math.max(
534-
outer.offsetHeight,
535-
3 * parseFloat(getComputedStyle(document.documentElement).fontSize),
536-
);
537-
// Set height and vertical padding to 0 to prepare the height transition
538-
outer.style.setProperty("height", 0);
539-
outer.style.setProperty("padding-top", 0);
540-
outer.style.setProperty("padding-bottom", 0);
541-
outer.classList.remove("init");
542-
// Set height to the computed height with a small timeout to activate the transition
543-
setTimeout(() => {
544-
outer.style.setProperty("height", `${autoHeight}px`);
545-
// Wait for a bit more than 300ms (the transition duration) then remove the
546-
// forcefully set styles and let CSS take over
547-
setTimeout(() => {
548-
outer.style.removeProperty("padding-top");
549-
outer.style.removeProperty("padding-bottom");
550-
outer.style.removeProperty("height");
551-
outer.style.setProperty("min-height", "3rem");
552-
}, 320);
553-
}, 10);
527+
banner.classList.remove("d-none");
554528
}
555529

556530
/*******************************************************************************
@@ -584,27 +558,29 @@ function initRTDObserver() {
584558
observer.observe(document.body, config);
585559
}
586560

587-
// fetch the JSON version data (only once), then use it to populate the version
588-
// switcher and maybe show the version warning bar
589-
var versionSwitcherBtns = document.querySelectorAll(
590-
".version-switcher__button",
591-
);
592-
const hasSwitcherMenu = versionSwitcherBtns.length > 0;
593-
const hasVersionsJSON = DOCUMENTATION_OPTIONS.hasOwnProperty(
594-
"theme_switcher_json_url",
595-
);
596-
const wantsWarningBanner = DOCUMENTATION_OPTIONS.show_version_warning_banner;
597-
598-
if (hasVersionsJSON && (hasSwitcherMenu || wantsWarningBanner)) {
599-
const data = await fetchVersionSwitcherJSON(
600-
DOCUMENTATION_OPTIONS.theme_switcher_json_url,
561+
async function fetchAndUseVersions() {
562+
// fetch the JSON version data (only once), then use it to populate the version
563+
// switcher and maybe show the version warning bar
564+
var versionSwitcherBtns = document.querySelectorAll(
565+
".version-switcher__button",
566+
);
567+
const hasSwitcherMenu = versionSwitcherBtns.length > 0;
568+
const hasVersionsJSON = DOCUMENTATION_OPTIONS.hasOwnProperty(
569+
"theme_switcher_json_url",
601570
);
602-
// TODO: remove the `if(data)` once the `return null` is fixed within fetchVersionSwitcherJSON.
603-
// We don't really want the switcher and warning bar to silently not work.
604-
if (data) {
605-
populateVersionSwitcher(data, versionSwitcherBtns);
606-
if (wantsWarningBanner) {
607-
showVersionWarningBanner(data);
571+
const wantsWarningBanner = DOCUMENTATION_OPTIONS.show_version_warning_banner;
572+
573+
if (hasVersionsJSON && (hasSwitcherMenu || wantsWarningBanner)) {
574+
const data = await fetchVersionSwitcherJSON(
575+
DOCUMENTATION_OPTIONS.theme_switcher_json_url,
576+
);
577+
// TODO: remove the `if(data)` once the `return null` is fixed within fetchVersionSwitcherJSON.
578+
// We don't really want the switcher and warning bar to silently not work.
579+
if (data) {
580+
populateVersionSwitcher(data, versionSwitcherBtns);
581+
if (wantsWarningBanner) {
582+
showVersionWarningBanner(data);
583+
}
608584
}
609585
}
610586
}
@@ -718,10 +694,70 @@ function debounce(callback, wait) {
718694
};
719695
}
720696

697+
/*******************************************************************************
698+
* Announcement banner - fetch and load remote HTML
699+
*/
700+
async function setupAnnouncementBanner() {
701+
const banner = document.querySelector(".bd-header-announcement");
702+
const { pstAnnouncementUrl } = banner.dataset;
703+
704+
if (!pstAnnouncementUrl) {
705+
return;
706+
}
707+
708+
try {
709+
const response = await fetch(pstAnnouncementUrl);
710+
if (!response.ok) {
711+
throw new Error(
712+
`[PST]: HTTP response status not ok: ${response.status} ${response.statusText}`,
713+
);
714+
}
715+
const data = await response.text();
716+
if (data.length === 0) {
717+
console.log(`[PST]: Empty announcement at: ${pstAnnouncementUrl}`);
718+
return;
719+
}
720+
banner.innerHTML = `<div class="bd-header-announcement__content">${data}</div>`;
721+
banner.classList.remove("d-none");
722+
} catch (_error) {
723+
console.log(`[PST]: Failed to load announcement at: ${pstAnnouncementUrl}`);
724+
console.error(_error);
725+
}
726+
}
727+
728+
/*******************************************************************************
729+
* Reveal (and animate) the banners (version warning, announcement) together
730+
*/
731+
async function fetchRevealBannersTogether() {
732+
// Wait until finished fetching and loading banners
733+
await Promise.allSettled([fetchAndUseVersions(), setupAnnouncementBanner()]);
734+
735+
// The revealer element should have CSS rules that set height to 0, overflow
736+
// to hidden, and an animation transition on the height (unless the user has
737+
// turned off animations)
738+
const revealer = document.querySelector(".pst-async-banner-revealer");
739+
740+
// Remove the d-none (display-none) class to calculate the children heights.
741+
revealer.classList.remove("d-none");
742+
743+
// Add together the heights of the element's children
744+
const height = Array.from(revealer.children).reduce(
745+
(height, el) => height + el.offsetHeight,
746+
0,
747+
);
748+
749+
// Use the calculated height to give the revealer a non-zero height (if
750+
// animations allowed, the height change will animate)
751+
revealer.style.setProperty("height", `${height}px`);
752+
}
753+
721754
/*******************************************************************************
722755
* Call functions after document loading.
723756
*/
724757

758+
// Call this one first to kick off the network request for the version warning
759+
// and announcement banner data as early as possible.
760+
documentReady(fetchRevealBannersTogether);
725761
documentReady(addModeListener);
726762
documentReady(scrollToActive);
727763
documentReady(addTOCInteractivity);

src/pydata_sphinx_theme/assets/styles/sections/_announcement.scss

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,38 @@
1+
.pst-async-banner-revealer {
2+
// Setting height to 0 and overflow to hidden allows us to add up the heights
3+
// of this element's children before revealing them.
4+
height: 0;
5+
overflow: hidden;
6+
7+
// Height to be set by JavaScript, which should trigger the following
8+
// transition rule (unless the user has set their system to reduce motion).
9+
transition: height 300ms ease-in-out;
10+
@media (prefers-reduced-motion) {
11+
transition: none;
12+
}
13+
}
14+
115
.bd-header-version-warning,
216
.bd-header-announcement {
17+
min-height: 3rem;
318
width: 100%;
419
display: flex;
520
position: relative;
621
align-items: center;
722
justify-content: center;
823
text-align: center;
9-
transition: height 300ms ease-in-out;
10-
overflow-y: hidden;
1124
padding: 0.5rem 12.5%; // Horizontal padding so the width is 75%
1225
// One breakpoint less than $breakpoint-sidebar-primary. See variables/_layout.scss for more info.
1326
@include media-breakpoint-down(lg) {
1427
// Announcements can take a bit more width on mobile
1528
padding: 0.5rem 2%;
1629
}
1730

18-
&.init {
19-
position: fixed;
20-
visibility: hidden;
21-
}
22-
2331
p {
2432
font-weight: bold;
2533
margin: 0;
2634
}
2735

28-
&:empty {
29-
display: none;
30-
}
31-
3236
// Ensure there is enough contrast against the background
3337
a {
3438
color: var(--pst-color-inline-code-links);

src/pydata_sphinx_theme/locale/ca/LC_MESSAGES/sphinx.po

+5-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,11 @@ msgstr ""
143143
"theme.readthedocs.io/en/stable/index.html\">Tema PyData Sphinx</a> "
144144
"%(theme_version)s."
145145

146-
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
146+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
147+
msgid "Version warning"
148+
msgstr ""
149+
150+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
147151
msgid "Announcement"
148152
msgstr ""
149153

src/pydata_sphinx_theme/locale/cs/LC_MESSAGES/sphinx.po

+6-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
msgid ""
99
msgstr ""
1010

11+
1112
#: docs/conf.py:94
1213
msgid "Click to expand"
1314
msgstr ""
@@ -142,7 +143,11 @@ msgstr ""
142143
"theme.readthedocs.io/en/stable/index.html\">PyData Sphinx Theme</a> "
143144
"%(theme_version)s."
144145

145-
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
146+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
147+
msgid "Version warning"
148+
msgstr ""
149+
150+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
146151
msgid "Announcement"
147152
msgstr ""
148153

src/pydata_sphinx_theme/locale/en/LC_MESSAGES/sphinx.po

+6-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
msgid ""
77
msgstr ""
88

9+
910
#: docs/conf.py:94
1011
msgid "Click to expand"
1112
msgstr ""
@@ -135,7 +136,11 @@ msgid ""
135136
"%(theme_version)s."
136137
msgstr ""
137138

138-
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
139+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
140+
msgid "Version warning"
141+
msgstr ""
142+
143+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
139144
msgid "Announcement"
140145
msgstr ""
141146

src/pydata_sphinx_theme/locale/es/LC_MESSAGES/sphinx.po

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
msgid ""
1010
msgstr ""
1111

12+
1213
#: docs/conf.py:94
1314
msgid "Click to expand"
1415
msgstr ""
@@ -143,7 +144,11 @@ msgstr ""
143144
"theme.readthedocs.io/en/stable/index.html\">Tema PyData Sphinx</a> "
144145
"%(theme_version)s."
145146

146-
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
147+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
148+
msgid "Version warning"
149+
msgstr ""
150+
151+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
147152
msgid "Announcement"
148153
msgstr ""
149154

src/pydata_sphinx_theme/locale/fr/LC_MESSAGES/sphinx.po

+6-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
msgid ""
1111
msgstr ""
1212

13+
1314
#: docs/conf.py:94
1415
msgid "Click to expand"
1516
msgstr "Cliquez pour développer"
@@ -144,7 +145,11 @@ msgstr ""
144145
"theme.readthedocs.io/en/stable/index.html\">Thème PyData Sphinx</a> "
145146
"%(theme_version)s."
146147

147-
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
148+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
149+
msgid "Version warning"
150+
msgstr ""
151+
152+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
148153
msgid "Announcement"
149154
msgstr "Annonce"
150155

src/pydata_sphinx_theme/locale/ru/LC_MESSAGES/sphinx.po

+6-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
msgid ""
99
msgstr ""
1010

11+
1112
#: docs/conf.py:94
1213
msgid "Click to expand"
1314
msgstr ""
@@ -142,7 +143,11 @@ msgstr ""
142143
"theme.readthedocs.io/en/stable/index.html\\\">PyData Sphinx</a> "
143144
"%(theme_version)s."
144145

145-
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
146+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
147+
msgid "Version warning"
148+
msgstr ""
149+
150+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
146151
msgid "Announcement"
147152
msgstr ""
148153

src/pydata_sphinx_theme/locale/sphinx.pot

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ msgid ""
88
msgstr ""
99
"Project-Id-Version: PROJECT VERSION\n"
1010
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
11-
"POT-Creation-Date: 2024-04-29 13:43+0200\n"
11+
"POT-Creation-Date: 2024-05-10 18:43+0200\n"
1212
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414
"Language-Team: LANGUAGE <[email protected]>\n"
@@ -146,7 +146,11 @@ msgid ""
146146
"%(theme_version)s."
147147
msgstr ""
148148

149-
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
149+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
150+
msgid "Version warning"
151+
msgstr ""
152+
153+
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
150154
msgid "Announcement"
151155
msgstr ""
152156

0 commit comments

Comments
 (0)