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

[HTML Theme]: Add "Navigate to Top" Button #12618

Closed
Closed
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
10 changes: 10 additions & 0 deletions sphinx/themes/basic/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ <h3>{{ _('Navigation') }}</h3>
{%- if not embedded %}
{%- block scripts %}
{{- script() }}
{%- block navigate_to_top_script %}
<script src="{{ pathto('_static/navigate_top.js', 1) }}"></script>
{%- endblock %}
{%- endblock %}
{%- if pageurl %}
<link rel="canonical" href="{{ pageurl|e }}" />
Expand Down Expand Up @@ -213,5 +216,12 @@ <h3>{{ _('Navigation') }}</h3>
{%- endif %}
</div>
{%- endblock %}

{%- block navigate_to_top %}
<a href="#" id="navigate-to-top" class="hide-navigate-to-top">
Navigate to Top
</a>
{%- endblock %}

</body>
</html>
29 changes: 29 additions & 0 deletions sphinx/themes/basic/static/basic.css.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@

/* -- main layout ----------------------------------------------------------- */

html {
scroll-behavior: smooth;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this is something we should force onto every derived theme.

}

div.clearer {
clear: both;
}
Expand Down Expand Up @@ -112,6 +116,31 @@ img {
max-width: 100%;
}

/* -- navigate to top -------------------------------------------------------*/
#navigate-to-top {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
text-decoration: none;
color: #000;
font-size: 14px;
padding: 2px 8px;
background-color: rgb(239, 239, 239);
border: 1px outset #000;
border-radius: 2px;
box-sizing: border-box;
z-index: 1000;
}

.hide-navigate-to-top {
display: none;
}

.show-navigate-to-top {
display: block;
}

/* -- search page ----------------------------------------------------------- */

ul.search {
Expand Down
52 changes: 52 additions & 0 deletions sphinx/themes/basic/static/navigate_top.js
Copy link
Member

Choose a reason for hiding this comment

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

HTML specifies the #top anchor which seems simpler than this script.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* Add Navigate to Top Functionality */
kavania2002 marked this conversation as resolved.
Show resolved Hide resolved
// inspired from https://github.com/pradyunsg/furo

"use strict";

// fetch the pixels scrolled vertically from origin
var lastScrollTop = document.documentElement.scrollTop;
const GO_TO_TOP_OFFSET = 64;

const _scrollToTop = (positionY) => {
const navigateToTopButtom = document.getElementById("navigate-to-top");
// position not yet crossed of offset
if (positionY < GO_TO_TOP_OFFSET) {
navigateToTopButtom.classList.add("hide-navigate-to-top");
navigateToTopButtom.classList.remove("show-navigate-to-top");
} else {
if (positionY > lastScrollTop) {
// scrolling down
navigateToTopButtom.classList.add("hide-navigate-to-top");
navigateToTopButtom.classList.remove("show-navigate-to-top");
} else if (positionY < lastScrollTop) {
// scrolling up
navigateToTopButtom.classList.add("show-navigate-to-top");
navigateToTopButtom.classList.remove("hide-navigate-to-top");
}
}
// update the position for next scroll event
lastScrollTop = positionY;
};

const _setupScrollHandler = () => {
let lastKnownScrollPosition = 0;
// help to keep track if requestAnimationFrame is scheduled
let ticking = false;

document.addEventListener("scroll", (event) => {
lastKnownScrollPosition = window.scrollY;

if (!ticking) {
window.requestAnimationFrame(() => {
_scrollToTop(lastKnownScrollPosition)
// animation is complete (so now be called again)
ticking = false;
});

// it's scheduled so don't call back the requestAnimationFrame
ticking = true;
}
});
};

document.addEventListener("DOMContentLoaded", _setupScrollHandler);