Skip to content

Commit f0a24ce

Browse files
New search experience via Swiftype (#5223)
* Prototyping new Swiftype search integration * Remove script for building search index * Remove search * Script cleanup * Style adjustments * Relocate search bar to top of left nav * Back out inadvertent package.json additions * Reparent the Swiftype autocomplete container Co-authored-by: Christian Nunciato <[email protected]>
1 parent 5df058e commit f0a24ce

20 files changed

+111
-371
lines changed

CONTRIBUTING.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ Which, on a page inside the `./content/reference` directory, will generate:
5151

5252
- **no_on_this_page** Specify this variable to prevent displaying an "On This Page" TOC on the right nav for the page.
5353
- **block_external_search_index** Specify this variable to prevent crawlers from indexing the page.
54-
- **exclude_from_pulumi_search_index** Specify this variable to prevent the page from appear in internal search results.
55-
5654
## Style guide
5755

5856
### Language and terminology styles

Makefile

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,6 @@ build_components:
4545
@echo -e "\033[0;32mBUILD COMPONENTS:\033[0m"
4646
yarn --cwd components run build
4747

48-
.PHONY: build_search_index
49-
build_search_index:
50-
@echo -e "\033[0;32mBUILD SEARCH INDEX:\033[0m"
51-
node ./scripts/build-search-index.js < ./public/docs/search-data/index.json > ./public/docs/search-index.json
52-
rm -rf ./public/docs/search-data
53-
5448
.PHONY: generate
5549
generate:
5650
@echo -e "\033[0;32mGENERATE:\033[0m"

assets/config/postcss.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,15 @@ module.exports = {
6868
],
6969

7070
// Whitelist custom parent selectors and their children.
71-
whitelistPatterns: [/^fa-/, /^hs-/, /^highlight$/, /^pagination$/, /^code-/, /^copy-/, /^carousel/, /^bg-/, /BambooHR-/],
71+
whitelistPatterns: [/^fa-/, /^hs-/, /^highlight$/, /^pagination$/, /^code-/, /^copy-/, /^carousel/, /^bg-/, /^st-/],
7272
whitelistPatternsChildren: [
7373
/^hs-/,
7474
/^highlight$/,
7575
/^pagination$/,
7676
/^code-/,
7777
/^copy-/,
7878
/^carousel/,
79+
/^st-/,
7980

8081
// Whitelist our web components along with any of their descendent selectors.
8182
/^pulumi-chooser/,

assets/js/search.js

Lines changed: 32 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -1,172 +1,38 @@
1-
"use strict";
2-
3-
(function () {
4-
var searchBox = document.getElementById("search-query");
5-
var spinner = document.getElementById("search-spinner");
6-
var searchResultsContainer = document.getElementById("search-results");
7-
8-
// Use a worker to download and setup the index in the background.
9-
var worker = new Worker("/js/search-worker.js");
10-
worker.onmessage = function (message) {
11-
var payload = message.data.payload;
12-
displaySearchResults(payload.results);
13-
};
14-
15-
// Extract the query from the browser's URL.
16-
var query = getQueryVariable("q");
17-
if (query) {
18-
// Set the search-box's value to the query.
19-
searchBox.value = query;
20-
// Update the page title to include the query.
21-
document.title = query + " - Pulumi";
22-
// Kick-off the search by sending a message to the worker.
23-
worker.postMessage({ type: "search", payload: query });
24-
} else {
25-
// If no query, display empty results.
26-
displaySearchResults([]);
27-
}
28-
29-
// Display the results of the search.
30-
function displaySearchResults(results) {
31-
// Hide the spinner.
32-
spinner.style.display = "none";
33-
34-
if (results.length) {
35-
// Group the results by category.
36-
var categoryMap = {};
37-
for (var i = 0; i < results.length; i++) {
38-
var result = results[i];
39-
var categoryName = getCategoryName(result.url);
40-
var category = categoryMap[categoryName] = categoryMap[categoryName] || [];
41-
prepareResult(result, categoryName);
42-
category.push(result);
43-
}
44-
45-
// Build up the HTML to display.
46-
var appendString = "";
47-
for (var i = 0; i < categories.length; i++) {
48-
var categoryName = categories[i].name;
49-
var category = categoryMap[categoryName];
50-
if (category && category.length > 0) {
51-
appendString += buildCategoryString(categoryName, category);
1+
// Swiftype appends the autocomplete results container to the body element, which prevents us
2+
// from being able to position it in a way that scrolls alongside the other content in the L2 nav.
3+
// So we listen for DOM changes, and when Swiftype appends the element, we reposition it below the
4+
// input field.
5+
6+
// Only bother doing this if we're on a page with a search box.
7+
if (document.querySelector("#search-container")) {
8+
const observer = new MutationObserver((mutations, observer) => {
9+
var [ mutation ] = mutations;
10+
11+
// Only bother when nodes are added.
12+
if (mutation && mutation.addedNodes && mutation.addedNodes.length > 0) {
13+
const [ newNode ] = mutation.addedNodes;
14+
15+
if (newNode && (typeof newNode.getAttribute === "function") && newNode.getAttribute("id") === "st-injected-content") {
16+
17+
// Find our results container and reparent the Swiftype container with it.
18+
var resultsContainer = document.querySelector("#search-results");
19+
if (resultsContainer) {
20+
resultsContainer.appendChild(newNode);
5221
}
22+
23+
// Stop listening.
24+
observer.disconnect();
5325
}
54-
searchResultsContainer.innerHTML = appendString;
55-
} else {
56-
searchResultsContainer.innerHTML = "<p>No results found.</p>";
5726
}
58-
}
27+
});
5928

60-
var defaultCategory = "Other";
61-
var categories = [
29+
// Start listening for DOM mutation events.
30+
observer.observe(
31+
document.querySelector("body"),
6232
{
63-
name: "APIs",
64-
predicate: function (url) {
65-
return url.startsWith("/docs/reference/pkg/");
66-
}
33+
attributes: false,
34+
childList: true, // New childNodes are all we care about.
35+
subtree: false,
6736
},
68-
{
69-
name: "CLI",
70-
predicate: function (url) {
71-
return url.startsWith("/docs/reference/cli/");
72-
}
73-
},
74-
{
75-
name: "Tutorials",
76-
predicate: function (url) {
77-
return url.startsWith("/docs/get-started/") ||
78-
url.startsWith("/docs/tutorials/") ||
79-
url.startsWith("/docs/guides/");
80-
}
81-
},
82-
{
83-
name: defaultCategory,
84-
predicate: function (url) {
85-
return true;
86-
}
87-
},
88-
];
89-
90-
function getCategoryName(url) {
91-
for (var i = 0; i < categories.length; i++) {
92-
var category = categories[i];
93-
if (category.predicate(url)) {
94-
return category.name;
95-
}
96-
}
97-
return defaultCategory;
98-
}
99-
100-
function prepareResult(result, categoryName) {
101-
switch (categoryName) {
102-
case "APIs":
103-
if (result.title.startsWith("Module ")) {
104-
result.display = result.title.substring("Module ".length);
105-
result.type = "module";
106-
return;
107-
} else if (result.title.startsWith("Package ")) {
108-
result.display = result.title.substring("Package ".length);
109-
result.type = "package";
110-
return;
111-
}
112-
break;
113-
114-
case "CLI":
115-
if (result.title.length === 0 && result.url.startsWith("/docs/reference/cli/")) {
116-
var regex = /\/docs\/reference\/cli\/([a-z_]+)/gm;
117-
var match = regex.exec(result.url)
118-
if (match !== null) {
119-
result.display = match[1].replace(/_/g, " ");
120-
return;
121-
}
122-
}
123-
break;
124-
}
125-
126-
result.display = result.title || result.url;
127-
}
128-
129-
function buildCategoryString(categoryName, category) {
130-
var appendString = "<div class='search-results-category'><h2>" + categoryName + " (" + category.length + ")</h2>";
131-
132-
// Display the top 5 results first.
133-
appendString += "<ul>";
134-
var topResults = category.splice(0, 5);
135-
for (var i = 0; i < topResults.length; i++) {
136-
var item = topResults[i];
137-
var prefix = getPrefix(item, categoryName);
138-
appendString += "<li><a href='" + item.url + "' title='" + item.display + "'>" + prefix + item.display + "</a>";
139-
}
140-
appendString += "</ul>";
141-
142-
// Now display any remaining results, sorted alphabetically.
143-
if (category.length > 0) {
144-
category.sort(function (l, r) {
145-
return l.display.toUpperCase() > r.display.toUpperCase() ? 1 : -1;
146-
});
147-
appendString += "<ul>";
148-
for (var i = 0; i < category.length; i++) {
149-
var item = category[i];
150-
var prefix = getPrefix(item, categoryName);
151-
appendString += "<li><a href='" + item.url + "'>" + prefix + item.display + "</a>";
152-
}
153-
appendString += "</ul>";
154-
}
155-
156-
appendString += "</div>";
157-
return appendString;
158-
}
159-
160-
function getPrefix(result, categoryName) {
161-
if (result.type) {
162-
switch (result.type) {
163-
case "module":
164-
return "<span class='symbol module' title='Module'></span>";
165-
case "package":
166-
return "<span class='symbol package' title='Package'></span>"
167-
}
168-
}
169-
170-
return "";
171-
}
172-
})();
37+
);
38+
}

assets/sass/_search.scss

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,54 @@
1-
.search-results-category {
2-
@apply mb-4 justify-between flex-1 p-4 bg-gray-200 text-sm overflow-auto rounded;
1+
// Override the default styles of the Swiftype input field.
2+
.st-default-search-input {
3+
display: block !important;
4+
width: 100% !important;
5+
font-size: .875rem !important;
6+
padding: .75rem !important;
7+
padding-left: 2.5rem !important;
8+
border-radius: .25rem !important;
9+
border-color: #cbd5e0 !important; /* border-gray-400 */
10+
font-family: "Open Sans" !important;
11+
background: none !important;
312

4-
&:not(:last-of-type) {
5-
@apply mr-4
6-
}
13+
@include transition;
714

8-
h2 {
9-
@apply mt-0 mb-4 text-gray-700 text-xl;
15+
&:focus {
16+
border-color: #52a6da !important; /* border-blue-500 */
1017
}
1118

12-
ul {
13-
@apply p-0 list-none;
19+
@screen md {
20+
margin-right: 1em !important;
21+
}
22+
}
1423

15-
li {
16-
.symbol {
17-
&:before {
18-
@apply text-white text-xs rounded mr-2 px-1;
19-
}
24+
// Override the default styles of the Swiftype autocomplete results container.
25+
.st-default-autocomplete {
26+
z-index: 40 !important; /* z-40 */
2027

21-
&.module {
22-
&:before {
23-
content: "M";
24-
@apply bg-green-700;
25-
}
26-
}
28+
// Swiftype's JS imperatively positions the autocomplete container in relation to the top-left
29+
// corner of the document, which is okay if your search box scrolls with the page, but since ours
30+
// scrolls and sticks independently of the main content pane, this doesn't work. Overriding the
31+
// top and left settings allows the container to be positioned absolutely in place.
32+
top: auto !important;
33+
left: auto !important;
2734

28-
&.package {
29-
&:before {
30-
content: "P";
31-
@apply bg-purple-700;
32-
}
33-
}
35+
.st-query-present {
36+
.st-ui-result {
37+
.st-ui-type-heading {
38+
font-size: 0.75rem !important; /* text-xs */
39+
color: #4387c7 !important; /* text-blue-600 */
40+
margin-bottom: 4px !important;
41+
}
42+
.st-ui-type-detail {
43+
color: #4a5568 !important; /* text-gray-600 */
3444
}
3545
}
3646
}
3747
}
48+
49+
// Override the default styles of the results overlay.
50+
.st-ui-container {
51+
@screen lg {
52+
top: 80px !important;
53+
}
54+
}

config/marketing-dev/config.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
ignoreFiles = [ "content/docs/.*" ]
1+
ignoreFiles = [ "content/docs/reference/pkg/*" ]
22
refLinksErrorLevel = "WARNING"

content/docs/_index.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
title: Documentation
33
linktitle: Docs
44
meta_desc: Learn how to create, deploy, and manage infrastructure on any cloud using Pulumi's open source infrastructure as code SDK.
5-
exclude_from_pulumi_search_index: true
65
no_on_this_page: true
76
menu:
87
header:

content/docs/search-data.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

content/docs/search.md

Lines changed: 0 additions & 6 deletions
This file was deleted.

layouts/docs/list.html

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ <h1>{{ .Title }}</h1>
1616

1717
<div class="md:w-3/12 md:pl-8">
1818
<div class="sticky-sidebar">
19-
<div class="mt-10 pt-8 border-t-2 border-gray-400 md:border-none md:block md:mb-4 md:pt-0 md:mt-0">
20-
{{ partial "docs/search.html" . }}
21-
</div>
22-
2319
<div class="ml-2 hidden md:block">
2420
{{ partial "docs/right-nav.html" . }}
2521
</div>
@@ -32,7 +28,12 @@ <h1>{{ .Title }}</h1>
3228

3329
<div class="md:w-3/12 pr-8 mb-2 pt-8 md:order-first md:border-none md:pt-0 md:mt-0">
3430
<div class="sticky-sidebar">
35-
{{ partial "docs/toc.html" . }}
31+
<div class="md:mt-1 mb-6">
32+
{{ partial "docs/search.html" . }}
33+
</div>
34+
<div>
35+
{{ partial "docs/toc.html" . }}
36+
</div>
3637
</div>
3738
</div>
3839
</div>

layouts/docs/search-data.json

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)