diff --git a/doc/changelog.d/689.fixed.md b/doc/changelog.d/689.fixed.md new file mode 100644 index 000000000..3cf7f559c --- /dev/null +++ b/doc/changelog.d/689.fixed.md @@ -0,0 +1 @@ +smaller screen view and search for mobile views \ No newline at end of file diff --git a/src/ansys_sphinx_theme/assets/styles/ansys-sphinx-theme-variable.scss b/src/ansys_sphinx_theme/assets/styles/ansys-sphinx-theme-variable.scss index b561bef7b..5bdea9158 100644 --- a/src/ansys_sphinx_theme/assets/styles/ansys-sphinx-theme-variable.scss +++ b/src/ansys_sphinx_theme/assets/styles/ansys-sphinx-theme-variable.scss @@ -15,7 +15,6 @@ :root { /** Ansys specific changes to the theme */ - /** * Ansys Font family * @@ -52,6 +51,7 @@ --bs-nav-link-font-size: 0.875rem; /* 14px */ --bs-navbar-color: var(--bs-ast-navbar-color); --ast-font-sidebar-header: 1rem; /* 16px */ + /** * weight */ @@ -401,7 +401,7 @@ html[data-theme="dark"] { body { font-family: var(--ast-body-family); line-height: var(--ast-global-line-height); - font-size: 14px; + font-size: 0.875rem; // 14px color: var(--ast-color-text); } @@ -420,5 +420,108 @@ h6 { } h1 { - line-height: 56px; + line-height: 3.5rem; // 56px +} + + +/* Mobile-specific overrides (≤ 1200px) */ +@media (max-width: 1200px) { + .navbar-header-items { + display: none !important; + flex-grow: 1 !important; + padding: 0 0 0 0.5rem !important; + } + + ul.navbar-nav { + align-items: baseline; + } + + .navbar-center-items .navbar-item { + display: inline-block; + } + + .navbar-persistent--mobile { + display: none; + } + + .navbar-persistent--container { + display: flex; + } + + .bd-sidebar-primary { + flex-grow: 0.75; + height: 100vh; + left: 0; + margin-left: -75%; + max-height: 100vh !important; + max-width: 21.875rem !important; // 350px + position: fixed; + top: 0; + transition: visibility 0.2s ease-out,margin 0.2s ease-out; + visibility: hidden; + width: 75%; + z-index: 1050; + display: flex !important; + } + + .bd-sidebar-primary[open] { + visibility: visible !important; + } + + button.primary-toggle { + display: flex !important; + } + + #pst-collapse-sidebar-button { + display: none !important; + } + + nav.bd-links { + display: block !important; + } + + .nav-link .hide-on-wide { + display: none !important; + } + + .bd-sidebar-primary.hide-on-wide { + display: flex !important; + } + + .bd-sidebar-primary .sidebar-header-items { + display: flex !important; + } } + +/* Desktop-specific overrides (> 1200px) */ +@media (min-width: 1200px) { + .navbar-header-items { + display: inherit; + flex-grow: 1; + padding: 0 0 0 0.5rem; + } + + ul.navbar-nav { + align-items: baseline; + } + + .navbar-center-items .navbar-item { + display: inline-block; + } + + .navbar-persistent--mobile { + display: none; + } + + .navbar-persistent--container { + display: flex; + } + + .bd-sidebar-primary { + font-size: var(--pst-sidebar-font-size); + } + + button.primary-toggle { + display: none; + } +} \ No newline at end of file diff --git a/src/ansys_sphinx_theme/assets/styles/ast-search.scss b/src/ansys_sphinx_theme/assets/styles/ast-search.scss index 7bcae5189..efd747379 100644 --- a/src/ansys_sphinx_theme/assets/styles/ast-search.scss +++ b/src/ansys_sphinx_theme/assets/styles/ast-search.scss @@ -1,4 +1,8 @@ /* Static Search Results Container */ + +.bd-search{ + display: flex; +} .static-search-results { display: flex; flex-direction: column; @@ -80,10 +84,6 @@ html[data-theme="light"] .highlight { .bd-search .search-button__kbd-shortcut { background-color: var(--ast-search-bar-enable-background) !important; box-shadow: none !important; - height: 2.25rem; /* 36px */ - display: flex; - flex-wrap: wrap; - align-content: center; } /* Index Select Dropdown */ @@ -149,21 +149,55 @@ html[data-theme="light"] .highlight { } /* Responsive Styles */ -@media (max-width: 48rem) { /* 768px */ - .bd-search input.expanded { - width: 6.25rem; /* 100px */ +@media (min-width: 1200px) and (max-width: 85.375rem) { + .bd-search input.form-control.expanded { + width: 100%; /* 320px */ + } + + .bd-search input.form-control { + width: 100%; /* 240px */ + } + + .bd-search .search-button__kbd-shortcut { + display: none !important; + } + + .static-search-results { + width: 50%; /* 480px */ + } +} + +@media (max-width: 1200px) { + + .bd-search input.form-control.expanded { + width: 5rem; /* 320px */ } - .form-control { - width: 3.125rem; /* 50px */ + .bd-search input.form-control { + width: 100%; /* 240px */ } - .result { - width: 6.25rem; /* 100px */ + .static-search-results { + width: 50%; /* 480px */ } .bd-search .search-button__kbd-shortcut { - display: none; + display: none !important; + } +} + +// laptop +@media (min-width: 85.375rem) and (max-width: 128rem) { + .bd-search input.form-control.expanded { + width: 35rem; /* 560px */ + } + + .bd-search input.form-control { + width: 100%; /* 240px */ + } + + .static-search-results { + width: 37rem; /* 600px */ } } diff --git a/src/ansys_sphinx_theme/assets/styles/pydata-sphinx-theme-custom.scss b/src/ansys_sphinx_theme/assets/styles/pydata-sphinx-theme-custom.scss index 5863c81ca..8581dbf82 100644 --- a/src/ansys_sphinx_theme/assets/styles/pydata-sphinx-theme-custom.scss +++ b/src/ansys_sphinx_theme/assets/styles/pydata-sphinx-theme-custom.scss @@ -744,25 +744,25 @@ button.btn.version-switcher__button:hover { max-width: 100%; } -@media (min-width: 960px) { +@media (min-width: 1200px) { .bd-sidebar-primary { width: 20%; } } -@media (min-width: 960px) { +@media (min-width: 1200px) { .col-lg-3 { width: fit-content; } } -@media (min-width: 960px) { +@media (min-width: 1200px) { .bd-page-width { max-width: min(100%, 1700px) !important; } } -@media (min-width: 960px) { +@media (min-width: 1200px) { .bd-main .bd-content .bd-article-container { width: min(100%, 1070px); } diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/js/search.js b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/js/search.js index dab5c7548..23b81b80d 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/js/search.js +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/js/search.js @@ -1,11 +1,19 @@ -const SEARCH_BAR = document.getElementById("search-bar"); -const SEARCH_INPUT = SEARCH_BAR.querySelector(".bd-search input.form-control"); -const RESULTS = document.getElementById("static-search-results"); -const MAIN_PAGE_CONTENT = document.querySelector(".bd-main"); -let CURRENT_INDEX = -1; +/** + * @file search.js + * @description Client-side search functionality using Fuse.js for the Ansys Sphinx Theme. + */ +const MAIN_PAGE_CONTENT = document.querySelector(".bd-main"); const FUSE_VERSION = "6.4.6"; - +let SEARCH_BAR, + RESULTS, + SEARCH_INPUT, + CURRENT_INDEX = -1, + fuse; + +/** + * Load fuse.js from CDN and initialize search functionality. + */ require.config({ paths: { fuse: `https://cdn.jsdelivr.net/npm/fuse.js@${FUSE_VERSION}/dist/fuse.min`, @@ -13,70 +21,89 @@ require.config({ }); require(["fuse"], function (Fuse) { - // Declare global variables - let fuse; - - // Debounce function to limit the rate of function calls - function debounce(func, delay) { + // Debounce utility + const debounce = (func, delay) => { let timeout; - return function (...args) { + return (...args) => { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), delay); }; - } + }; - // Initialize Fuse when the data is fetched - function initializeFuse(data, options) { - fuse = new Fuse(data, options); - // add env variable "FUSE_ACTIVE" to indicate that the search is ready - document.documentElement.setAttribute("data-fuse_active", "true"); - } + // Truncate text for preview + const truncateTextPreview = (text, maxLength = 200) => + text.length <= maxLength ? text : `${text.slice(0, maxLength)}...`; - // Expand the search bar input + // Get full path using Sphinx's data-content_root + const getDynamicPath = (targetFile) => { + const contentRoot = + document.documentElement.getAttribute("data-content_root"); + return `${contentRoot}${targetFile}`; + }; + + // Navigate to a given URL + const navigateToHref = (href) => { + window.location.href = getDynamicPath(href); + }; + + // Expand the search input UI function expandSearchInput() { RESULTS.style.display = "flex"; SEARCH_INPUT.classList.add("expanded"); MAIN_PAGE_CONTENT.classList.add("blurred"); SEARCH_INPUT.focus(); + + // Fix overlapping on mobile view + const modalSidebar = document.querySelector( + "#pst-primary-sidebar-modal > div.sidebar-primary-items__start.sidebar-primary__section", + ); + if (modalSidebar) modalSidebar.style.opacity = "0.1"; } - // Collapse the search bar input and hide any results + // Collapse and reset the search UI function collapseSearchInput() { RESULTS.style.display = "none"; SEARCH_INPUT.classList.remove("expanded"); SEARCH_INPUT.value = ""; MAIN_PAGE_CONTENT.classList.remove("blurred"); - } + CURRENT_INDEX = -1; - // Truncate the preview of the text - function truncateTextPreview(text, maxLength = 200) { - if (text.length <= maxLength) { - return text; // If the text is already within the limit, return as is - } - return text.slice(0, maxLength) + "..."; + const modalSidebar = document.querySelector( + "#pst-primary-sidebar-modal > div.sidebar-primary-items__start.sidebar-primary__section", + ); + if (modalSidebar) modalSidebar.style.opacity = "1"; } - // Display search results - function displayResults(results) { - if (!RESULTS) { - console.error("RESULTS element is not defined."); - return; - } - - if (results.length === 0) { - noResultsFoundBanner(); - RESULTS.style.display = "none"; - return; - } + // Show banner when no results found + function noResultsFoundBanner() { + RESULTS.innerHTML = ""; + RESULTS.style.display = "flex"; + const banner = document.createElement("div"); + banner.className = "warning-banner"; + banner.textContent = + "No results found. Press Ctrl+Enter for extended search."; + banner.style.fontStyle = "italic"; + RESULTS.appendChild(banner); + } + // Show a temporary searching indicator + function searchingForResultsBanner() { + RESULTS.innerHTML = ""; RESULTS.style.display = "flex"; + const banner = document.createElement("div"); + banner.className = "searching-banner"; + banner.textContent = "Searching..."; + banner.style.fontStyle = "italic"; + RESULTS.appendChild(banner); + } + + // Display search results from Fuse + function displayResults(results) { RESULTS.innerHTML = ""; + if (!results.length) return noResultsFoundBanner(); const fragment = document.createDocumentFragment(); - - results.forEach((result) => { - const { title, text, href } = result.item; - + results.forEach(({ item: { title, text, href } }) => { const resultItem = document.createElement("div"); resultItem.className = "result-item"; resultItem.dataset.href = href; @@ -85,34 +112,35 @@ require(["fuse"], function (Fuse) { const resultTitle = document.createElement("div"); resultTitle.className = "result-title"; resultTitle.textContent = title; - resultItem.appendChild(resultTitle); const resultText = document.createElement("div"); resultText.className = "result-text"; - const highlightedText = truncateTextPreview(text); - resultText.textContent = highlightedText; - resultItem.appendChild(resultText); + resultText.textContent = truncateTextPreview(text); + resultItem.append(resultTitle, resultText); fragment.appendChild(resultItem); - console.log("Adding search result item"); }); - // Add Advanced Search Option + + // Advanced Search Option + const query = SEARCH_INPUT.value.trim(); const advancedSearchItem = document.createElement("div"); advancedSearchItem.className = "result-item advanced-search"; advancedSearchItem.style.display = "flex"; advancedSearchItem.style.justifyContent = "space-between"; advancedSearchItem.style.alignItems = "center"; - const query = SEARCH_INPUT.value.trim(); advancedSearchItem.dataset.href = ADVANCE_SEARCH_PATH + "?q=" + query; advancedSearchItem.innerHTML = `Show all results Ctrl + Enter`; advancedSearchItem.addEventListener("click", () => { window.location.href = ADVANCE_SEARCH_PATH + "?q=" + SEARCH_INPUT.value.trim(); }); + fragment.appendChild(advancedSearchItem); RESULTS.appendChild(fragment); + RESULTS.style.display = "flex"; } - // Focus the selected result item + + // Focus the currently selected result item function focusSelected(resultsItems) { if (CURRENT_INDEX >= 0 && CURRENT_INDEX < resultsItems.length) { resultsItems.forEach((item) => item.classList.remove("selected")); @@ -123,99 +151,47 @@ require(["fuse"], function (Fuse) { } } - // Display a banner indicating that the search is running - function noResultsFoundBanner() { - RESULTS.innerHTML = ""; - RESULTS.style.display = "flex"; - const warningBanner = document.createElement("div"); - warningBanner.className = "warning-banner"; - warningBanner.textContent = - "No results found. Press Enter for extended search."; - warningBanner.style.display = "block"; - warningBanner.style.fontStyle = "italic"; - RESULTS.appendChild(warningBanner); - } - - // Build the complete hyperlink for the target file - function getDynamicPath(targetFile) { - const contentRoot = - document.documentElement.getAttribute("data-content_root"); - return `${contentRoot}${targetFile}`; - } - - // Navigate to the desired file - function navigateToHref(href) { - const finalUrl = getDynamicPath(href); - window.location.href = finalUrl; - } - - // Display a banner indicating that no results were found - function searchingForResultsBanner() { - RESULTS.innerHTML = ""; - RESULTS.style.display = "flex"; - const searchingBanner = document.createElement("div"); - searchingBanner.className = "searching-banner"; - searchingBanner.textContent = "Searching..."; - searchingBanner.style.display = "block"; - console.log("Searching..."); - searchingBanner.style.fontStyle = "italic"; - RESULTS.appendChild(searchingBanner); - } - - // Handle search input + // Handle search query input with debounce const handleSearchInput = debounce( () => { const query = SEARCH_INPUT.value.trim(); - if (query.length > 0) { - const searchResults = fuse.search(query, { - limit: parseInt(SEARCH_OPTIONS.limit), - }); - if (searchResults.length === 0) { - noResultsFoundBanner(); - } else { - displayResults(searchResults); - } - } else { - RESULTS.style.display = "none"; - } + if (!query) return (RESULTS.style.display = "none"); + + const searchResults = fuse.search(query, { + limit: parseInt(SEARCH_OPTIONS.limit), + }); + displayResults(searchResults); }, parseInt(SEARCH_OPTIONS.delay) || 300, ); - // Handle keydown event for the search input + // Handle keyboard navigation inside search input function handleKeyDownSearchInput(event) { const resultItems = RESULTS.querySelectorAll(".result-item"); - switch (event.key) { case "Tab": event.preventDefault(); break; - case "Escape": collapseSearchInput(); break; - case "Enter": - event.preventDefault(); // Always prevent default on Enter + event.preventDefault(); if (event.ctrlKey || event.metaKey) { const query = SEARCH_INPUT.value.trim(); window.location.href = ADVANCE_SEARCH_PATH + "?q=" + query; } else if (CURRENT_INDEX >= 0 && CURRENT_INDEX < resultItems.length) { - const href = resultItems[CURRENT_INDEX].dataset.href; - navigateToHref(href); + navigateToHref(resultItems[CURRENT_INDEX].dataset.href); } else if (resultItems.length > 0) { - const href = resultItems[0].dataset.href; - navigateToHref(href); + navigateToHref(resultItems[0].dataset.href); } break; - case "ArrowDown": if (resultItems.length > 0) { CURRENT_INDEX = (CURRENT_INDEX + 1) % resultItems.length; focusSelected(resultItems); } break; - case "ArrowUp": if (resultItems.length > 0) { CURRENT_INDEX = @@ -223,9 +199,7 @@ require(["fuse"], function (Fuse) { focusSelected(resultItems); } break; - default: - // Ignore keys like Ctrl, Alt, Shift (don't trigger search) if ( event.ctrlKey || event.altKey || @@ -235,58 +209,74 @@ require(["fuse"], function (Fuse) { ) { return; } - if ( document.documentElement.getAttribute("data-fuse_active") === "true" ) { searchingForResultsBanner(); } else { - console.error("[AST]: Fuse is not active yet."); RESULTS.style.display = "none"; } - handleSearchInput(); } } - // Handle keydown event globally - function handleGlobalKeyDown(event) { - switch (event.key) { - case "k": - if (event.ctrlKey) { - expandSearchInput(); - } - break; - - case "Escape": - collapseSearchInput(); - break; + // Initialize and bind search elements + function setupSearchElements() { + if (window.innerWidth < 1200) { + SEARCH_BAR = document.querySelector( + "div.sidebar-header-items__end #search-bar", + ); + RESULTS = document.querySelector( + "div.sidebar-header-items__end .static-search-results", + ); + } else { + SEARCH_BAR = document.getElementById("search-bar"); + RESULTS = document.querySelector(".static-search-results"); } + if (!SEARCH_BAR) { + console.warn("SEARCH_BAR not found for current view."); + return; + } + SEARCH_INPUT = SEARCH_BAR.querySelector(".bd-search input.form-control"); + if (SEARCH_INPUT) { + SEARCH_INPUT.addEventListener("click", expandSearchInput); + SEARCH_INPUT.addEventListener("keydown", handleKeyDownSearchInput); + } + } + + // Handle global keydown events for search shortcuts + function handleGlobalKeyDown(event) { + if (event.key === "Escape") collapseSearchInput(); + else if (event.key === "k" && event.ctrlKey) expandSearchInput(); } - // Handle click event globally + // Collapse search if clicking outside function handleGlobalClick(event) { if (!RESULTS.contains(event.target) && event.target !== SEARCH_INPUT) { collapseSearchInput(); } } - // Add event listeners - SEARCH_INPUT.addEventListener("click", expandSearchInput); - SEARCH_INPUT.addEventListener("keydown", handleKeyDownSearchInput); + // Initialize search functionality on page load + setupSearchElements(); + window.addEventListener("resize", debounce(setupSearchElements, 250)); document.addEventListener("keydown", handleGlobalKeyDown); document.addEventListener("click", handleGlobalClick); - // Fetch search data and initialize Fuse fetch(SEARCH_FILE) .then((response) => { - if (!response.ok) { + if (!response.ok) throw new Error(`[AST]: HTTPS error ${response.statusText}`); - } return response.json(); }) .then((SEARCH_DATA) => initializeFuse(SEARCH_DATA, SEARCH_OPTIONS)) .catch((error) => - console.error(`[AST]: Can not fetch ${SEARCH_FILE}`, error.message), + console.error(`[AST]: Cannot fetch ${SEARCH_FILE}`, error.message), ); + + // Initialize Fuse with the given data and options + function initializeFuse(data, options) { + fuse = new Fuse(data, options); + document.documentElement.setAttribute("data-fuse_active", "true"); + } });