Skip to content

Commit c198775

Browse files
authored
Merge pull request #92 from yel-hadd/master
Integrated the new search API
2 parents 8856fdb + ed9038d commit c198775

File tree

5 files changed

+309
-211
lines changed

5 files changed

+309
-211
lines changed

docs/.vuepress/client.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ export default defineClientConfig({
7777
appId: "0TCNL6CGX8",
7878
},
7979

80-
MAX_ALGOLIA_VISIBLE_RESULT: 20,
81-
MAX_ALGOLIA_VISIBLE_ROWS: 15,
82-
MAX_ALGOLIA_HITS_PER_PAGE: 20,
80+
MAX_VISIBLE_RESULT: 12,
81+
MAX_VISIBLE_ROWS: 12,
82+
MAX_HITS_PER_PAGE: 12,
8383
})
8484
}
8585
})

docs/.vuepress/theme/drawer/Drawer.vue

Lines changed: 18 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,15 @@
1111
<p @click="onCloseDrawer" class="drawer-cross__text">close</p>
1212
</div>
1313
</div>
14-
<DrawerTabs v-model="selectedTabIndex" :data="tabs"/>
1514
<main>
16-
<div class="drawer-main">
17-
<div class="drawer-main__wrapper">
18-
<div class="drawer-main__breadcrumb">
19-
<p v-if="drawerArticleResult.length" class="drawer-main__breadcrumb__text">Home
20-
<img :src="withBase('/arrows/arrow-right-breadcrumb.svg')" alt="breadcrumb icon"/>
21-
Documentation
22-
</p>
23-
</div>
24-
<DrawerSearchResult :modelValue="modelValue" :data="drawerArticleResult"/>
25-
</div>
26-
</div>
15+
<div class="drawer-main">
16+
<div class="drawer-main__wrapper">
17+
<div class="drawer-main__breadcrumb">
18+
<!-- Optional breadcrumb can stay here -->
19+
</div>
20+
<DrawerSearchResult :modelValue="modelValue" :data="drawerArticleResult"/>
21+
</div>
22+
</div>
2723
<Footer v-if="isOpenDrawer && isMobileWidth" class="drawer-footer__mobile"/>
2824
</main>
2925
</div>
@@ -32,10 +28,9 @@
3228
</template>
3329

3430
<script setup>
35-
import {withBase} from "@vuepress/client";
31+
import { withBase } from "@vuepress/client";
3632
import Footer from "../footer/Footer.vue";
37-
import {computed, ref, watch} from "vue";
38-
import DrawerTabs from "./DrawerTabs.vue";
33+
import { computed, ref, watch } from "vue";
3934
import DrawerSearchResult from "./DrawerSearchResult.vue";
4035
4136
const props = defineProps({
@@ -44,7 +39,7 @@ const props = defineProps({
4439
required: true,
4540
default: false
4641
},
47-
isMobileWidth:{
42+
isMobileWidth: {
4843
type: Boolean,
4944
required: true,
5045
default: false
@@ -59,39 +54,21 @@ const props = defineProps({
5954
required: true,
6055
default: () => []
6156
}
62-
})
63-
64-
65-
const emit = defineEmits(['closeDrawer', 'update:modelValue'])
66-
67-
const selectedTabIndex = ref(0);
68-
69-
const tabs = computed(() => {
70-
const uniqueTitles = props.homeLayoutSearchResult.reduce((unique, result) => {
71-
const title = result.hierarchy?.lvl0;
72-
unique[title] = unique[title] || { title, numberResults: 0 };
73-
unique[title].numberResults++;
74-
return unique;
75-
}, {});
76-
return Object.values(uniqueTitles);
7757
});
7858
59+
const emit = defineEmits(['closeDrawer', 'update:modelValue']);
60+
7961
const drawerArticleResult = computed(() => {
80-
if (selectedTabIndex.value === -1) {
81-
return props.homeLayoutSearchResult || [];
82-
}
83-
const selectedTab = tabs.value[selectedTabIndex.value];
84-
return props.homeLayoutSearchResult.filter(result => result.hierarchy.lvl0 === selectedTab?.title);
85-
})
62+
return props.homeLayoutSearchResult; // Now directly returning all results since there are no tabs
63+
});
8664
8765
const onCloseDrawer = () => {
88-
emit('closeDrawer')
89-
selectedTabIndex.value = 0
66+
emit('closeDrawer');
9067
}
9168
9269
watch(() => props.isOpenDrawer, () => {
93-
document.body.classList.toggle('disable-scroll', props.isOpenDrawer)
94-
})
70+
document.body.classList.toggle('disable-scroll', props.isOpenDrawer);
71+
});
9572
</script>
9673

