From 9f8ac77af6d644ca75ebcfce13b20b93e5126123 Mon Sep 17 00:00:00 2001 From: Lukas Hirt Date: Sun, 20 Dec 2020 20:09:49 +0100 Subject: [PATCH] Group search by sections --- assets/js/groupBy.min.js | 9 +++++ assets/js/search.js | 75 +++++++++++++++++++++++++++++++--------- src/sass/_base.scss | 38 ++++++++++++++++---- 3 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 assets/js/groupBy.min.js diff --git a/assets/js/groupBy.min.js b/assets/js/groupBy.min.js new file mode 100644 index 0000000..808a440 --- /dev/null +++ b/assets/js/groupBy.min.js @@ -0,0 +1,9 @@ +/** + * Part of [Canivete](http://canivete.leofavre.com/#deepgroupby) + * + * Groups the contents of an array by one or more iteratees. + * Unlike Lodash [`groupBy()`](https://lodash.com/docs/4.17.4#groupBy), + * this function can create nested groups, but cannot receive + * strings for iteratees. + */ +const groupBy=(e,...t)=>{let r=e.map(e=>t.map(t=>t(e))),a={};return r.forEach((t,r)=>{let l=(_simpleAt(a,t)||[]).concat([e[r]]);_simpleSet(a,t,l)}),a},_isPlainObject=e=>null!=e&&"object"==typeof e&&e.constructor==Object,_parsePath=e=>Array.isArray(e)?e:`${e}`.split("."),_simpleAt=(e,t)=>_parsePath(t).reduce((e,t)=>null!=e&&e.hasOwnProperty(t)?e[t]:void 0,e),_simpleSet=(e,t,r)=>_parsePath(t).reduce((e,t,a,l)=>{let s=a===l.length-1;return e.hasOwnProperty(t)&&(s||_isPlainObject(e[t]))||(e[t]={}),s?e[t]=r:e[t]},e); \ No newline at end of file diff --git a/assets/js/search.js b/assets/js/search.js index afd434d..4a62773 100644 --- a/assets/js/search.js +++ b/assets/js/search.js @@ -6,6 +6,11 @@ (function() { const input = document.querySelector('#gdoc-search-input'); const results = document.querySelector('#gdoc-search-results'); + let showParent = false + + {{ if .Site.Params.GeekdocSearchShowParent }} + showParent = true + {{ end }} input.addEventListener('focus', init); input.addEventListener('keyup', search); @@ -19,6 +24,7 @@ input.required = false; search(); }); + loadScript('{{ index .Site.Data.assets "js/groupBy.min.js" | relURL }}'); } function search() { @@ -32,31 +38,68 @@ return; } - const searchHits = window.geekdocSearchIndex.search(input.value, 10); + let searchHits = window.geekdocSearchIndex.search(input.value, 10); console.log(searchHits.length); - if (searchHits.length > 0) { - results.classList.add("has-hits"); - } else { - results.classList.remove("has-hits"); + if (searchHits.length < 1) { + return results.classList.remove("has-hits"); } - searchHits.forEach(function(page) { - const li = document.createElement('li'), - a = li.appendChild(document.createElement('a')); + results.classList.add("has-hits"); + + if (showParent) { + searchHits = groupBy(searchHits, hit => hit.parent); + } + + const items = []; + + if (showParent) { + for (const section in searchHits) { + const item = document.createElement('li'), + title = item.appendChild(document.createElement('span')), + subList = item.appendChild(document.createElement('ul')); + + title.textContent = section; + title.classList.add('gdoc-search__list__section-title'); + createLinks(searchHits[section], subList); + + items.push(item); + } + } else { + items.push(...createLinks(searchHits)); + } + + items.forEach(item => { + results.appendChild(item); + }) + results.classList.add('DUMMY'); + } + + /** + * Creates links to given pages and either returns them in an array or attaches them to a target element + * @param {Object} pages Page to which the link should point to + * @param {HTMLElement} target Element to which the links should be attatched + * @returns {Array} If target is not specified, returns an array of built links + */ + function createLinks(pages, target) { + const items = []; + + for (const page of pages) { + const item = document.createElement('li'), + a = item.appendChild(document.createElement('a')); a.href = page.href; - - {{ if .Site.Params.GeekdocSearchShowParent }} - a.textContent = page.parent ? page.parent + ' / ' + page.title : page.title; - {{ else }} a.textContent = page.title; - {{ end }} - results.appendChild(li); - results.classList.add("DUMMY"); - }); + if (target) { + target.appendChild(item); + continue + } + items.push(item); + } + + return items; } function loadScript(src, callback) { diff --git a/src/sass/_base.scss b/src/sass/_base.scss index f50e252..51f15b9 100644 --- a/src/sass/_base.scss +++ b/src/sass/_base.scss @@ -398,10 +398,6 @@ img { height: $font-size-16; } - .has-hits { - border-bottom: 1px dashed $gray-600; - } - &::after { display: block; content: ""; @@ -441,22 +437,50 @@ img { } &__list { - padding-left: 1em; + display: none; + background-color: #ffffff; + border-radius: $border-radius; + box-shadow: 0 1px 3px 0 rgba(0,0,0,0.1),0 1px 2px 0 rgba(0,0,0,0.06); + position: absolute; margin: 0; - padding: $padding-8 0; + padding: $padding-8; list-style: none; + left: 0; + top: calc(100% + #{$padding-8}); + width: 100%; + z-index: 2; ul { - padding-left: $padding-16; + list-style: none; + margin-top: $padding-8; + padding-left: 0; } li { margin: $padding-4 0; } + > li > span { + color: $gray-600; + font-size: $font-size-14; + font-weight: bold; + } + + > li + li { + margin-top: $padding-16; + } + .icon { margin-right: $padding-4; } + + a { + font-size: $font-size-16; + } + } + + &:focus-within &__list.has-hits { + display: block !important; } }