Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animate remotely loaded banners together #1808

Merged
merged 8 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions docs/user_guide/announcements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,20 @@ For example, the following configuration tells the theme to load the ``custom-te
Update or remove announcement banner
------------------------------------

To update or remove the announcement banner, you can change the value of
Carreau marked this conversation as resolved.
Show resolved Hide resolved
``html_theme_options["announcement"]`` in your ``conf.py`` or you can edit the
contents of the ``custom-template.html`` file directly. For example, if you have a
temporary announcement that you want to remove without rebuilding your
documentation pages, you can use an empty ``custom-template.html`` file and the
banner will be hidden.
If you set ``html_theme_options["announcement"]`` to plain text or HTML, then to
update the announcement banner you need to modify this string and rebuild your
documentation pages. To remove the announcement banner, set this value to an
empty string and rebuild your documentation pages.

If you set ``html_theme_options["announcement"]`` to a URL string (starts with
``http``), then you can edit the file at that URL to update the announcement
banner. Saving an empty file at that URL will remove the announcement banner.
That's the main advantage of using a URL--you can change the announcement banner
without rebuilding and redeploying all of your documentation pages. For example,
if you point the announcement to the URL of a file in your repo, as we do on
this documentation site (see previous section), then you can edit, save and push
your changes to just that file (empty file = remove announcement) without
rebuilding and redeploying all your docs.

.. _version-warning-banners:

Expand Down
134 changes: 85 additions & 49 deletions src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,16 +488,13 @@ function showVersionWarningBanner(data) {
return;
}
// now construct the warning banner
var outer = document.createElement("aside");
// TODO: add to translatable strings
outer.setAttribute("aria-label", "Version warning");
const banner = document.querySelector(".bd-header-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
// the init class is used for animation
outer.classList = "bd-header-version-warning container-fluid init";
middle.classList = "bd-header-announcement__content";
inner.classList = "sidebar-message";
button.classList =
Expand All @@ -522,35 +519,12 @@ function showVersionWarningBanner(data) {
} else {
bold.innerText = `version ${version}`;
}
outer.appendChild(middle);
banner.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);
// At least 3rem height
const autoHeight = Math.max(
outer.offsetHeight,
3 * parseFloat(getComputedStyle(document.documentElement).fontSize),
);
// Set height and vertical padding to 0 to prepare the height transition
outer.style.setProperty("height", 0);
outer.style.setProperty("padding-top", 0);
outer.style.setProperty("padding-bottom", 0);
outer.classList.remove("init");
// Set height to the computed height with a small timeout to activate the transition
setTimeout(() => {
outer.style.setProperty("height", `${autoHeight}px`);
// Wait for a bit more than 300ms (the transition duration) then remove the
// forcefully set styles and let CSS take over
setTimeout(() => {
outer.style.removeProperty("padding-top");
outer.style.removeProperty("padding-bottom");
outer.style.removeProperty("height");
outer.style.setProperty("min-height", "3rem");
}, 320);
}, 10);
banner.classList.remove("d-none");
}

/*******************************************************************************
Expand Down Expand Up @@ -584,27 +558,29 @@ function initRTDObserver() {
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(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I discovered this line I was a bit surprised. An await in the middle of a module file causes all the rest of the code below it to be deferred until the promise is settled. So this represents a pretty serious slowdown in executing this file, since pretty much all of the code in this file is actually run at the end of the file.

This was introduced in #1344. Previously, the fetch was also executed at the module level, but without the await syntax, so it didn't hold back the rest of the file from executing.

So I decided to put all of this code into a new asynchronous function, fetchAndUseVersions which is called when the document is ready.

DOCUMENTATION_OPTIONS.theme_switcher_json_url,
async function fetchAndUseVersions() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function definition should arguably moved to a different part of the file, next to other code that has to do with the version switcher, but I didn't want to make the diff harder to compare so I left this code at the same place in the file.

// 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",
);
// TODO: remove the `if(data)` once the `return null` is fixed within fetchVersionSwitcherJSON.
// We don't really want the switcher and warning bar to silently not work.
if (data) {
populateVersionSwitcher(data, versionSwitcherBtns);
if (wantsWarningBanner) {
showVersionWarningBanner(data);
const wantsWarningBanner = DOCUMENTATION_OPTIONS.show_version_warning_banner;

if (hasVersionsJSON && (hasSwitcherMenu || wantsWarningBanner)) {
const data = await fetchVersionSwitcherJSON(
DOCUMENTATION_OPTIONS.theme_switcher_json_url,
);
// TODO: remove the `if(data)` once the `return null` is fixed within fetchVersionSwitcherJSON.
// We don't really want the switcher and warning bar to silently not work.
if (data) {
populateVersionSwitcher(data, versionSwitcherBtns);
if (wantsWarningBanner) {
showVersionWarningBanner(data);
}
}
}
}
Expand Down Expand Up @@ -718,10 +694,70 @@ function debounce(callback, wait) {
};
}

/*******************************************************************************
* Announcement banner - fetch and load remote HTML
*/
async function setupAnnouncementBanner() {
const banner = document.querySelector(".bd-header-announcement");
const { pstAnnouncementUrl } = banner.dataset;

if (!pstAnnouncementUrl) {
return;
}

try {
const response = await fetch(pstAnnouncementUrl);
if (!response.ok) {
throw new Error(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorporates #1755

`[PST]: HTTP response status not ok: ${response.status} ${response.statusText}`,
);
}
const data = await response.text();
if (data.length === 0) {
console.log(`[PST]: Empty announcement at: ${pstAnnouncementUrl}`);
return;
}
banner.innerHTML = `<div class="bd-header-announcement__content">${data}</div>`;
banner.classList.remove("d-none");
} catch (_error) {
console.log(`[PST]: Failed to load announcement at: ${pstAnnouncementUrl}`);
console.error(_error);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously the error was not being printed to the console. I thought it might be helpful to our users to print the error.

}
}