9774
<style lang="stylus">

docs/.vuepress/theme/drawer/DrawerSearch.vue

Lines changed: 123 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
<template>
2-
<form id="search-form" class="drawer-header__input">
3-
<input :value="modelValue"
2+
<form id="search-form" class="drawer-header__input" @submit.prevent="performSearch">
3+
<input type="text"
4+
:value="modelValue"
45
@input="$emit('update:modelValue', $event.target.value)"
56
id="algolia-search-input"
67
:placeholder="placeholder"
78
:class="activeSearchClass"
8-
@keypress.enter.prevent="$emit('openDrawer')"
9+
maxlength="100"
910
/>
1011
<div :class="activeSearchIconClass">
11-
<img @click="$emit('openDrawer')" alt="search icon" :src="withBase(activeSearchIcon)"/>
12+
<img v-if="!loading" @click="performSearch" alt="search icon" :src="withBase(activeSearchIcon)"/>
13+
<div v-if="loading" class="spinner"></div>
1214
</div>
1315
</form>
1416
</template>
1517

1618
<script setup>
1719
import {usePageFrontmatter, withBase} from "@vuepress/client";
18-
import {computed, inject, watch} from "vue";
19-
const { MAX_ALGOLIA_HITS_PER_PAGE } = inject('themeConfig')
20-
20+
import {computed, inject, ref, watch} from "vue";
2121
22+
const { MAX_HITS_PER_PAGE } = inject('themeConfig')
2223
const {headerDefaultSearchIcon, headerSearchIcon, headerSearchPlaceholder} = inject('themeConfig')
24+
2325
const props = defineProps({
2426
options: {
2527
type: [Object, Array],
@@ -37,9 +39,10 @@ const props = defineProps({
3739
type: Boolean,
3840
}
3941
});
40-
const emit = defineEmits(["openDrawer", 'update:modelValue', 'result'])
4142
43+
const emit = defineEmits(["openDrawer", 'update:modelValue', 'result'])
4244
const frontmatter = usePageFrontmatter()
45+
4346
const isGlobalLayout = computed(() => {
4447
return frontmatter.value.layout === 'HomeLayout'
4548
})
@@ -61,43 +64,110 @@ const placeholderDesktop = computed(() => {
6164
})
6265
6366
const placeholder = computed(() => {
64-
return props.isMobileWidth ? 'Search accross all Imunify Security support' : placeholderDesktop.value
67+
return props.isMobileWidth ? 'Search accross all Imunify360 Docs' : placeholderDesktop.value
6568
})
6669
67-
68-
const initialize = async (userOptions) => {
69-
if( typeof window === 'undefined' ) return
70-
const [docsearchModule] = await Promise.all([
71-
import(/* webpackChunkName: "docsearch" */ "docsearch.js/dist/cdn/docsearch.min.js"),
72-
import(/* webpackChunkName: "docsearch" */ "docsearch.js/dist/cdn/docsearch.min.css"),
73-
]);
74-
const docsearch = docsearchModule.default;
75-
docsearch(
76-
Object.assign({}, userOptions, {
77-
inputSelector: "#algolia-search-input",
78-
algoliaOptions: {
79-
hitsPerPage: MAX_ALGOLIA_HITS_PER_PAGE,
80-
},
81-
handleSelected: () => {
82-
emit('openDrawer')
70+
function parseDocs(api_response) {
71+
return api_response.imunify360_docs.map((doc) => {
72+
const titleParts = doc.title.split("->").map((part) => part.trim());
73+
74+
const hierarchy = {
75+
lvl0: titleParts[0] || null,
76+
lvl1: titleParts[1] || null,
77+
lvl2: titleParts[2] || null,
78+
lvl3: titleParts[3] || null,
79+
lvl4: titleParts[4] || null,
80+
lvl5: null,
81+
lvl6: null,
82+
};
83+
84+
const anchor = doc.url.split("#")[1] || "";
85+
86+
const objectID = doc.id;
87+
88+
return {
89+
anchor,
90+
content: null,
91+
hierarchy,
92+
url: doc.url,
93+
title: doc.title,
94+
preview: doc.preview,
95+
category: doc.category,
96+
section: doc.section,
97+
objectID,
98+
_highlightResult: {
99+
hierarchy: {
100+
lvl0: {
101+
value: hierarchy.lvl0 || "",
102+
matchLevel: "none",
103+
matchedWords: [],
104+
},
105+
lvl1: {
106+
value: hierarchy.lvl1 || "",
107+
matchLevel: "full",
108+
fullyHighlighted: false,
109+
matchedWords: [hierarchy.lvl1?.toLowerCase()],
110+
},
83111
},
84-
transformData: (hits) => {
85-
emit('result', hits)
86-
},
87-
})
88-
);
89-
};
90-
watch(
91-
() => props.options,
92-
async (newValue) => {
93-
await initialize(newValue);
94-
}, {
95-
immediate: true
112+
hierarchy_camel: [
113+
{
114+
lvl0: {
115+
value: hierarchy.lvl0 || "",
116+
matchLevel: "none",
117+
matchedWords: [],
118+
},
119+
lvl1: {
120+
value: `<span class="algolia-docsearch-suggestion--highlight">${hierarchy.lvl1 || ""}</span>`,
121+
matchLevel: "full",
122+
fullyHighlighted: false,
123+
matchedWords: [hierarchy.lvl1?.toLowerCase()],
124+
},
125+
},
126+
],
127+
},
128+
};
129+
});
130+
}
131+
132+
async function queryGlobalSearch(query, n_results=10) {
133+
const baseUrl = 'https://global-search.cl-edu.com/search'; let urlEncodedQuery = encodeURIComponent(query);
134+
let url = `${baseUrl}?query=${urlEncodedQuery}&collections=imunify360_docs&n_results=${n_results}&source=imunify360_docs`;
135+
try {
136+
const response = await fetch(url);
137+
if (!response.ok) {
138+
throw new Error(`HTTP error! status: ${response.status}`);
96139
}
140+
const data = await response.json();
141+
return data;
142+
} catch (error) {
143+
console.error('Error querying global search:', error);
144+
return null;
145+
}
146+
}
147+
148+
const loading = ref(false); // Reactive variable for loading state
149+
150+
const performSearch = async () => {
151+
loading.value = true; // Set loading to true when search starts
152+
const data = await queryGlobalSearch(props.modelValue, MAX_HITS_PER_PAGE);
153+
loading.value = false; // Set loading to false when search finishes
154+
if (data) {
155+
const hits = parseDocs(data);
156+
emit('result', hits);
157+
emit('openDrawer');
158+
}
159+
}
160+
161+
watch(
162+
() => props.options,
163+
async (newValue) => {
164+
// Initialize if needed or any other dependent setup
165+
}, {
166+
immediate: true
167+
}
97168
);
98169
</script>
99170
100-
101171
<style lang="stylus">
102172
@import '../../styles/config.styl'
103173
.algolia-autocomplete
@@ -139,7 +209,6 @@ watch(
139209
justify-content center
140210
align-content center
141211
142-
143212
@media (max-width: $mobileBreakpoint)
144213
.drawer-header__search
145214
width 100%
@@ -158,4 +227,18 @@ watch(
158227
width 75%
159228
.header-layout__search-title
160229
text-align center
161-
</style>
230+
231+
.spinner
232+
border 4px solid rgba(0, 0, 0, 0.1)
233+
border-top 4px solid #6ccc93
234+
border-radius 50%
235+
width 20px
236+
height 20px
237+
animation spin 1s linear infinite
238+
239+
@keyframes spin
240+
0%
241+
transform rotate(0deg)
242+
100%
243+
transform rotate(360deg)
244+
</style>

0 commit comments

Comments
 (0)