diff --git a/_layouts/default.html b/_layouts/default.html index 23c09cef7..725c95bd4 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -43,6 +43,5 @@ -
diff --git a/_sass/components/_search.scss b/_sass/components/_search.scss index 88102539b..7c017b9d3 100644 --- a/_sass/components/_search.scss +++ b/_sass/components/_search.scss @@ -119,36 +119,6 @@ } } -// ------------------------------------------------------------ -// Search results dropdown -// ------------------------------------------------------------ -.search-results { - position: absolute; - left: 0; - display: none; - width: 100%; - max-height: calc(100% - #{$sp-10}); - overflow-y: auto; - padding: $sp-1 $sp-2; - border-bottom-right-radius: $border-radius; - border-bottom-left-radius: $border-radius; - - @include mq(md) { - top: 100%; - max-height: calc(100vh - 200%) !important; - padding-left: 3rem; - } -} - -.search-results-list { - padding-left: 0; - margin-bottom: $sp-1; - list-style: none; - background-color: $body-background-color; - outline: 1px solid $border-color; - outline-offset: -1px; -} - // ------------------------------------------------------------ // Full search results page // ------------------------------------------------------------ @@ -176,107 +146,10 @@ } } -// ------------------------------------------------------------ -// Individual search result listing -// ------------------------------------------------------------ -.search-results-list-item { - padding: 0; - margin: 0; - font-size: var(--text-font-size-sm); -} - -.search-result { - display: block; - padding: $sp-1 $sp-3; - - &:hover, - &.active { - background-color: $feedback-color; - } -} - -.search-result-title { - display: block; - padding: $sp-2 0; - - @include mq(sm) { - display: inline-block; - padding-right: $sp-2; - vertical-align: top; - } -} - -// ------------------------------------------------------------ -// Document name + icon -// ------------------------------------------------------------ -.search-result-doc { - display: flex; - align-items: center; - word-wrap: break-word; - - .search-result-icon { - width: $sp-4; - height: $sp-4; - margin-right: $sp-2; - color: $link-color; - flex-shrink: 0; - } - - .search-result-doc-title { - overflow: auto; - font-weight: 700; - } -} - -// ------------------------------------------------------------ -// Section title -// ------------------------------------------------------------ -.search-result-section { - margin-left: #{$sp-4 + $sp-2}; - word-wrap: break-word; -} - -.search-result-rel-url { - display: block; - margin-left: #{$sp-4 + $sp-2}; - overflow: hidden; - color: $search-result-preview-color; - text-overflow: ellipsis; - white-space: nowrap; -} - -// ------------------------------------------------------------ -// Search previews (disabled for now) -// ------------------------------------------------------------ -.search-result-previews { - display: none; - padding: $sp-2 0 $sp-2 $sp-4; - margin-left: $sp-2; - color: $search-result-preview-color; - word-wrap: break-word; - border-left: $border; - border-left-color: $border-color; - - @include mq(sm) { - width: 60%; - padding-left: $sp-2; - margin-left: 0; - vertical-align: top; - } -} - -.search-result-preview + .search-result-preview { - margin-top: $sp-1; -} - .search-result-highlight { font-weight: normal; } -.search-no-result { - padding: $sp-2 $sp-3; -} - // ------------------------------------------------------------ // Floating search button // ------------------------------------------------------------ @@ -293,86 +166,3 @@ align-items: center; justify-content: center; } - -// ------------------------------------------------------------ -// Search overlay -// ------------------------------------------------------------ -.search-overlay { - position: fixed; - top: 0; - left: 0; - z-index: 1; - width: 0; - height: 0; - background-color: rgba(0, 0, 0, 0.3); - opacity: 0; - transition: - opacity ease $transition-duration, - width 0s $transition-duration, - height 0s $transition-duration; -} - -// ------------------------------------------------------------ -// Search-active state -// ------------------------------------------------------------ -.search-active { - .search { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: var(--color-neutral-inverse-bg-document); - - @include mq(md) { - background-color: var(--color-neutral-bg-document); - } - } - - .search-input-wrap { - height: $sp-10; - border-radius: 0; - - @include mq(md) { - width: $search-results-width; - } - } - - .search-input { - background-color: var(--color-neutral-bg-document); - } - - .search-results { - display: block; - } - - .search-no-result { - background-color: var(--color-neutral-bg-document); - } - - .search-overlay { - width: 100%; - height: 100%; - opacity: 1; - transition: - opacity ease $transition-duration, - width 0s, - height 0s; - } - - @include mq(md) { - .main { - position: fixed; - right: 0; - left: 0; - } - } - - .main-header { - padding-top: $sp-10; - - @include mq(md) { - padding-top: 0; - } - } -} diff --git a/assets/js/wp-a11y-docs.js b/assets/js/wp-a11y-docs.js index 171c9f71a..ad1463d12 100644 --- a/assets/js/wp-a11y-docs.js +++ b/assets/js/wp-a11y-docs.js @@ -1,8 +1,4 @@ ---- - layout: null ---- - - (function (jtd, undefined) { +(function (jtd, undefined) { // // --------------------------------------------------------- @@ -125,14 +121,12 @@ * - `window.jtdSearchIndex` * - `window.jtdSearchDocs` * - * Then calls {@link searchLoaded} to bind UI behavior. - * * @function initSearch * @private */ function initSearch() { var request = new XMLHttpRequest(); - request.open('GET', '{{ "assets/js/search-data.json" | relative_url }}', true); + request.open('GET', '/assets/js/search-data.json', true); request.onload = function() { if (request.status >= 200 && request.status < 400) { @@ -160,7 +154,6 @@ } }); - searchLoaded(index, docs); window.jtdSearchIndex = index; window.jtdSearchDocs = docs; @@ -176,289 +169,6 @@ request.send(); } -// -// --------------------------------------------------------- -// Search widget behavior -// --------------------------------------------------------- - - /** - * Initializes live search UI. - * - * Includes: - * - Updated results on keystrokes - * - Accessibility announcements - * - Keyboard navigation (arrows, Enter) - * - Fuzzy search fallback - * - * @function searchLoaded - * @param {lunr.Index} index - Lunr search index. - * @param {Object.} docs - Document metadata. - * @private - */ - function searchLoaded(index, docs) { - var searchInput = document.getElementById('search-input'); - var searchResults = document.getElementById('search-results'); - var mainHeader = document.getElementById('main-header'); - var currentInput; - var currentSearchIndex = 0; - - // Show search input via Ctrl+ shortcut - jtd.addEvent(document, 'keydown', function(e) { - if ((e.ctrlKey || e.metaKey) && e.key === '{{ site.search.focus_shortcut_key }}') { - e.preventDefault(); - mainHeader.classList.add('nav-open'); - searchInput.focus(); - } - }); - - /** - * Shows the search results panel. - * @function - */ - function showSearch() { - document.documentElement.classList.add('search-active'); - } - - /** - * Hides the search results panel. - * @function - */ - function hideSearch() { - document.documentElement.classList.remove('search-active'); - } - - /** - * Updates search results each time input changes. - * - * Handles: - * - Live search - * - Fuzzy matching fallback - * - Batched result rendering - * - Screen reader announcements - * - * @function update - * @private - */ - function update() { - currentSearchIndex++; - var input = searchInput.value; - - if (input === '') { - hideSearch(); - } else { - showSearch(); - // Scroll fix for iOS Safari - window.scroll(0, -1); - setTimeout(function(){ window.scroll(0, 0); }, 0); - } - - if (input === currentInput) return; - - currentInput = input; - searchResults.innerHTML = ''; - - if (input === '') return; - - /** @type {lunr.Index.Result[]} */ - var results = index.query(function(query) { - var tokens = lunr.tokenizer(input); - query.term(tokens, { boost: 10 }); - query.term(tokens, { - wildcard: lunr.Query.wildcard.TRAILING - }); - }); - - // Fuzzy fallback - if (results.length === 0 && input.length > 2) { - var tokens = lunr.tokenizer(input).filter(t => t.str.length < 20); - if (tokens.length > 0) { - results = index.query(function(query) { - query.term(tokens, { - editDistance: Math.round(Math.sqrt(input.length / 2 - 1)) - }); - }); - } - } - - let screenReaderFeedback = document.getElementById('screen-reader-feedback'); - screenReaderFeedback.innerText = ""; - - if (results.length === 0) { - // No results - var noResultsDiv = document.createElement('div'); - noResultsDiv.classList.add('search-no-result'); - noResultsDiv.innerText = 'No results found'; - searchResults.appendChild(noResultsDiv); - screenReaderFeedback.innerText = 'No results found'; - - } else { - // Render results - var resultsList = document.createElement('ul'); - resultsList.classList.add('search-results-list'); - searchResults.appendChild(resultsList); - - screenReaderFeedback.innerText = - results.length === 1 ? - '1 result found, use arrow keys to read' : - results.length + ' results found, use arrow keys to read'; - - jtd.addEvent(resultsList, 'keydown', function(e) { - handleSearchKeyEvents(searchInput, e); - }); - - addResults(resultsList, results, 0, 10, 100, currentSearchIndex); - } - - /** - * Recursively batch-renders search results to reduce UI blocking. - * - * @param {HTMLElement} resultsList - * @param {lunr.Index.Result[]} results - * @param {number} start - Start index. - * @param {number} batchSize - How many results to render at once. - * @param {number} batchMillis - Delay between batches. - * @param {number} searchIndex - Used to cancel outdated renders. - */ - function addResults(resultsList, results, start, batchSize, batchMillis, searchIndex) { - if (searchIndex !== currentSearchIndex) return; - - for (var i = start; i < start + batchSize; i++) { - if (i === results.length) return; - addResult(resultsList, results[i]); - } - - setTimeout(function() { - addResults(resultsList, results, start + batchSize, batchSize, batchMillis, searchIndex); - }, batchMillis); - } - - /** - * Renders a single search result item. - * - * @param {HTMLElement} resultsList - * @param {lunr.Index.Result} result - */ - function addResult(resultsList, result) { - let doc = docs[result.ref]; - - let resultsListItem = document.createElement('li'); - resultsListItem.classList.add('search-results-list-item'); - resultsList.appendChild(resultsListItem); - - let resultLink = document.createElement('a'); - resultLink.classList.add('search-result'); - resultLink.href = doc.url; - resultsListItem.appendChild(resultLink); - - let resultTitle = document.createElement('div'); - resultTitle.classList.add('search-result-title'); - resultLink.appendChild(resultTitle); - - let resultDoc = document.createElement('div'); - resultDoc.classList.add('search-result-doc'); - resultDoc.innerHTML = ''; - resultTitle.appendChild(resultDoc); - - let resultDocTitle = document.createElement('div'); - resultDocTitle.classList.add('search-result-doc-title'); - resultDocTitle.innerHTML = doc.title; - resultDoc.appendChild(resultDocTitle); - - let resultSection = document.createElement('div'); - resultSection.classList.add('search-result-section'); - resultSection.innerHTML = "In: " + doc.doc; - resultTitle.appendChild(resultSection); - } - } - - // Bind search events - jtd.addEvent(searchInput, 'focus', () => setTimeout(update, 0)); - jtd.addEvent(searchInput, 'keyup', function(e) { - switch (e.keyCode) { - case 27: searchInput.value = ''; break; - case 38: - case 40: - case 13: e.preventDefault(); return; - } - update(); - }); - - jtd.addEvent(searchInput, 'keydown', function(e) { - handleSearchKeyEvents(searchInput, e); - }); - - // Hide search when tabbing away - jtd.addEvent(document, 'keyup', function(e) { - if (e.keyCode === 9) { - let focus = document.activeElement; - let results = document.querySelector('.search'); - if (!results.contains(focus)) hideSearch(); - } - }); - - // Hide search when clicking outside input - jtd.addEvent(document, 'click', function(e) { - if (e.target !== searchInput) hideSearch(); - }); - } - -// -// --------------------------------------------------------- -// Keyboard navigation for search results -// --------------------------------------------------------- - - /** - * Handles arrow key navigation and Enter selection inside search results. - * - * @function handleSearchKeyEvents - * @param {HTMLInputElement} searchInput - The search input element. - * @param {KeyboardEvent} e - Key event. - */ - function handleSearchKeyEvents(searchInput, e) { - switch (e.keyCode) { - case 38: { // Up arrow - e.preventDefault(); - var active = document.querySelector('.search-result.active'); - if (active) { - active.classList.remove('active'); - if (active.parentElement.previousSibling) { - var prev = active.parentElement.previousSibling.querySelector('.search-result'); - prev.classList.add('active'); - prev.focus(); - } - } - return; - } - - case 40: { // Down arrow - e.preventDefault(); - var active = document.querySelector('.search-result.active'); - if (active) { - if (active.parentElement.nextSibling) { - var next = active.parentElement.nextSibling.querySelector('.search-result'); - active.classList.remove('active'); - next.classList.add('active'); - next.focus(); - } - } else { - var first = document.querySelector('.search-result'); - if (first) { - first.classList.add('active'); - first.focus(); - } - } - return; - } - - case 13: { // Enter - e.preventDefault(); - var active = document.querySelector('.search-result.active'); - if (active) active.click(); - return; - } - } - } - // // --------------------------------------------------------- // Navigation link helpers (active link, scroll into view)