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>
1719import {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' )
2223const {headerDefaultSearchIcon , headerSearchIcon , headerSearchPlaceholder } = inject (' themeConfig' )
24+
2325const 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' ])
4244const frontmatter = usePageFrontmatter ()
45+
4346const isGlobalLayout = computed (() => {
4447 return frontmatter .value .layout === ' HomeLayout'
4548})
@@ -61,43 +64,110 @@ const placeholderDesktop = computed(() => {
6164})
6265
6366const 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