Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-docs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSarah German <sgerman@gitlab.com>2022-09-22 18:10:42 +0300
committerKati Paizee <kpaizee@gitlab.com>2022-09-22 18:10:42 +0300
commit6ef828e917f82a7bd8a621c8a652e3127666ac37 (patch)
tree62b2f8c2f54d46bda3a58e8c45b1cad2e9777514 /content/frontend
parenta5ac9d88bd1251c252d53680e8af0df0eef1d743 (diff)
Add Lunr search UI components
Diffstat (limited to 'content/frontend')
-rw-r--r--content/frontend/search/components/lunr_page.vue97
-rw-r--r--content/frontend/search/components/lunr_search_form.vue23
-rw-r--r--content/frontend/search/lunrsearch.js26
-rw-r--r--content/frontend/search/search.js5
4 files changed, 150 insertions, 1 deletions
diff --git a/content/frontend/search/components/lunr_page.vue b/content/frontend/search/components/lunr_page.vue
new file mode 100644
index 00000000..5edcb04c
--- /dev/null
+++ b/content/frontend/search/components/lunr_page.vue
@@ -0,0 +1,97 @@
+<script>
+/* global lunr */
+import { GlSearchBoxByClick, GlLink } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlSearchBoxByClick,
+ GlLink,
+ },
+ data() {
+ return {
+ query: '',
+ submitted: false,
+ error: false,
+ results: [],
+ contentMap: [],
+ relevancy_threshold: 15,
+ };
+ },
+ computed: {
+ noResults() {
+ return this.submitted && !this.results.length && !this.error;
+ },
+ },
+ async created() {
+ try {
+ // Load the search index and content map.
+ const [indexResp, mapResp] = await Promise.all([
+ fetch('/assets/javascripts/lunr-index.json'),
+ fetch('/assets/javascripts/lunr-map.json'),
+ ]);
+ const lindex = await indexResp.json();
+ this.contentMap = await mapResp.json();
+
+ // Initialize Lunr.
+ const idx = lunr.Index.load(lindex);
+ window.idx = idx;
+
+ // If we have a query string in the URL, run the search.
+ const searchParams = new URLSearchParams(window.location.search);
+ if (searchParams.has('query')) {
+ this.search(searchParams.get('query'));
+ }
+ } catch (e) {
+ this.handleError(e);
+ }
+ },
+ methods: {
+ onSubmit() {
+ if (this.query) {
+ this.search(this.query);
+ }
+ },
+ search(query) {
+ this.query = query;
+ this.submitted = true;
+
+ // Run the search.
+ this.results = window.idx.search(this.query);
+
+ // Limit the results by relevancy score.
+ this.results = this.results.filter((key) => key.score > this.relevancy_threshold);
+
+ // Add page titles to the result set.
+ Object.keys(this.results).forEach((key) => {
+ const contentItem = this.contentMap.find(({ id }) => id === this.results[key].ref);
+ this.results[key].title = contentItem.h1;
+ });
+
+ // Add the search term to the URL to allow linking to result pages.
+ const url = new URL(window.location);
+ url.searchParams.set('query', this.query);
+ window.history.pushState(null, '', url.toString());
+ },
+ handleError() {
+ this.error = true;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="lunr-search">
+ <h1>Search</h1>
+ <gl-search-box-by-click v-model="query" :value="query" @submit="onSubmit" />
+ <div v-if="results.length" class="gl-font-sm gl-mb-6">{{ results.length }} results found</div>
+
+ <ul v-if="results.length">
+ <li v-for="result in results" :key="result.ref">
+ <gl-link :href="`/${result.ref}`">{{ result.title }}</gl-link>
+ </li>
+ </ul>
+
+ <p v-if="noResults" class="gl-py-5">No results found.</p>
+ <p v-if="error" class="gl-py-5" data-testid="lunr-error">Error fetching search index.</p>
+ </div>
+</template>
diff --git a/content/frontend/search/components/lunr_search_form.vue b/content/frontend/search/components/lunr_search_form.vue
new file mode 100644
index 00000000..958e5b07
--- /dev/null
+++ b/content/frontend/search/components/lunr_search_form.vue
@@ -0,0 +1,23 @@
+<script>
+import { GlSearchBoxByClick } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlSearchBoxByClick,
+ },
+ data() {
+ return {
+ query: '',
+ };
+ },
+ methods: {
+ onSubmit() {
+ window.location.href = `/search/?query=${encodeURI(this.query)}`;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-search-box-by-click v-model="query" class="lunr-search" @submit="onSubmit" />
+</template>
diff --git a/content/frontend/search/lunrsearch.js b/content/frontend/search/lunrsearch.js
new file mode 100644
index 00000000..ae0a06d9
--- /dev/null
+++ b/content/frontend/search/lunrsearch.js
@@ -0,0 +1,26 @@
+import Vue from 'vue';
+import LunrPage from './components/lunr_page.vue';
+import LunrSearchForm from './components/lunr_search_form.vue';
+
+// Search results page (/search)
+document.addEventListener('DOMContentLoaded', () => {
+ return new Vue({
+ el: '.js-lunrsearch',
+ render(createElement) {
+ return createElement(LunrPage);
+ },
+ });
+});
+
+// Homepage and interior navbar search forms
+document.addEventListener('DOMContentLoaded', () => {
+ return new Vue({
+ el: '.js-lunr-form',
+ components: {
+ LunrSearchForm,
+ },
+ render(createElement) {
+ return createElement(LunrSearchForm);
+ },
+ });
+});
diff --git a/content/frontend/search/search.js b/content/frontend/search/search.js
index ab202445..7c53542f 100644
--- a/content/frontend/search/search.js
+++ b/content/frontend/search/search.js
@@ -27,7 +27,10 @@ export const getAlgoliaCredentials = (crawler = 'production') => {
export const getDocsVersion = () => {
let docsVersion = 'main';
- if (document.querySelector('meta[name="docsearch:version"]').content.length > 0) {
+ if (
+ document.querySelector('meta[name="docsearch:version"]') &&
+ document.querySelector('meta[name="docsearch:version"]').content.length
+ ) {
docsVersion = document.querySelector('meta[name="docsearch:version"]').content;
}
return docsVersion;