Skip to content

Commit f0a7e6b

Browse files
author
maxiloc
authored
feat(v2): modification for v2 (#112)
- Add a no result screen. Fixes #92 - Change class prefix. Fixes #102 - Add a transformData option - Add searchBox option - Add a layout option
1 parent b70cf94 commit f0a7e6b

File tree

5 files changed

+102
-25
lines changed

5 files changed

+102
-25
lines changed

dev/app.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ docsearch({
44
apiKey: 'e3d767b736584dbe6d4c35f7cf7d4633',
55
indexName: 'react-native',
66
inputSelector: '#search-input',
7-
autocompleteOptions: {
8-
debug: true
9-
}
7+
debug: true
108
});
119

1210
document.getElementById('search-input').focus();

src/lib/DocSearch.js

+38-9
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,12 @@ class DocSearch {
4040
debug: false,
4141
hint: false,
4242
autoselect: true
43-
}
43+
},
44+
transformData = false,
45+
enhancedSearchInput = false,
46+
layout = 'collumns'
4447
}) {
45-
DocSearch.checkArguments({apiKey, indexName, inputSelector, debug, algoliaOptions, autocompleteOptions});
48+
DocSearch.checkArguments({apiKey, indexName, inputSelector, debug, algoliaOptions, autocompleteOptions, transformData, enhancedSearchInput, layout});
4649

4750
this.apiKey = apiKey;
4851
this.appId = appId;
@@ -52,15 +55,25 @@ class DocSearch {
5255
let autocompleteOptionsDebug = autocompleteOptions && autocompleteOptions.debug ? autocompleteOptions.debug: false;
5356
autocompleteOptions.debug = debug || autocompleteOptionsDebug;
5457
this.autocompleteOptions = autocompleteOptions;
58+
this.autocompleteOptions.cssClasses = {
59+
prefix: 'ds'
60+
};
61+
62+
this.isSimpleLayout = (layout === 'simple');
5563

5664
this.client = algoliasearch(this.appId, this.apiKey);
5765
this.client.addAlgoliaAgent('docsearch.js ' + version);
5866

67+
if (enhancedSearchInput) {
68+
DocSearch.injectSearchBox(this.input);
69+
}
70+
5971
this.autocomplete = autocomplete(this.input, autocompleteOptions, [{
60-
source: this.getAutocompleteSource(),
72+
source: this.getAutocompleteSource(transformData),
6173
templates: {
62-
suggestion: DocSearch.getSuggestionTemplate(),
63-
footer: templates.footer
74+
suggestion: DocSearch.getSuggestionTemplate(this.isSimpleLayout),
75+
footer: templates.footer,
76+
empty: DocSearch.getEmptyTemplate()
6477
}
6578
}]);
6679
this.autocomplete.on(
@@ -89,6 +102,11 @@ class DocSearch {
89102
}
90103
}
91104

105+
static injectSearchBox(input) {
106+
input.before(templates.searchBox);
107+
input.remove();
108+
}
109+
92110
/**
93111
* Returns the matching input from a CSS selector, null if none matches
94112
* @function getInputFromSelector
@@ -108,14 +126,18 @@ class DocSearch {
108126
* @returns {function} Method to be passed as the `source` option of
109127
* autocomplete
110128
*/
111-
getAutocompleteSource() {
129+
getAutocompleteSource(transformData) {
112130
return (query, callback) => {
113131
this.client.search([{
114132
indexName: this.indexName,
115133
query: query,
116134
params: this.algoliaOptions
117135
}]).then((data) => {
118-
callback(DocSearch.formatHits(data.results[0].hits));
136+
let hits = data.results[0].hits;
137+
if (transformData) {
138+
hits = transformData(hits) || hits;
139+
}
140+
callback(DocSearch.formatHits(hits));
119141
});
120142
};
121143
}
@@ -187,10 +209,17 @@ class DocSearch {
187209
return null;
188210
}
189211

190-
static getSuggestionTemplate() {
212+
static getEmptyTemplate() {
213+
return (args) => {
214+
return Hogan.compile(templates.empty).render(args);
215+
};
216+
}
217+
218+
static getSuggestionTemplate(isSimpleLayout) {
191219
const template = Hogan.compile(templates.suggestion);
192220
return (suggestion) => {
193-
return template.render(suggestion);
221+
isSimpleLayout = isSimpleLayout || false;
222+
return template.render({isSimpleLayout, ...suggestion});
194223
};
195224
}
196225

src/lib/templates.js

+50
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ let templates = {
77
<div class="${suggestionPrefix}
88
{{#isCategoryHeader}}${suggestionPrefix}__main{{/isCategoryHeader}}
99
{{#isSubCategoryHeader}}${suggestionPrefix}__secondary{{/isSubCategoryHeader}}
10+
{{#isSimpleLayout}}suggestion-layout-simple{{/isSimpleLayout}}
1011
">
1112
<div class="${suggestionPrefix}--category-header">{{{category}}}</div>
1213
<div class="${suggestionPrefix}--wrapper">
@@ -27,6 +28,55 @@ let templates = {
2728
<div class="${footerPrefix}">
2829
Search by <a class="${footerPrefix}--logo" href="https://www.algolia.com/docsearch">Algolia</a>
2930
</div>
31+
`,
32+
empty: `
33+
<div class="${suggestionPrefix}">
34+
<div class="${suggestionPrefix}--wrapper">
35+
<div class="${suggestionPrefix}--content ${suggestionPrefix}--no-result">
36+
<div class="${suggestionPrefix}--title">
37+
<div class="${suggestionPrefix}--text">
38+
No results found for query <b>{{{query}}}</b>
39+
</div>
40+
</div>
41+
</div>
42+
</div>
43+
</div>
44+
`,
45+
searchBox: `
46+
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
47+
<symbol xmlns="http://www.w3.org/2000/svg" id="sbx-icon-search-18" viewBox="0 0 40 40">
48+
<path d="M30.776 27.146l-1.32-1.32-3.63 3.632 1.32 1.32 3.63-3.632zm1.368 1.368l6.035 6.035c.39.39.4 1.017.008 1.408l-2.23 2.23c-.387.387-1.015.387-1.41-.008l-6.035-6.035 3.63-3.63zm-8.11 1.392c-2.356 1.363-5.092 2.143-8.01 2.143C7.174 32.05 0 24.873 0 16.023S7.174 0 16.024 0c8.85 0 16.025 7.174 16.025 16.024 0 2.918-.78 5.654-2.144 8.01l8.96 8.962c1.175 1.174 1.184 3.07.008 4.246l-1.632 1.632c-1.17 1.17-3.067 1.173-4.247-.007l-8.96-8.96zm-8.01.54c7.965 0 14.422-6.457 14.422-14.422 0-7.965-6.457-14.422-14.422-14.422-7.965 0-14.422 6.457-14.422 14.422 0 7.965 6.457 14.422 14.422 14.422zm0-2.403c6.638 0 12.018-5.38 12.018-12.02 0-6.636-5.38-12.017-12.018-12.017-6.637 0-12.018 5.38-12.018 12.018 0 6.638 5.38 12.02 12.018 12.02zm0-1.402c5.863 0 10.616-4.752 10.616-10.616 0-5.863-4.753-10.616-10.616-10.616-5.863 0-10.616 4.753-10.616 10.616 0 5.864 4.753 10.617 10.616 10.617z"
49+
fill-rule="evenodd" />
50+
</symbol>
51+
<symbol xmlns="http://www.w3.org/2000/svg" id="sbx-icon-clear-5" viewBox="0 0 20 20">
52+
<path d="M10 20c5.523 0 10-4.477 10-10S15.523 0 10 0 0 4.477 0 10s4.477 10 10 10zm1.35-10.123l3.567 3.568-1.225 1.226-3.57-3.568-3.567 3.57-1.226-1.227 3.568-3.568-3.57-3.57 1.227-1.224 3.568 3.568 3.57-3.567 1.224 1.225-3.568 3.57zM10 18.272c4.568 0 8.272-3.704 8.272-8.272S14.568 1.728 10 1.728 1.728 5.432 1.728 10 5.432 18.272 10 18.272z"
53+
fill-rule="evenodd" />
54+
</symbol>
55+
</svg>
56+
57+
<form action="void(0);" novalidate="novalidate" class="searchbox sbx-custom">
58+
<div role="search" class="sbx-custom__wrapper">
59+
<input type="search" name="search" placeholder="Search your website" autocomplete="off" required="required" class="sbx-custom__input">
60+
<button type="submit" title="Submit your search query." class="sbx-custom__submit">
61+
<svg role="img" aria-label="Search">
62+
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-search-18"></use>
63+
</svg>
64+
</button>
65+
<button type="reset" title="Clear the search query." class="sbx-custom__reset">
66+
<svg role="img" aria-label="Reset">
67+
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-clear-5"></use>
68+
</svg>
69+
</button>
70+
</div>
71+
</form>
72+
<!--Js: focus search input after reset-->
73+
<script type="text/javascript">
74+
//<![CDATA[
75+
document.querySelector('.searchbox [type="reset"]').addEventListener('click', function() {
76+
this.parentNode.querySelector('input').focus();
77+
});
78+
//]]>
79+
</script>
3080
`
3181
};
3282

src/styles/main.scss

+9-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// - Adding a second colum to let the content breath if enough room available
77

88
// Main autocomplete wrapper
9-
.aa-dropdown-menu {
9+
.ds-dropdown-menu {
1010
background-color: #FFF;
1111
border: 1px solid #333;
1212
border-radius: 4px;
@@ -56,10 +56,10 @@
5656
}
5757

5858
// Selected suggestion
59-
.aa-cursor .algolia-docsearch-suggestion--content {
59+
.ds-cursor .algolia-docsearch-suggestion--content {
6060
color: $color-selected-text;
6161
}
62-
.aa-cursor .algolia-docsearch-suggestion {
62+
.ds-cursor .algolia-docsearch-suggestion {
6363
background: $color-selected-background;
6464
}
6565

@@ -79,10 +79,10 @@
7979
border-top: 1px solid lighten($color-border, 60%);
8080
}
8181

82-
.algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--content,
83-
.algolia-docsearch-suggestion__secondary .algolia-docsearch-suggestion--content {
84-
border-top: 0;
85-
}
82+
.algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--content,
83+
.algolia-docsearch-suggestion__secondary .algolia-docsearch-suggestion--content {
84+
border-top: 0;
85+
}
8686

8787
.algolia-docsearch-suggestion--subcategory-inline {
8888
display: inline-block;
@@ -121,7 +121,7 @@
121121
// BREAKPOINT 1:
122122
// Screen is big enough to display the text snippets
123123
@media (min-width: $breakpoint-medium) {
124-
.aa-dropdown-menu {
124+
.ds-dropdown-menu {
125125
min-width: $dropdown-min-width-medium;
126126
}
127127
.algolia-docsearch-suggestion--text {
@@ -134,7 +134,7 @@
134134
// BREAKPOINT 2:
135135
// Screen is big enough to display results in two columns
136136
@media (min-width: $breakpoint-large) {
137-
.aa-dropdown-menu {
137+
.ds-dropdown-menu {
138138
min-width: $dropdown-min-width-large;
139139
}
140140
.algolia-docsearch-suggestion {

test/DocSearch-test.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ describe('DocSearch', () => {
168168
// Then
169169
expect(typeof actual.algoliaOptions).toEqual('object');
170170
expect(actual.algoliaOptions.anOption).toEqual(42);
171-
expect(actual.autocompleteOptions).toEqual({debug: false, anOption: 44});
171+
expect(actual.autocompleteOptions).toEqual({debug: false, "cssClasses": { "prefix": "ds" }, anOption: 44});
172172
});
173173
it('should instantiate algoliasearch with the correct values', () => {
174174
// Given
@@ -205,7 +205,7 @@ describe('DocSearch', () => {
205205

206206
// Then
207207
expect(AutoComplete.calledOnce).toBe(true);
208-
expect(AutoComplete.calledWith($input, {anOption: '44', debug: false})).toBe(true);
208+
expect(AutoComplete.calledWith($input, {anOption: '44', "cssClasses": { "prefix": "ds" }, debug: false})).toBe(true);
209209
});
210210
it('should listen to the selected and shown event of autocomplete', () => {
211211
// Given
@@ -980,11 +980,11 @@ describe('DocSearch', () => {
980980
let actual = DocSearch.getSuggestionTemplate();
981981

982982
// When
983-
actual('foo');
983+
actual({'foo': 'bar'});
984984

985985
// Then
986986
expect(render.calledOnce).toBe(true);
987-
expect(render.calledWith('foo')).toBe(true);
987+
expect(render.args[0][0]).toEqual({'isSimpleLayout': false, 'foo': 'bar'});
988988
});
989989
});
990990
});

0 commit comments

Comments
 (0)