diff options
author | David O'Regan <doregan@gitlab.com> | 2022-06-16 12:54:51 +0300 |
---|---|---|
committer | David O'Regan <doregan@gitlab.com> | 2022-06-16 12:54:51 +0300 |
commit | 8c014dc9f1c366207b57075005ced6e64351c9ec (patch) | |
tree | 05359e8de55d70f070d03bb1c9ddcfd89a486ee2 /content | |
parent | bd3df1259d0ba5a1071e2eb4c5e135602383171a (diff) | |
parent | 700448adb96fe2a19bfb0c31b751ae99d188d9d7 (diff) |
Merge branch 'instantsearch-vue' into 'main'
Use instantsearch-vue for the dedicated search page
Closes #656
See merge request gitlab-org/gitlab-docs!2816
Diffstat (limited to 'content')
-rw-r--r-- | content/assets/stylesheets/instantsearch.scss | 184 | ||||
-rw-r--r-- | content/frontend/search/components/search_page.vue | 77 | ||||
-rw-r--r-- | content/frontend/search/docsearch.js | 8 | ||||
-rw-r--r-- | content/frontend/search/index.js | 74 | ||||
-rw-r--r-- | content/frontend/search/instantsearch.js | 35 | ||||
-rw-r--r-- | content/frontend/search/search.js | 11 | ||||
-rw-r--r-- | content/search/index.md | 24 |
7 files changed, 127 insertions, 286 deletions
diff --git a/content/assets/stylesheets/instantsearch.scss b/content/assets/stylesheets/instantsearch.scss deleted file mode 100644 index f50c7f11..00000000 --- a/content/assets/stylesheets/instantsearch.scss +++ /dev/null @@ -1,184 +0,0 @@ ---- -version: 15 ---- - -@import 'variables'; - -// original CSS: https://github.com/algolia/examples/blob/master/instant-search/instantsearch.js/assets/style.css -// original CSS customized and converted to SCSS with http://sebastianpontow.de/css2compass/ - -//colors -$color0: rgba(180, 162, 231, 0.1); -$color1: rgba(180, 162, 231, 0.2); -$color2: rgba(180, 162, 231, 0.1); -$color3: rgba(79, 171, 225, 0.2); -$color4: #eee; -$color5: #ed5565; -$color6: #999; -$color7: #868686; -$color8: #fff; -$color9: #383838; -$color10: rgb(117, 117, 117); -$color11: transparent; -// link-color: rgb(32, 139, 196); -$color12: rgba(32, 139, 196, 0.2); //link color lighter - - -/* stylelint-disable-next-line selector-class-pattern */ -.ais-SearchBox { - width: 100%; - max-width: 100% !important; // was 300px -} - -.search-input { - border-radius: 2px; -} - -/* stylelint-disable-next-line selector-class-pattern */ -.ais-PoweredBy { - font-family: $gl-regular-font; - font-size: $body-font-size; - - svg { - display: inline; - } -} - -.hit-content { - border-top: 1px solid $color0; - padding: 1rem 0.5rem; - margin: 0; - font-size: 13px; - font-weight: 300; - width: 100%; // was 81% - position: relative; - color: $color10; - transition: 0.3s ease; - word-wrap: break-word; - - &:hover { - background-color: $color12; - - .hit-tag { - color: $link-color; - border-color: $color3; - } - } - - .lvl0 { - color: $gds-black; - } - - .lvl1 { - font-size: 18px !important; - } - - .lvl2 { - font-size: 0.875rem; - color: $color7; - } - - .hit-name { - font-weight: normal; - margin-top: 0; - } - - em { - font-style: normal; - background-color: $color3; - } - - p { - font-size: 13px; - } - - .hit-description { - margin: 1px 0 5px; - } - - .hit-tag { - display: block; - position: absolute; - padding: 3px; - border: 1px solid $color0; - border-top: 0; - border-bottom-left-radius: 2px; - border-bottom-right-radius: 2px; - right: 0; - top: 0; - width: 70px; - height: 25px; - font-size: 11px; - font-weight: 500; - text-align: center; - text-transform: uppercase; - color: $color6; - } - - .hit-text { - font-size: inherit; - color: $link-color; - } - - @media all and (max-width: $bp-sm) { - .hit-tag { - width: 60px; - height: 23px; - font-size: 10px; - } - - .lvl0 { - padding-top: 5px; - } - } -} - -#hits { - /* stylelint-disable-next-line selector-list-comma-newline-after */ - > h1, h2, h3, h4, h5, h6 { - border: 0; - } -} - -.algolia-docsearch-suggestion--highlight { - background-color: $color3; -} - -/* stylelint-disable selector-class-pattern */ -.ais-InfiniteHits { - .ais-InfiniteHits-item { - // https://github.com/algolia/instantsearch-specs/blob/v7.4.4/src/scss/themes/algolia.scss#L277-L305 - width: calc(100% - 1rem); - border: 0; - box-shadow: none; - } -} - -.ais-InfiniteHits-loadMore { - display: block; - width: 100%; - margin: 1rem 0.5rem; - - &:focus { - outline: none; - } -} - -.ais-Stats-text { - color: $body-color; -} - -.ais-RefinementList-item { - display: inline-block; - padding-right: 10px; -} - -.ais-RefinementList-label { - text-transform: uppercase; - color: $link-color; -} -/* stylelint-enable selector-class-pattern */ - -.search-results { - min-height: 50vh; -} diff --git a/content/frontend/search/components/search_page.vue b/content/frontend/search/components/search_page.vue new file mode 100644 index 00000000..621d2b9d --- /dev/null +++ b/content/frontend/search/components/search_page.vue @@ -0,0 +1,77 @@ +<script> +import algoliasearch from 'algoliasearch/lite'; +import 'instantsearch.css/themes/satellite-min.css'; +import { history as historyRouter } from 'instantsearch.js/es/lib/routers'; +import { singleIndex as singleIndexMapping } from 'instantsearch.js/es/lib/stateMappings'; +import { GlIcon } from '@gitlab/ui'; + +export default { + components: { + GlIcon, + }, + props: { + docsVersion: { + type: String, + required: true, + }, + }, + data() { + return { + searchClient: algoliasearch('3PNCFOU757', '89b85ffae982a7f1adeeed4a90bb0ab1'), + routing: { + router: historyRouter(), + stateMapping: singleIndexMapping('gitlab'), + }, + }; + }, +}; +</script> + +<template> + <ais-instant-search + :search-client="searchClient" + index-name="gitlab" + :routing="routing" + :stalled-search-delay="500" + class="gl-pb-8" + > + <h1 class="gl-mt-5!">Search</h1> + <ais-search-box + placeholder="Search GitLab Documentation" + show-loading-indicator + data-testid="docs-search" + /> + + <ais-state-results> + <template #default="{ results: { hits, query } }"> + <div class="gl-display-flex gl-align-items-bottom gl-mb-6"> + <ais-stats v-show="query.length > 0" class="gl-font-sm" /> + <ais-powered-by + :class-names="{ + 'ais-PoweredBy': 'gl-absolute gl-right-7 gl-mt-2', + 'ais-PoweredBy-link': 'no-attachment-icon gl-border-bottom-0!', + }" + /> + </div> + + <ais-infinite-hits v-if="query.length > 0 && hits.length > 0"> + <template #item="{ item }"> + <div> + <a :href="item.url" class="gl-font-lg">{{ item.hierarchy.lvl0 }}</a> + <p v-if="item.hierarchy.lvl2" class="gl-mt-2! gl-font-base!"> + <gl-icon name="chevron-right" :size="12" /> {{ item.hierarchy.lvl2 }} + </p> + </div> + </template> + </ais-infinite-hits> + + <div v-if="query.length > 0 && hits.length < 0"> + No results found for <em>{{ query }}</em + >. + </div> + </template> + </ais-state-results> + + <ais-configure :hits-per-page.camel="10" :facet-filters.camel="`version:` + docsVersion" /> + </ais-instant-search> +</template> diff --git a/content/frontend/search/docsearch.js b/content/frontend/search/docsearch.js index 0e12f398..e01ab696 100644 --- a/content/frontend/search/docsearch.js +++ b/content/frontend/search/docsearch.js @@ -1,11 +1,9 @@ import docsearch from '@docsearch/js'; import '@docsearch/css'; +import { getDocsVersion } from './search'; document.addEventListener('DOMContentLoaded', () => { - let version = 'main'; - if (document.querySelector('meta[name="docsearch:version"]').content.length > 0) { - version = document.querySelector('meta[name="docsearch:version"]').content; - } + const docsVersion = getDocsVersion(); // eslint-disable-next-line no-undef docsearch({ @@ -15,7 +13,7 @@ document.addEventListener('DOMContentLoaded', () => { appId: '3PNCFOU757', placeholder: 'Search the docs', searchParameters: { - facetFilters: [`version:${version}`], + facetFilters: [`version:${docsVersion}`], }, resultsFooterComponent({ state }) { return { diff --git a/content/frontend/search/index.js b/content/frontend/search/index.js deleted file mode 100644 index 1c658dc9..00000000 --- a/content/frontend/search/index.js +++ /dev/null @@ -1,74 +0,0 @@ -import instantsearch from 'instantsearch.js'; -import { singleIndex } from 'instantsearch.js/es/lib/stateMappings'; -import { - searchBox, - refinementList, - infiniteHits, - stats, - poweredBy, - configure, -} from 'instantsearch.js/es/widgets'; -import algoliasearch from 'algoliasearch'; - -document.addEventListener('DOMContentLoaded', () => { - const search = instantsearch({ - indexName: 'gitlab', - searchClient: algoliasearch('3PNCFOU757', '89b85ffae982a7f1adeeed4a90bb0ab1'), - algoliaOptions: { - // Filter by tags as described in https://github.com/algolia/docsearch-configs/blob/master/configs/gitlab.json - filters: 'tags:gitlab<score=3> OR tags:omnibus<score=2> OR tags:runner<score=1>', - }, - routing: { - stateMapping: singleIndex('gitlab'), - }, - searchFunction: (helper) => { - if (helper.state.query === '') { - return; - } - helper.search(); - }, - }); - - search.addWidgets([ - searchBox({ - container: '#searchbox', - placeholder: 'Search GitLab Documentation', - showReset: true, - showLoadingIndicator: true, - }), - - poweredBy({ - container: '#powered-by', - }), - - refinementList({ - container: '#refinement-list', - attribute: 'tags', - sortBy: ['name:asc', 'isRefined'], - templates: { - header: 'Refine your search:', - }, - }), - - infiniteHits({ - container: '#hits', - templates: { - item: document.getElementById('hit-template').innerHTML, - empty: 'We didn\'t find any results for the search <em>"{{query}}"</em>', - }, - escapeHits: true, - showMoreLabel: 'Load more results...', - }), - - stats({ - container: '#stats', - }), - - configure({ - // Number of results shown in the search dropdown - hitsPerPage: 10, - }), - ]); - - search.start(); -}); diff --git a/content/frontend/search/instantsearch.js b/content/frontend/search/instantsearch.js new file mode 100644 index 00000000..64bd9f9a --- /dev/null +++ b/content/frontend/search/instantsearch.js @@ -0,0 +1,35 @@ +import Vue from 'vue'; +import { + AisInstantSearch, + AisStateResults, + AisSearchBox, + AisStats, + AisPoweredBy, + AisInfiniteHits, + AisConfigure, +} from 'vue-instantsearch'; +import SearchPage from './components/search_page.vue'; +import { getDocsVersion } from './search'; + +Vue.component(AisInstantSearch.name, AisInstantSearch); +Vue.component(AisSearchBox.name, AisSearchBox); +Vue.component(AisStateResults.name, AisStateResults); +Vue.component(AisStats.name, AisStats); +Vue.component(AisPoweredBy.name, AisPoweredBy); +Vue.component(AisInfiniteHits.name, AisInfiniteHits); +Vue.component(AisConfigure.name, AisConfigure); + +const docsVersion = getDocsVersion(); + +document.addEventListener('DOMContentLoaded', () => { + return new Vue({ + el: '.js-instantsearch', + render(createElement) { + return createElement(SearchPage, { + props: { + docsVersion, + }, + }); + }, + }); +}); diff --git a/content/frontend/search/search.js b/content/frontend/search/search.js new file mode 100644 index 00000000..5ea8a87a --- /dev/null +++ b/content/frontend/search/search.js @@ -0,0 +1,11 @@ +/** + * Functions used by both DocSearch and InstantSearch. + */ + +export const getDocsVersion = () => { + let docsVersion = 'main'; + if (document.querySelector('meta[name="docsearch:version"]').content.length > 0) { + docsVersion = document.querySelector('meta[name="docsearch:version"]').content; + } + return docsVersion; +}; diff --git a/content/search/index.md b/content/search/index.md index 8869da3f..a4d484db 100644 --- a/content/search/index.md +++ b/content/search/index.md @@ -1,26 +1,4 @@ --- -title: Search through GitLab Documentation +title: Search GitLab Docs layout: instantsearch -feedback: nil --- -<header> - <div id="searchbox"></div> - <div id="powered-by"></div> -</header> -<main class="search-results"> - <div id="stats"></div> - <div id="refinement-list"></div> - <div id="hits"></div> - - <script type="text/html" id="hit-template"> - <a href="{{ url }}" class="hit"> - <div class="hit-content"> - <h3 class="hit-name lvl0">{{{_highlightResult.hierarchy.lvl0.value}}}</h3> - <h4 class="hit-description lvl1">{{{_highlightResult.hierarchy.lvl1.value}}}</h4> - <h5 class="hit-description lvl2">{{{_highlightResult.hierarchy.lvl2.value}}}</h5> - <div class="hit-text">{{{_highlightResult.content.value}}}</div> - <div class="hit-tag">{{ tags }}</div> - </div> - </a> - </script> -</main> |