🔧 🌱 Complete the algolia search feature, Close #9.

This commit is contained in:
凡梦星尘 2022-07-31 18:01:57 +08:00
parent 9a4883832f
commit c1e7e59646
7 changed files with 182 additions and 139 deletions

View File

@ -1,130 +0,0 @@
/* global instantsearch, algoliasearch, CONFIG, pjax */
document.addEventListener('DOMContentLoaded', () => {
const { indexName, appID, apiKey, hits } = CONFIG.algolia;
const search = instantsearch({
indexName,
searchClient : algoliasearch(appID, apiKey),
searchFunction: helper => {
if (document.querySelector('.search-input').value) {
helper.search();
}
}
});
if (typeof pjax === 'object') {
search.on('render', () => {
pjax.refresh(document.querySelector('.algolia-hits'));
});
}
// Registering Widgets
search.addWidgets([
instantsearch.widgets.configure({
hitsPerPage: hits.per_page || 10
}),
instantsearch.widgets.searchBox({
container : '.search-input-container',
placeholder : CONFIG.i18n.placeholder,
// Hide default icons of algolia search
showReset : false,
showSubmit : false,
showLoadingIndicator: false,
cssClasses : {
input: 'search-input'
}
}),
instantsearch.widgets.stats({
container: '.algolia-stats',
templates: {
text: data => {
const stats = CONFIG.i18n.hits_time
.replace('${hits}', data.nbHits)
.replace('${time}', data.processingTimeMS);
return `<span>${stats}</span>
<img src="${CONFIG.images}/logo-algolia-nebula-blue-full.svg" alt="Algolia">`;
}
},
cssClasses: {
text: 'search-stats'
}
}),
instantsearch.widgets.hits({
container : '.algolia-hits',
escapeHTML: false,
templates : {
item: data => {
const { title, excerpt, excerptStrip, contentStripTruncate } = data._highlightResult;
let result = `<a href="${data.permalink}" class="search-result-title">${title.value}</a>`;
const content = excerpt || excerptStrip || contentStripTruncate;
if (content && content.value) {
const div = document.createElement('div');
div.innerHTML = content.value;
result += `<a href="${data.permalink}"><p class="search-result">${div.textContent.substring(0, 100)}...</p></a>`;
}
return result;
},
empty: data => {
return `<div class="algolia-hits-empty">
${CONFIG.i18n.empty.replace('${query}', data.query)}
</div>`;
}
},
cssClasses: {
list: 'search-result-list'
}
}),
instantsearch.widgets.pagination({
container: '.algolia-pagination',
scrollTo : false,
showFirst: false,
showLast : false,
templates: {
first : '<i class="fa fa-angle-double-left"></i>',
last : '<i class="fa fa-angle-double-right"></i>',
previous: '<i class="fa fa-angle-left"></i>',
next : '<i class="fa fa-angle-right"></i>'
},
cssClasses: {
list : ['pagination', 'algolia-pagination'],
item : 'pagination-item',
link : 'page-number',
selectedItem: 'current',
disabledItem: 'disabled-item'
}
})
]);
search.start();
// Handle and trigger popup window
document.querySelectorAll('.popup-trigger').forEach(element => {
element.addEventListener('click', () => {
document.body.classList.add('search-active');
setTimeout(() => document.querySelector('.search-input').focus(), 500);
});
});
// Monitor main search box
const onPopupClose = () => {
document.body.classList.remove('search-active');
};
document.querySelector('.search-pop-overlay').addEventListener('click', event => {
if (event.target === document.querySelector('.search-pop-overlay')) {
onPopupClose();
}
});
document.querySelector('.popup-btn-close').addEventListener('click', onPopupClose);
document.addEventListener('pjax:success', onPopupClose);
window.addEventListener('keyup', event => {
if (event.key === 'Escape') {
onPopupClose();
}
});
});

141
assets/js/third-party/search/algolia.js vendored Normal file
View File

