Skip to content

Commit bcddfd7

Browse files
authored
perf: Defer the search UI, whole-card results, cleaner index (#904)
* perf: Load the search UI on first use and make result cards one link The pagefind js and css were the last render-blocking requests in the head of every page; they now load when the search popover first opens (button, Ctrl+K), keeping search behaviour identical from the second keystroke of a visit onwards. The result template used to wrap only the title in a link while pagefind's stylesheet gave the whole card a pointer cursor; the card is one block-level link now, with hover and focus-visible styling, and the keyboard navigation follows the flatter markup. * fix: Keep pagination and the end-of-life banner out of the search index Both render inside the article element and were indexed with the page content, polluting excerpts with navigation labels and banner text.
1 parent 1f51229 commit bcddfd7

7 files changed

Lines changed: 94 additions & 59 deletions

File tree

ui/src/css/search.css

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,24 @@
4848
margin-top: 0;
4949
}
5050

51+
/* the whole result card is one link */
52+
a.pagefind-modular-list-inner {
53+
display: block;
54+
text-decoration: none;
55+
}
56+
57+
a.pagefind-modular-list-inner:hover,
58+
a.pagefind-modular-list-inner:focus-visible {
59+
background-color: var(--color-background2);
60+
outline-offset: 2px;
61+
}
62+
63+
.pagefind-modular-list-title {
64+
color: var(--color-brand-primary);
65+
font-weight: 600;
66+
margin: 0;
67+
}
68+
5169
.pagefind-modular-list-breadcrumbs {
5270
font-size: calc(18px * var(--pagefind-ui-scale));
5371
font-weight: 500;

ui/src/js/07-search.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
document.getElementById('search-background').style.display = 'block'
66
document.getElementById('search').style.display = 'block'
77

8-
// focus the textbox after popover appears
9-
focusSearchInput()
10-
// add eventlisteners after popover appears
11-
addNavigationToSearch()
8+
// the search assets load on first use (see footer-scripts.hbs)
9+
window.loadSearch().then(function () {
10+
// focus the textbox after the input exists
11+
focusSearchInput()
12+
// add eventlisteners after popover appears
13+
addNavigationToSearch()
14+
})
1215
}
1316

1417
function closeSearchPopover () {
@@ -37,19 +40,20 @@
3740
}
3841

