diff --git a/docs/css/instantsearch.css b/docs/css/instantsearch.css new file mode 100644 index 0000000000..4d6264b302 --- /dev/null +++ b/docs/css/instantsearch.css @@ -0,0 +1,150 @@ +.md-content { + margin: 0 auto; +} + +footer.md-footer { + left: 0; +} + +.md-content .ais-InstantSearch { + letter-spacing: 0.12px; +} + +.md-content .ais-InstantSearch h1 { + font-size: 32px; + line-height: 36px; + letter-spacing: 0.17px; + margin: 8px 0 40px; +} + +.md-content .ais-InstantSearch .ais-SearchBox .ais-SearchBox-submit { + left: 16px; +} + +.md-content .ais-InstantSearch .ais-SearchBox .ais-SearchBox-submitIcon { + width: 16px; +} + +.md-content .ais-InstantSearch .ais-SearchBox .ais-SearchBox-input { + font-size: 14px; + line-height: 21px; + height: 48px; + padding-left: 48px; + border-color: #A0A4A8; +} + +.md-content .ais-InstantSearch .ais-Hits-list { + margin-left: 0; +} + +.md-content .ais-InstantSearch .ais-Hits-item { + padding: 0px; + width: initial; + margin: 0; + border: 0; + box-shadow: none; +} + +.md-content .ais-InstantSearch .ais-Hits-item + .ais-Hits-item { + border-top: 1px solid #E0E0E8; + margin-top: 16px; + padding-top: 16px; +} + +.md-content .ais-InstantSearch .ais-Highlight-highlighted { + background-color: #ECF4FF; + color: #4191FF; + font-size: 14px; + line-height: 21px; +} + +.md-content .ais-InstantSearch .instantsearch__entry { + display: block; + color: var(--ibexa-dusk-black); +} + +.md-content .ais-InstantSearch .instantsearch__entry:hover, +.md-content .ais-InstantSearch .instantsearch__entry:hover .instantsearch__entry-header, +.md-content .ais-InstantSearch .instantsearch__entry:hover .instantsearch__entry-content { + color: var(--ibexa-jazzberry) +} + +.md-content .ais-InstantSearch .instantsearch__entry:hover mark, +.md-content .ais-InstantSearch .instantsearch__entry:hover .instantsearch__entry-header mark, +.md-content .ais-InstantSearch .instantsearch__entry:hover .instantsearch__entry-content mark { + color: var(--ibexa-jazzberry) +} + +.md-content .ais-InstantSearch .instantsearch__entry-header { + font-size: 18px; + line-height: 20px; + letter-spacing: 0.12px; + margin: 4px 0; +} + +.md-content .ais-InstantSearch .instantsearch__entry-header .ais-Highlight-highlighted { + font-size: 18px; + line-height: 20px; +} + +.md-content .ais-InstantSearch .instantsearch__entry-content { + color: #3B424A; + font-size: 14px; + line-height: 21px; + letter-spacing: 0.12px; + margin-top: 10px; + padding-left: 10px; + border-left: 2px solid var(--mid-grey); +} + +.md-content .ais-InstantSearch .instantsearch__entry-content .ais-Highlight-highlighted { + font-size: 14px; + line-height: 21px; +} + +.md-content .ais-InstantSearch .instantsearch__entry-breadcrumbs { + font-size: 12px; + line-height: 21px; + letter-spacing: 0.12px; +} + +.md-content .ais-InstantSearch .instantsearch__entry-breadcrumbs-item:after { + content: '>'; + display: inline-block; + padding: 0 10px; +} + +.md-content .ais-InstantSearch .ais-Pagination .ais-Pagination-list:not([hidden]) { + display: flex; + list-style: none; + margin: 15px 0 0; + display: flex; + justify-content: flex-end; +} + +.md-content .ais-InstantSearch .ais-Pagination .ais-Pagination-list .ais-Pagination-item { + margin: 0; +} + +.md-content .ais-InstantSearch .ais-Pagination .ais-Pagination-link { + border: none; + font-size: 14px; + line-height: 21px; + letter-spacing: 0.12px; + color: var(--ibexa-dusk-black); + height: 40px; + min-width: 40px; + display: flex; + justify-content: center; + align-items: center; +} + +.md-content .ais-InstantSearch .ais-Pagination .ais-Pagination-item--selected .ais-Pagination-link, +.md-content .ais-InstantSearch .ais-Pagination .ais-Pagination-link:hover { + background-color: #F3F3F6; + border-radius: 5px; +} + +#version { + display: none; +} diff --git a/docs/css/search.css b/docs/css/search.css new file mode 100644 index 0000000000..ae03dc459f --- /dev/null +++ b/docs/css/search.css @@ -0,0 +1,120 @@ +.md-header .md-search .algolia-autocomplete .ds-dataset-1 { + padding: 0; +} + +.md-header .md-search .algolia-autocomplete .algolia-docsearch-suggestion { + padding: 0; +} + +.md-header .md-search .algolia-autocomplete .ds-dropdown-menu .ds-suggestion.ds-cursor .algolia-docsearch-suggestion:not(.suggestion-layout-simple) .algolia-docsearch-suggestion--content { + background-color: transparent; + color: var(--ibexa-jazzberry); +} + +.md-header .md-search .algolia-autocomplete .ds-dropdown-menu .ds-suggestion.ds-cursor .algolia-docsearch-suggestion:not(.suggestion-layout-simple) .algolia-docsearch-suggestion--wrapper * { + color: var(--ibexa-jazzberry); +} + +.md-header .md-search .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--highlight { + background-color: #ECF4FF; + color: #4191FF !important; + box-shadow: none; + padding: 0; +} + +.md-header .md-search .algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--category-header { + display: flex; + align-items: center; + font-size: 14px; + line-height: 21px; + letter-spacing: 0.12px; + height: 40px; + margin: 16px 0 0 0; + padding: 0 40px; + border: 0; + background-color: #F2F2F5; + color: var(--ibexa-dusk-black); + font-weight: 600; +} + +.md-header .md-search .algolia-autocomplete .ds-suggestions > .ds-suggestion:first-child .algolia-docsearch-suggestion.algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--category-header { + margin-top: 0; +} + +.md-header .md-search .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--wrapper { + padding: 0; +} + +.md-header .md-search .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column { + float: none; + width: 100%; + text-align: left; + font-size: 18px; + line-height: 20px; + letter-spacing: 0.12px; + margin: 24px 40px 4px; + padding: 0; + color: var(--ibexa-dusk-black); + font-weight: 600; +} + +.md-header .md-search .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--content { + float: none; + width: 100%; + text-align: left; + color: #3B424A; + font-size: 14px; + line-height: 21px; + letter-spacing: 0.12px; + padding: 0; + margin: 0 40px; + display: flex; + flex-direction: column-reverse; +} + +.md-header .md-search .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--content::before { + display: none; +} + +.md-header .md-search .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--title { + font-size: 12px; + line-height: 21px; + letter-spacing: 0.12px; + margin-top: 16px; + font-weight: 500; +} + +.md-header .md-search .algolia-autocomplete .algolia-docsearch-suggestion .aa-suggestion-title-separator { + margin: 0 12px; + font-weight: 500; +} + +.md-header .md-search .algolia-autocomplete .ds-dataset-1 { + z-index: 1; + padding-bottom: 70px; +} + +.md-header .md-search .algolia-autocomplete .search-page-link-wrapper { + position: absolute; + z-index: 2; + bottom: 0; + left: 0; + right: 0; + background-color: #F2F2F5; + width: 100%; + height: 60px; + padding: 0 40px; + display: flex; + align-items: center; + justify-content: center; +} + +.md-header .md-search .algolia-autocomplete .search-page-link { + color: var(--link); + transition: color 125ms; +} + +.md-header .md-search .algolia-autocomplete .search-page-link:hover { + color: var(--ibexa-jazzberry); + transition: color 125ms; +} diff --git a/docs/images/caret-back.svg b/docs/images/caret-back.svg new file mode 100644 index 0000000000..d1f332c19d --- /dev/null +++ b/docs/images/caret-back.svg @@ -0,0 +1,4 @@ + +caret-back + + diff --git a/docs/images/caret-double-back.svg b/docs/images/caret-double-back.svg new file mode 100644 index 0000000000..7e3a53b1f0 --- /dev/null +++ b/docs/images/caret-double-back.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/images/caret-double-next.svg b/docs/images/caret-double-next.svg new file mode 100644 index 0000000000..41d13ea6d0 --- /dev/null +++ b/docs/images/caret-double-next.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/images/caret-next.svg b/docs/images/caret-next.svg new file mode 100644 index 0000000000..50e97f2754 --- /dev/null +++ b/docs/images/caret-next.svg @@ -0,0 +1,4 @@ + +caret-next + + diff --git a/docs/images/ez-icons.svg b/docs/images/ez-icons.svg index 2e912f590a..4ae23b0ff3 100644 --- a/docs/images/ez-icons.svg +++ b/docs/images/ez-icons.svg @@ -95,6 +95,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/docs/js/custom.js b/docs/js/custom.js index 649bdec1aa..7846d9327d 100644 --- a/docs/js/custom.js +++ b/docs/js/custom.js @@ -104,20 +104,21 @@ $(document).ready(function() { } }); - $('.md-content a:not(.md-icon):not(.md-source)') + $('.md-content a:not(.md-icon):not(.md-source):not(.instantsearch__entry)') .filter(function() { return this.hostname && this.hostname !== location.hostname; }) .addClass('external'); - docsearch({ + let search = docsearch({ container: '#docsearch', appId: '2DNYOU6YJZ', apiKey: '21ce3e522455e18e7ee16cf7d66edb4b', indexName: 'ezplatform', inputSelector: '#search_input', transformData: function(hits) { - let removedPattern = '¶'; + const hitsPerPage = 10; + const removedPattern = '¶'; $.each(hits, function(index, hit) { for (let lvl=2; lvl<=6; lvl++) { if (null !== hit.hierarchy['lvl'+lvl]) { @@ -128,24 +129,51 @@ $(document).ready(function() { } } }); + + let link = $('.ds-dropdown-menu a.search-page-link'); + const href = '/en/' + branchName + '/search_results/?sq=' + encodeURI($('#search_input').val()) + '&p=1'; + + if (!link.length) { + link = $('.ds-dropdown-menu').append(``); + } + + link.attr('href', href).show(); + + if (hits.length < hitsPerPage) { + link.hide(); + } }, algoliaOptions: { facetFilters: ['lang:en', 'version:' + branchName], hitsPerPage: 10, }, + handleSelected: function (input, event, suggestion, datasetNumber, context) { + if (context.selectionMethod == 'click') { + window.location = suggestion.url; + } else if (context.selectionMethod == 'enterKey') { + window.location = $('.ds-dropdown-menu a.search-page-link').attr('href'); + } + }, debug: false, }); + search.autocomplete.on('autocomplete:updated', event => { + $('.ds-dropdown-menu .ds-suggestion').each(function() { + let category = $(this).find('.algolia-docsearch-suggestion--subcategory-column'); + let content = $(this).find('.algolia-docsearch-suggestion--title'); + if (content.text().trim() == category.text().trim()) { + content.remove(); + } + }); + }); - $(document).on('keypress', '#search_input', function(event) { + $(document).on('keydown keypress', 'form.md-search__form', function(event) { if (event.keyCode == 13) { event.preventDefault(); - } - }); - $(document).on('blur', '#search_input', function(event) { - setTimeout(() => { - $('#search_input').val(''); - }, 0); + return false + } }); $('#search_input, label.md-search__icon').on('click', function() { diff --git a/docs/js/instantsearch.js b/docs/js/instantsearch.js new file mode 100644 index 0000000000..c0da4d2631 --- /dev/null +++ b/docs/js/instantsearch.js @@ -0,0 +1,132 @@ +(function (global, doc) { + let match; + const search_query = (match = doc.location.search.match(/sq=(.*?)(&|$)/)) ? match[1] : ''; + const parsed_search_query = decodeURI(search_query.replaceAll('+', ' ')); + const search_page = (match = doc.location.search.match(/p=(\d*?)(&|$)/)) ? match[1] : 1; + const parsed_search_page = parseInt(search_page); + let version = doc.location.pathname.split('/')[2]; + if (!/^\d+\.\d+$/.test(version) && version !== 'latest') { + version = 'master'; + } + const search = instantsearch({ + indexName: 'ezplatform', + searchClient: algoliasearch('2DNYOU6YJZ', '21ce3e522455e18e7ee16cf7d66edb4b'), + initialUiState: { + ezplatform: { + query: parsed_search_query, + refinementList: {version: [version]}, + page: parsed_search_page, + }, + }, + }); + + doc.getElementById('searchbox').addEventListener('keyup', function (event) { + const url = new URL(window.location); + url.searchParams.set('sq', event.target.value.trim()); + if (url.href != window.location.href) { + url.searchParams.set('p', 1); + window.history.pushState({}, '', url); + } + }) + + doc.getElementById('pagination').addEventListener('click', function (event) { + const page = doc.getElementsByClassName('ais-Pagination-item--selected').length ? parseInt(doc.getElementsByClassName('ais-Pagination-item--selected')[0].innerText) : 1 + const url = new URL(window.location); + url.searchParams.set('p', page); + window.history.pushState({}, '', url); + }) + + window.onpopstate = (event) => { + window.location.reload(); + }; + + search.addWidgets([ + instantsearch.widgets.configure({ + hitsPerPage: 10, + }), + instantsearch.widgets.stats({ + container: '#stats', + templates: { + text: `

+ Search results ({{#helpers.formatNumber}}{{nbHits}}{{/helpers.formatNumber}}) +

`, + }, + }), + instantsearch.widgets.searchBox({ + container: '#searchbox', + }), + instantsearch.widgets.hits({ + container: '#hits', + templates: { + item: (hit) => { + const hierarchy = Object.entries(hit.hierarchy).filter(([, value]) => value); + const breadcrumbsKeys = hierarchy.map(([key]) => key); + const entryNameKey = breadcrumbsKeys.pop(); + + const headerHTML = `

+ ${instantsearch.highlight({ + attribute: `hierarchy.${entryNameKey}`, + highlightedTagName: 'mark', + hit: hit + })} +

`; + + let breadcrumbsHTML = ''; + let contentHTML = ''; + + if (hit.content && hit._highlightResult.content.matchedWords.length && (!hit._highlightResult.content.fullyHighlighted || 1 < hit._highlightResult.content.matchedWords.length)) { + contentHTML = `
+ ${instantsearch.highlight({ + attribute: `content`, + highlightedTagName: 'mark', + hit: hit + }).replaceAll('&', '&')} +
`; + } + + breadcrumbsKeys?.forEach((breadcrumbKey) => { + breadcrumbsHTML += ` + ${instantsearch.highlight({ + attribute: `hierarchy.${breadcrumbKey}`, + highlightedTagName: 'mark', + hit: hit + })} + ` + }); + + return resultHTML = ` +
+ ${breadcrumbsHTML} +
+ ${headerHTML} + ${contentHTML} +
`; + }, + }, + }), + instantsearch.widgets.pagination({ + container: '#pagination', + padding: 2, + templates: { + first: ` + + `, + previous: ` + + `, + next: ` + + `, + last: ` + + `, + }, + }), + instantsearch.widgets.refinementList({ + container: document.querySelector('#version'), + attribute: 'version', + }), + ]); + + search.start(); +})(window, window.document); diff --git a/docs/search_results.md b/docs/search_results.md new file mode 100644 index 0000000000..73ca274535 --- /dev/null +++ b/docs/search_results.md @@ -0,0 +1,5 @@ +--- +title: Developer Documentation Search +description: Search for keywords in the Developer Documentation +template: instantsearch.html +--- diff --git a/mkdocs.yml b/mkdocs.yml index e620a6f3d6..c9597fc72a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -936,6 +936,7 @@ extra_css: - css/custom.css - css/page-not-found.css - css/navigation.css + - css/search.css - css/docs.switcher.css - css/jquery-ui.min.css - '//cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css' diff --git a/theme/instantsearch.html b/theme/instantsearch.html new file mode 100644 index 0000000000..5b0fbdc5c8 --- /dev/null +++ b/theme/instantsearch.html @@ -0,0 +1,35 @@ +{% extends "main.html" %} + +{% block styles %} + {{ super() }} + + + +{% endblock %} + +{% block scripts %} + {{ super() }} + + + + +{% endblock %} + +{% block site_nav %} +{% endblock %} + +{% block content %} + {% raw %} +
+ +
+ +
+ +
+
+ {% endraw %} +{% endblock %}