@ -0,0 +1,141 @@
/* global instantsearch, algoliasearch, CONFIG, pjax */
document.addEventListener('DOMContentLoaded', () => {
const algoiajs = NexT.utils.getCDNResource(NexT.CONFIG.algolia.js);
const instantschjs = NexT.utils.getCDNResource(NexT.CONFIG.algolia.instantjs);
NexT.utils.getScript(algoiajs, {});
NexT.utils.getScript(instantschjs, {}).then(() => {
const { indexname, appid, apikey, hits } = NexT.CONFIG.algolia.cfg;
const indexName = indexname;
const search = instantsearch({
indexName,
searchClient: algoliasearch(appid, apikey),
searchFunction: helper => {
if (document.querySelector('.search-input').value) {
helper.search();
}
}
});
if (typeof pjax === 'object') {
search.on('render', () => {
pjax.refresh(document.querySelector('.algolia-hits'));
});
}
// Registering Widgets
search.addWidgets([
instantsearch.widgets.configure({
hitsPerPage: hits.perpage || 10
}),
instantsearch.widgets.searchBox({
container: '.search-input-container',
placeholder: NexT.CONFIG.i18n.placeholder,
// Hide default icons of algolia search
showReset: false,
showSubmit: false,
showLoadingIndicator: false,
cssClasses: {
input: 'search-input'
}
}),
instantsearch.widgets.stats({
container: '.algolia-stats',
templates: {
text: data => {
const stats = NexT.CONFIG.i18n.hits_time
.replace('${hits}', data.nbHits)
.replace('${time}', data.processingTimeMS);
return `<span>${stats}</span>`;
//<img src="${CONFIG.images}/logo-algolia-nebula-blue-full.svg" alt="Algolia">`;
}
},
cssClasses: {
text: 'search-stats'
}
}),
instantsearch.widgets.hits({
container: '.algolia-hits',
escapeHTML: false,
templates: {
item: data => {
const { title, excerpt, excerptStrip, contentStripTruncate } = data._highlightResult;
let result = `<a href="${data.permalink}" class="search-result-title">${title.value}</a>`;
const content = excerpt || excerptStrip || contentStripTruncate;
if (content && content.value) {
const div = document.createElement('div');
div.innerHTML = content.value;
result += `<a href="${data.permalink}"><p class="search-result">${div.textContent.substring(0, 100)}...</p></a>`;
}
return result;
},
empty: data => {
return `<div class="algolia-hits-empty">
${NexT.CONFIG.i18n.empty.replace('${query}', data.query)}
</div>`;
}
},
cssClasses: {
list: 'search-result-list'
}
}),
instantsearch.widgets.pagination({
container: '.algolia-pagination',
scrollTo: false,
showFirst: false,
showLast: false,
templates: {
first: '<i class="fa fa-angle-double-left"></i>',
last: '<i class="fa fa-angle-double-right"></i>',
previous: '<i class="fa fa-angle-left"></i>',
next: '<i class="fa fa-angle-right"></i>'
},
cssClasses: {
list: ['pagination', 'algolia-pagination'],
item: 'pagination-item',
link: 'page-number',
selectedItem: 'current',
disabledItem: 'disabled-item'
}
})
]);
search.start();
// Handle and trigger popup window
document.querySelectorAll('.popup-trigger').forEach(element => {
element.addEventListener('click', () => {
document.body.classList.add('search-active');
setTimeout(() => document.querySelector('.search-input').focus(), 500);
});
});
// Monitor main search box
const onPopupClose = () => {
document.body.classList.remove('search-active');
};
document.querySelector('.search-pop-overlay').addEventListener('click', event => {
if (event.target === document.querySelector('.search-pop-overlay')) {
onPopupClose();
}
});
document.querySelector('.popup-btn-close').addEventListener('click', onPopupClose);
document.addEventListener('pjax:success', onPopupClose);
window.addEventListener('keyup', event => {
if (event.key === 'Escape') {
onPopupClose();
}
});
});;
});

View File