3942
function addNavigationInSearchResults (event) {
43+
// the focused element is the result card link, a direct child of the li
4044
if (event.key === 'ArrowDown' && document.activeElement.classList.contains('pagefind-modular-list-link')) {
4145
event.preventDefault() // prevent page scrolling
42-
var nextSibling = document.activeElement.parentElement.parentElement.parentElement.nextElementSibling
43-
if (nextSibling) {
44-
nextSibling.querySelector('a').focus()
46+
var nextResult = document.activeElement.closest('li').nextElementSibling
47+
if (nextResult) {
48+
nextResult.querySelector('a').focus()
4549
}
4650
}
4751

4852
if (event.key === 'ArrowUp' && document.activeElement.classList.contains('pagefind-modular-list-link')) {
4953
event.preventDefault() // prevent page scrolling
50-
var previousSibling = document.activeElement.parentElement.parentElement.parentElement.previousElementSibling
51-
if (previousSibling) {
52-
previousSibling.querySelector('a').focus()
54+
var previousResult = document.activeElement.closest('li').previousElementSibling
55+
if (previousResult) {
56+
previousResult.querySelector('a').focus()
5357
}
5458
}
5559
}

ui/src/partials/article.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ data-pagefind-body
1010
>
1111
{{! In antora.yml set asciidoc.attributes.page-end-of-life to true/false}}
1212
{{#if page.attributes.end-of-life}}
13-
<aside class="end-of-life-banner">
13+
<aside class="end-of-life-banner" data-pagefind-ignore>
1414
<h4>This version of the Stackable Data Platform is no longer maintained.</h4>
1515
<p>
1616
{{#if page.canonicalUrl}}

ui/src/partials/footer-scripts.hbs

Lines changed: 60 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,72 @@
22
<script async src="{{{uiRootPath}}}/js/vendor/highlight.js"></script>
33
<script async src="{{{uiRootPath}}}/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
44
<script>
5-
// This script block loads the pagefind search UI.
5+
// Loads the pagefind search UI on first use (see 07-search.js); the
6+
// assets stay off the critical rendering path of every page.
67
// Some styling is customized, these classes are found in search.css.
7-
window.addEventListener('DOMContentLoaded', (event) => {
8-
const instance = new PagefindModularUI.Instance({
9-
// customized rank tuning - see https://pagefind.app/docs/ranking/
10-
ranking: {
11-
termSaturation: 0.4,
12-
termSimilarity: 10.0
13-
}});
14-
instance.add(new PagefindModularUI.Input({
15-
containerElement: "#search-input"
16-
}));
17-
instance.add(new PagefindModularUI.ResultList({
18-
containerElement: "#search-results",
19-
resultTemplate: (result) => {
20-
const el = document.createElement("li");
21-
el.classList.add("pagefind-modular-list-result");
8+
window.loadSearch = (function () {
9+
let ready
2210
23-
const innerEl = document.createElement("div");
24-
innerEl.classList.add("pagefind-modular-list-inner");
25-
el.appendChild(innerEl);
11+
function initSearch () {
12+
const instance = new PagefindModularUI.Instance({
13+
// customized rank tuning - see https://pagefind.app/docs/ranking/
14+
ranking: {
15+
termSaturation: 0.4,
16+
termSimilarity: 10.0
17+
}});
18+
instance.add(new PagefindModularUI.Input({
19+
containerElement: "#search-input"
20+
}));
21+
instance.add(new PagefindModularUI.ResultList({
22+
containerElement: "#search-results",
23+
resultTemplate: (result) => {
24+
const el = document.createElement("li");
25+
el.classList.add("pagefind-modular-list-result");
2626
27-
// Create the child element for the breadcrumbs
28-
const bcEl = document.createElement("p");
29-
bcEl.classList.add("pagefind-modular-list-breadcrumbs");
30-
parts = (result.meta.breadcrumbs ?? '').split('.').map(part => part.trim()).filter(part => part.length > 0);
31-
parts.shift();
32-
parts.pop();
33-
bcEl.innerText = parts.join(' / ');
34-
innerEl.appendChild(bcEl);
27+
// the whole result card is one link
28+
const linkEl = document.createElement("a");
29+
linkEl.classList.add("pagefind-modular-list-link", "pagefind-modular-list-inner");
30+
linkEl.href = result.url;
31+
el.appendChild(linkEl);
3532
36-
// Create the child element for the title
37-
const titleEl = document.createElement("p");
38-
titleEl.classList.add("pagefind-modular-list-title");
39-
innerEl.appendChild(titleEl);
33+
const bcEl = document.createElement("p");
34+
bcEl.classList.add("pagefind-modular-list-breadcrumbs");
35+
const parts = (result.meta.breadcrumbs ?? '').split('.').map(part => part.trim()).filter(part => part.length > 0);
36+
parts.shift();
37+
parts.pop();
38+
bcEl.innerText = parts.join(' / ');
39+
linkEl.appendChild(bcEl);
4040
41-
// Create the anchor element
42-
const linkEl = document.createElement("a");
43-
linkEl.classList.add("pagefind-modular-list-link");
44-
linkEl.href = result.url;
45-
linkEl.innerText = result.meta.title;
46-
titleEl.appendChild(linkEl);
41+
const titleEl = document.createElement("p");
42+
titleEl.classList.add("pagefind-modular-list-title");
43+
titleEl.innerText = result.meta.title;
44+
linkEl.appendChild(titleEl);
4745
48-
// Create the child element for the excerpt
49-
const textEl = document.createElement("p");
50-
textEl.classList.add("pagefind-modular-list-excerpt");
51-
textEl.innerHTML = result.excerpt;
52-
innerEl.appendChild(textEl);
46+
const textEl = document.createElement("p");
47+
textEl.classList.add("pagefind-modular-list-excerpt");
48+
textEl.innerHTML = result.excerpt;
49+
linkEl.appendChild(textEl);
5350
54-
return el;
51+
return el;
52+
}
53+
}));
54+
}
55+
56+
return function () {
57+
if (!ready) {
58+
const css = document.createElement("link");
59+
css.rel = "stylesheet";
60+
css.href = "/pagefind/pagefind-modular-ui.css";
61+
document.head.appendChild(css);
62+
ready = new Promise((resolve, reject) => {
63+
const script = document.createElement("script");
64+
script.src = "/pagefind/pagefind-modular-ui.js";
65+
script.onload = () => { initSearch(); resolve(); };
66+
script.onerror = reject;
67+
document.head.appendChild(script);
68+
});
5569
}
56-
}));
57-
});
70+
return ready;
71+
};
72+
})();
5873
</script>

ui/src/partials/head-scripts.hbs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,3 @@
2222
-->
2323
{{/with}}
2424
<script>var uiRootPath = '{{{uiRootPath}}}'</script>
25-
<script src="/pagefind/pagefind-modular-ui.js"></script>

ui/src/partials/head-styles.hbs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
<link rel="preload" href="{{{uiRootPath}}}/font/noto-sans-latin-400-normal.woff2" as="font" type="font/woff2" crossorigin>
22
<link rel="preload" href="{{{uiRootPath}}}/font/ibm-plex-mono-latin-600-normal.woff2" as="font" type="font/woff2" crossorigin>
33
<link rel="stylesheet" href="{{{uiRootPath}}}/css/site.css">
4-
<link rel="stylesheet" href="/pagefind/pagefind-modular-ui.css">

ui/src/partials/pagination.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{{#unless (eq page.attributes.pagination undefined)}}
22
{{#if (or page.previous page.next)}}
3-
<nav class="pagination">
3+
<nav class="pagination" data-pagefind-ignore>
44
{{#with page.previous}}
55
<span class="prev"><a href="{{{relativize ./url}}}">{{{./content}}}</a></span>
66
{{/with}}

0 commit comments

Comments
 (0)