/*******************************************************************************
* Reveal (and animate) the banners (version warning, announcement) together
*/
async function fetchRevealBannersTogether() {
// Wait until finished fetching and loading banners
await Promise.allSettled([fetchAndUseVersions(), setupAnnouncementBanner()]);

// The revealer element should have CSS rules that set height to 0, overflow
// to hidden, and an animation transition on the height (unless the user has
// turned off animations)
const revealer = document.querySelector(".pst-async-banner-revealer");

// Remove the d-none (display-none) class to calculate the children heights.
revealer.classList.remove("d-none");

// Add together the heights of the element's children
const height = Array.from(revealer.children).reduce(
(height, el) => height + el.offsetHeight,
0,
);

// Use the calculated height to give the revealer a non-zero height (if
// animations allowed, the height change will animate)
revealer.style.setProperty("height", `${height}px`);
}

/*******************************************************************************
* Call functions after document loading.
*/

// Call this one first to kick off the network request for the version warning
// and announcement banner data as early as possible.
documentReady(fetchRevealBannersTogether);
documentReady(addModeListener);
documentReady(scrollToActive);
documentReady(addTOCInteractivity);
Expand Down
26 changes: 15 additions & 11 deletions src/pydata_sphinx_theme/assets/styles/sections/_announcement.scss
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
.pst-async-banner-revealer {
// Setting height to 0 and overflow to hidden allows us to add up the heights
// of this element's children before revealing them.
height: 0;
overflow: hidden;

// Height to be set by JavaScript, which should trigger the following
// transition rule (unless the user has set their system to reduce motion).
transition: height 300ms ease-in-out;
@media (prefers-reduced-motion) {
transition: none;
}
}

.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;
transition: height 300ms ease-in-out;
overflow-y: hidden;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the transition and overflow rules to the new container element.

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%;
}

&.init {
position: fixed;
visibility: hidden;
}

Comment on lines -18 to -22
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class was added by #1693. It's not needed now.

p {
font-weight: bold;
margin: 0;
}

&:empty {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This functionality—not showing the banner if it's empty—is now taken care of with the changes from #1703 and with the d-none class used in this PR.

display: none;
}

// Ensure there is enough contrast against the background
a {
color: var(--pst-color-inline-code-links);
Expand Down
6 changes: 5 additions & 1 deletion src/pydata_sphinx_theme/locale/ca/LC_MESSAGES/sphinx.po
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ msgstr ""
"theme.readthedocs.io/en/stable/index.html\">Tema PyData Sphinx</a> "
"%(theme_version)s."

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
msgid "Version warning"
msgstr ""

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
msgid "Announcement"
msgstr ""

Expand Down
7 changes: 6 additions & 1 deletion src/pydata_sphinx_theme/locale/cs/LC_MESSAGES/sphinx.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
msgid ""
msgstr ""


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

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
msgid "Version warning"
msgstr ""

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
msgid "Announcement"
msgstr ""

Expand Down
7 changes: 6 additions & 1 deletion src/pydata_sphinx_theme/locale/en/LC_MESSAGES/sphinx.po
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
msgid ""
msgstr ""


#: docs/conf.py:94
msgid "Click to expand"
msgstr ""
Expand Down Expand Up @@ -135,7 +136,11 @@ msgid ""
"%(theme_version)s."
msgstr ""

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
msgid "Version warning"
msgstr ""

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
msgid "Announcement"
msgstr ""

Expand Down
7 changes: 6 additions & 1 deletion src/pydata_sphinx_theme/locale/es/LC_MESSAGES/sphinx.po
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
msgid ""
msgstr ""


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

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
msgid "Version warning"
msgstr ""

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
msgid "Announcement"
msgstr ""

Expand Down
7 changes: 6 additions & 1 deletion src/pydata_sphinx_theme/locale/fr/LC_MESSAGES/sphinx.po
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
msgid ""
msgstr ""


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

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
msgid "Version warning"
msgstr ""

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
msgid "Announcement"
msgstr "Annonce"

Expand Down
7 changes: 6 additions & 1 deletion src/pydata_sphinx_theme/locale/ru/LC_MESSAGES/sphinx.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
msgid ""
msgstr ""


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

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
msgid "Version warning"
msgstr ""

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
msgid "Announcement"
msgstr ""

Expand Down
8 changes: 6 additions & 2 deletions src/pydata_sphinx_theme/locale/sphinx.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-04-29 13:43+0200\n"
"POT-Creation-Date: 2024-05-10 18:43+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand Down Expand Up @@ -146,7 +146,11 @@ msgid ""
"%(theme_version)s."
msgstr ""

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:1
#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:4
msgid "Version warning"
msgstr ""

#: src/pydata_sphinx_theme/theme/pydata_sphinx_theme/sections/announcement.html:6
msgid "Announcement"
msgstr ""

Expand Down
Loading
Loading