@ -39,8 +39,8 @@ analytics:
addthis: addthis:
js: https://s7.addthis.com/js/300/addthis_widget.js js: https://s7.addthis.com/js/300/addthis_widget.js
# 评论组件资源 # 评论组件
# Comment component Resources # Comment component
waline: waline:
js: js:
name: '@waline/client' name: '@waline/client'
@ -71,3 +71,14 @@ utterances:
livere: livere:
js: https://cdn-city.livere.com/js/embed.dist.js js: https://cdn-city.livere.com/js/embed.dist.js
# 全文搜索
# Full text search
algolia:
name: algoliasearch
version: 4.13.0
file: dist/algoliasearch-lite.umd.js
instant:
name: instantsearch.js
version: 4.40.5
file: dist/instantsearch.production.min.js

View File

@ -898,15 +898,17 @@ params:
# --------------------------------------------------------------- # ---------------------------------------------------------------
# TODO # 内容搜索服务
# 内容搜索服务(暂时未实现)
# Search Services # Search Services
# --------------------------------------------------------------- # ---------------------------------------------------------------
# Algolia Search # Algolia Search
# For more information: https://www.algolia.com # For more information: https://www.algolia.com
algoliaSearch: algoliaSearch:
enable: false enable: true
appId: #<algolia app id>
apiKey: #<algolia api key>
indexName: #<algolia index name>
hits: hits:
perPage: 10 perPage: 10

View File

@ -35,7 +35,6 @@
"bookmark" .Site.Params.bookmark "bookmark" .Site.Params.bookmark
"lazyload" .Site.Params.lazyload "lazyload" .Site.Params.lazyload
"motion" .Site.Params.motion "motion" .Site.Params.motion
"localSearch" .Site.Params.localSearch
"i18n" (dict "i18n" (dict
"placeholder" (T "SearchPh") "placeholder" (T "SearchPh")
"empty" (T "SearchEmpty") "empty" (T "SearchEmpty")
@ -44,6 +43,20 @@
) )
}} }}
{{ if .Site.Params.localSearch.enable }}
{{ $localSearch := dict "localSearch" .Site.Params.localSearch }}
{{ $config = merge $config $localSearch }}
{{ end }}
{{ if .Site.Params.algoliaSearch.enable }}
{{ $algoliaSearch := dict
"js" .Site.Data.resources.algolia
"instantjs" .Site.Data.resources.instant
"cfg" .Site.Params.algoliaSearch
}}
{{ $config = merge $config (dict "algolia" $algoliaSearch) }}
{{ end }}
{{ with .Site.Params.waline }} {{ with .Site.Params.waline }}
{{ $waline := dict {{ $waline := dict
"js" $.Site.Data.resources.waline.js "js" $.Site.Data.resources.waline.js

View File

@ -64,11 +64,17 @@
{{- $utterancesjs := resources.Get "js/third-party/comments/utterances.js" }} {{- $utterancesjs := resources.Get "js/third-party/comments/utterances.js" }}
{{- $nextjs = $nextjs | append $utterancesjs }} {{- $nextjs = $nextjs | append $utterancesjs }}
{{- end }} {{- end }}
{{- if .Site.Params.localSearch.enable }}
{{- $search := resources.Get "js/third-party/search/local.js" }}
{{- $nextjs = $nextjs | append $search }}
{{ end }}
{{- if .Site.Params.algoliaSearch.enable }}
{{- $search := resources.Get "js/third-party/search/algolia.js" }}
{{- $nextjs = $nextjs | append $search }}
{{ end }}
{{- $nextjs = $nextjs | resources.Concat "js/main.js"}} {{- $nextjs = $nextjs | resources.Concat "js/main.js"}}
{{ if hugo.IsProduction }} {{ if hugo.IsProduction }}
{{- $nextjs = $nextjs | minify | fingerprint }} {{- $nextjs = $nextjs | minify | fingerprint }}
{{ end }} {{ end }}
<script type="text/javascript" src="{{ $nextjs.RelPermalink }}" defer></script> <script type="text/javascript" src="{{ $nextjs.RelPermalink }}" defer></script>
{{- $search := resources.Get "js/third-party/search/local-search.js" }}
<script type="text/javascript" src="{{ $search.RelPermalink }}" defer></script>