From a2b3914a70fa054e7b3f3e8326adb5064f1255ac Mon Sep 17 00:00:00 2001 From: Andrew Haust Date: Wed, 21 Feb 2024 20:55:10 -0500 Subject: [PATCH] Bring search bar into view on desktop This commit changes how the search bar is brought into view on desktop as brought up in #1860: when using one of the keyboard shortcuts to focus the input, the entire page jumps to the top making you lose your scroll position. On mobile, technically smaller screens, this is remedied by causing the input to slide into view on scroll up, but I don't believe this is a desirable solution for desktop. The following changes are introduced: * Using one of the keyboard shortcuts will focus the search input causing it to stick to the top. * It will continue to stick to the top so long as it is focused allowing you to scroll with it open. * The slide-on-scroll effect has been changed to only fire on touch-enabled devices as opposed to just smaller screens. This is allows us to make the hexdocs window very small and still use keyboard shortcuts--Useful on laptops. Closes #1860 --- assets/css/layout.css | 2 +- assets/css/search-bar.css | 13 +++++++++++++ assets/js/helpers.js | 20 +++++++++++++++++++- assets/js/search-bar.js | 10 ++++++++-- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/assets/css/layout.css b/assets/css/layout.css index 826bfa0b0..a4cc95bb5 100644 --- a/assets/css/layout.css +++ b/assets/css/layout.css @@ -122,7 +122,7 @@ body.sidebar-closed .content { left: 0; } -@media screen and (max-width: 768px) { +@media screen and (hover: none) { .content, body.sidebar-opening .content { left: 0; diff --git a/assets/css/search-bar.css b/assets/css/search-bar.css index 30db46eb5..b133bcabc 100644 --- a/assets/css/search-bar.css +++ b/assets/css/search-bar.css @@ -1,6 +1,19 @@ .top-search { + position: relative; + top: 0; margin-top: 10px; background-color: var(--background); + z-index: 101; +} + +@media only screen and (hover: hover) { + .top-search { + padding: 0.8rem 0; + } +} + +.top-search.sticky { + position: sticky; } .search-settings { diff --git a/assets/js/helpers.js b/assets/js/helpers.js index a7155d6c1..a58e44c40 100644 --- a/assets/js/helpers.js +++ b/assets/js/helpers.js @@ -161,10 +161,28 @@ export function getProjectNameAndVersion () { } /** - * Return `true` if the client's OS is MacOS + * Return `true` if the client's OS is MacOS. * * @return {Boolean} */ export function isMacOS () { return /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) } + +/** + * Return `true` if the client's device is touch-enabled. + * + * @return {Boolean} + */ +export function isTouchDevice () { + return (('ontouchstart' in window) || + (navigator.maxTouchPoints > 0) || + (navigator.msMaxTouchPoints > 0)) +} + +/** + * + */ +export function isVisible (el) { + return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length > 0) +} diff --git a/assets/js/search-bar.js b/assets/js/search-bar.js index a987eb8ef..74e3ba177 100644 --- a/assets/js/search-bar.js +++ b/assets/js/search-bar.js @@ -7,10 +7,11 @@ import { AUTOCOMPLETE_CONTAINER_SELECTOR, AUTOCOMPLETE_SUGGESTION_SELECTOR } from './autocomplete/autocomplete-list' -import { isMacOS, qs } from './helpers' +import { isMacOS, isTouchDevice, isVisible, qs } from './helpers' const SEARCH_INPUT_SELECTOR = 'form.search-bar input' const SEARCH_CLOSE_BUTTON_SELECTOR = 'form.search-bar .search-close-button' +const TOP_SEARCH_SELECTOR = '.top-search' /** * Initializes the sidebar search box. @@ -34,6 +35,8 @@ export function setSearchInputValue (value) { */ export function focusSearchInput () { const searchInput = qs(SEARCH_INPUT_SELECTOR) + const topSearch = qs(TOP_SEARCH_SELECTOR) + topSearch.classList.add('sticky') searchInput.focus() } @@ -136,15 +139,18 @@ function clearSearch () { function hideAutocomplete () { document.body.classList.remove('search-focused') hideAutocompleteList() + qs(TOP_SEARCH_SELECTOR).classList.remove('sticky') } let lastScrollTop = window.scrollY -const topSearch = document.querySelector('.top-search') +const topSearch = document.querySelector(TOP_SEARCH_SELECTOR) const sidebarMenu = document.getElementById('sidebar-menu') const backgroundLayer = document.querySelector('.background-layer') const scrollThreshold = 70 // Set a threshold for scroll, adjust as needed window.addEventListener('scroll', function () { + if (!isTouchDevice()) { return } + const currentScroll = window.scrollY // Add 'fixed' class when not at the top